From 6e684c01ef9822ac362c0b3b8cf40818e9763f53 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 15 May 2024 17:48:22 +0800 Subject: [PATCH 01/12] fix and update (#677) --- .../ylt/standalone/iguana/detail/charconv.h | 44 ++++- .../ylt/standalone/iguana/detail/traits.hpp | 9 + include/ylt/standalone/iguana/json_reader.hpp | 71 +++++++- include/ylt/standalone/iguana/json_util.hpp | 29 ++- include/ylt/standalone/iguana/json_writer.hpp | 2 + include/ylt/standalone/iguana/reflection.hpp | 114 ++++++++++++ include/ylt/standalone/iguana/util.hpp | 129 +++++++++---- include/ylt/standalone/iguana/version.hpp | 8 + include/ylt/standalone/iguana/xml_reader.hpp | 169 +++++++++++------- include/ylt/standalone/iguana/xml_util.hpp | 151 +++++++++++++++- include/ylt/standalone/iguana/xml_writer.hpp | 64 ++++++- include/ylt/standalone/iguana/yaml_reader.hpp | 5 +- 12 files changed, 668 insertions(+), 127 deletions(-) create mode 100644 include/ylt/standalone/iguana/version.hpp diff --git a/include/ylt/standalone/iguana/detail/charconv.h b/include/ylt/standalone/iguana/detail/charconv.h index 0e81a39cd..a5b2d0c73 100644 --- a/include/ylt/standalone/iguana/detail/charconv.h +++ b/include/ylt/standalone/iguana/detail/charconv.h @@ -3,27 +3,48 @@ #include "dragonbox_to_chars.h" #include "fast_float.h" +#include "iguana/define.h" #include "itoa.hpp" namespace iguana { template struct is_char_type - : std::disjunction, std::is_same, - std::is_same, std::is_same, + : std::disjunction, std::is_same, std::is_same, std::is_same> {}; +inline void *to_chars_float(...) { + throw std::runtime_error("not allowed to invoke"); + return {}; +} + +template (), std::declval()))> +using return_of_tochars = std::conditional_t, + std::true_type, std::false_type>; +// here std::true_type is used as a type , any other type is also ok. +using has_to_chars_float = iguana::return_of_tochars; + namespace detail { -template + +// check_number==true: check if the string [first, last) is a legal number +template std::pair from_chars(const char *first, - const char *last, - U &value) noexcept { + const char *last, U &value) { using T = std::decay_t; if constexpr (std::is_floating_point_v) { auto [p, ec] = fast_float::from_chars(first, last, value); + if constexpr (check_number) { + if (p != last || ec != std::errc{}) + IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } + } return {p, ec}; } else { auto [p, ec] = std::from_chars(first, last, value); + if constexpr (check_number) { + if (p != last || ec != std::errc{}) + IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } + } return {p, ec}; } } @@ -33,7 +54,12 @@ template char *to_chars(char *buffer, T value) noexcept { using U = std::decay_t; if constexpr (std::is_floating_point_v) { - return jkj::dragonbox::to_chars(value, buffer); + if constexpr (has_to_chars_float::value) { + return static_cast(to_chars_float(value, buffer)); + } + else { + return jkj::dragonbox::to_chars(value, buffer); + } } else if constexpr (std::is_signed_v && (sizeof(U) >= 8)) { return xtoa(value, buffer, 10, 1); // int64_t @@ -41,9 +67,13 @@ char *to_chars(char *buffer, T value) noexcept { else if constexpr (std::is_unsigned_v && (sizeof(U) >= 8)) { return xtoa(value, buffer, 10, 0); // uint64_t } - else if constexpr (std::is_integral_v && !is_char_type::value) { + else if constexpr (std::is_integral_v && (sizeof(U) > 1)) { return itoa_fwd(value, buffer); // only support more than 2 bytes intergal } + else if constexpr (!is_char_type::value) { + return itoa_fwd(static_cast(value), + buffer); // only support more than 2 bytes intergal + } else { static_assert(!sizeof(U), "only support arithmetic type except char type"); } diff --git a/include/ylt/standalone/iguana/detail/traits.hpp b/include/ylt/standalone/iguana/detail/traits.hpp index 5938f4a7f..64f082e03 100644 --- a/include/ylt/standalone/iguana/detail/traits.hpp +++ b/include/ylt/standalone/iguana/detail/traits.hpp @@ -67,6 +67,15 @@ template struct has_type> : std::disjunction...> {}; +template +struct member_tratis {}; + +template +struct member_tratis { + using owner_type = Owner; + using value_type = T; +}; + template inline constexpr bool is_int64_v = std::is_same_v || std::is_same_v; diff --git a/include/ylt/standalone/iguana/json_reader.hpp b/include/ylt/standalone/iguana/json_reader.hpp index 1597d93bf..050183492 100644 --- a/include/ylt/standalone/iguana/json_reader.hpp +++ b/include/ylt/standalone/iguana/json_reader.hpp @@ -68,8 +68,8 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { if (size == 0) IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } const auto start = &*it; - auto [p, ec] = detail::from_chars(start, start + size, value); - if (ec != std::errc{}) + auto [p, ec] = detail::from_chars(start, start + size, value); + if (ec != std::errc{} || !can_follow_number(*p)) IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } it += (p - &*it); } @@ -82,9 +82,7 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { buffer[i] = *it++; ++i; } - auto [p, ec] = detail::from_chars(buffer, buffer + i, value); - if (ec != std::errc{}) - IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } + detail::from_chars(buffer, buffer + i, value); } } @@ -499,6 +497,44 @@ IGUANA_INLINE void skip_object_value(It &&it, It &&end) { } } +template +IGUANA_INLINE bool from_json_variant_impl(U &value, It it, It end, It &temp_it, + It &temp_end) { + try { + value_type val; + from_json_impl(val, it, end); + value = val; + temp_it = it; + temp_end = end; + return true; + } catch (std::exception &ex) { + return false; + } +} + +template +IGUANA_INLINE void from_json_variant(U &value, It &it, It &end, + std::index_sequence) { + static_assert(!has_duplicate_type_v>, + "don't allow same type in std::variant"); + bool r = false; + It temp_it = it; + It temp_end = end; + ((void)(!r && (r = from_json_variant_impl< + variant_element_t>>( + value, it, end, temp_it, temp_end), + true)), + ...); + it = temp_it; + end = temp_end; +} + +template , int> = 0> +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { + from_json_variant(value, it, end, + std::make_index_sequence< + std::variant_size_v>>{}); +} } // namespace detail template , int>> @@ -608,6 +644,31 @@ IGUANA_INLINE void from_json(T &value, const View &view) { from_json(value, std::begin(view), std::end(view)); } +template < + auto member, + typename Parant = typename member_tratis::owner_type, + typename T> +IGUANA_INLINE void from_json(T &value, std::string_view str) { + constexpr size_t duplicate_count = + iguana::duplicate_count, member>(); + static_assert(duplicate_count != 1, "the member is not belong to the object"); + static_assert(duplicate_count == 2, "has duplicate field name"); + + constexpr auto name = name_of(); + constexpr size_t index = index_of(); + constexpr size_t member_count = member_count_of(); + str = str.substr(str.find(name) + name.size()); + size_t pos = str.find(":") + 1; + if constexpr (index == member_count - 1) { // last field + str = str.substr(pos, str.find("}") - pos + 1); + } + else { + str = str.substr(pos, str.find(",") - pos); + } + + detail::from_json_impl(value.*member, std::begin(str), std::end(str)); +} + template , int> = 0> IGUANA_INLINE void from_json(T &value, const View &view, diff --git a/include/ylt/standalone/iguana/json_util.hpp b/include/ylt/standalone/iguana/json_util.hpp index 5c00c0771..f1bf3a331 100644 --- a/include/ylt/standalone/iguana/json_util.hpp +++ b/include/ylt/standalone/iguana/json_util.hpp @@ -18,10 +18,7 @@ class numeric_str { if (val_.empty()) IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } T res; - auto [_, ec] = - detail::from_chars(val_.data(), val_.data() + val_.size(), res); - if (ec != std::errc{}) - IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); } + detail::from_chars(val_.data(), val_.data() + val_.size(), res); return res; } @@ -214,4 +211,28 @@ IGUANA_INLINE bool is_numeric(char c) noexcept { return static_cast(is_num[static_cast(c)]); } +// '\t' '\r' '\n' '"' '}' ']' ',' ' ' '\0' +IGUANA_INLINE bool can_follow_number(char c) noexcept { + static constexpr int can_follow_num[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + return static_cast(can_follow_num[static_cast(c)]); +} + } // namespace iguana diff --git a/include/ylt/standalone/iguana/json_writer.hpp b/include/ylt/standalone/iguana/json_writer.hpp index 80e2558da..eeaeaa399 100644 --- a/include/ylt/standalone/iguana/json_writer.hpp +++ b/include/ylt/standalone/iguana/json_writer.hpp @@ -245,6 +245,8 @@ IGUANA_INLINE void to_json_impl(Stream &s, T &&t) { template , int>> IGUANA_INLINE void to_json_impl(Stream &s, T &&t) { + static_assert(!has_duplicate_type_v>, + "don't allow same type in std::variant"); std::visit( [&s](auto value) { to_json_impl(s, value); diff --git a/include/ylt/standalone/iguana/reflection.hpp b/include/ylt/standalone/iguana/reflection.hpp index 41e15423b..234da95d6 100644 --- a/include/ylt/standalone/iguana/reflection.hpp +++ b/include/ylt/standalone/iguana/reflection.hpp @@ -910,6 +910,120 @@ constexpr const std::string_view get_name() { return M::name(); } +namespace detail { +template +constexpr bool get_index_imple(T ptr, U ele) { + if constexpr (std::is_same_v) { + if (ele == ptr) { + return true; + } + else { + return false; + } + } + else { + return false; + } +} + +template +constexpr size_t member_index_impl(T ptr, Tuple &tp, + std::index_sequence) { + bool r = false; + size_t index = 0; + ((void)(!r && (r = get_index_imple(ptr, std::get(tp)), + !r ? index++ : index, true)), + ...); + return index; +} + +template +constexpr size_t member_index(T ptr, Tuple &tp) { + return member_index_impl( + ptr, tp, + std::make_index_sequence< + std::tuple_size_v>>{}); +} +} // namespace detail + +template +constexpr size_t index_of() { + using namespace detail; + using T = typename member_tratis::owner_type; + using M = Reflect_members; + constexpr auto tp = M::apply_impl(); + constexpr size_t Size = std::tuple_size_v; + constexpr size_t index = member_index(member, tp); + static_assert(index < Size, "out of range"); + return index; +} + +template +constexpr std::array indexs_of() { + return std::array{index_of()...}; +} + +template +constexpr auto name_of() { + using T = typename member_tratis::owner_type; + using M = Reflect_members; + constexpr auto s = M::arr()[index_of()]; + return std::string_view(s.data(), s.size()); +} + +template +constexpr std::array names_of() { + return std::array{ + name_of()...}; +} + +template +constexpr auto member_count_of() { + using T = typename member_tratis::owner_type; + using M = Reflect_members; + return M::value(); +} + +template +constexpr size_t duplicate_count(); + +template +constexpr void check_duplicate(Member member, size_t &index) { + using value_type = typename member_tratis::value_type; + + if (detail::get_index_imple(ptr, member)) { + index++; + } + + if constexpr (is_reflection_v) { + index += iguana::duplicate_count(); + } +} + +template +constexpr size_t duplicate_count() { + using M = Reflect_members; + constexpr auto name = name_of(); + constexpr auto arr = M::arr(); + + constexpr auto tp = M::apply_impl(); + size_t index = 0; + std::apply( + [&](auto... ele) { + (check_duplicate(ele, index), ...); + }, + tp); + + for (auto &s : arr) { + if (s == name) { + index++; + break; + } + } + + return index; +} + template constexpr const std::string_view get_fields() { using M = Reflect_members; diff --git a/include/ylt/standalone/iguana/util.hpp b/include/ylt/standalone/iguana/util.hpp index f910db795..47959618a 100644 --- a/include/ylt/standalone/iguana/util.hpp +++ b/include/ylt/standalone/iguana/util.hpp @@ -139,6 +139,10 @@ struct is_variant> : std::true_type {}; template constexpr inline bool variant_v = is_variant>::value; +template +using variant_element_t = std::remove_reference_t( + std::declval>()))>; + template constexpr inline bool refletable_v = is_reflection_v>; @@ -201,10 +205,59 @@ inline constexpr auto has_qoute = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { 0b0010001000100010001000100010001000100010001000100010001000100010); }; +template +IGUANA_INLINE void write_unicode_to_string(Ch& it, Stream& ss) { + static const char hexDigits[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + unsigned codepoint = 0; + if (!decode_utf8(it, codepoint)) + IGUANA_UNLIKELY { throw std::runtime_error("illegal unicode character"); } + if constexpr (is_xml_serialization) { + ss.append("&#x"); + } + else { + ss.push_back('\\'); + ss.push_back('u'); + } + + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { + ss.push_back(hexDigits[(codepoint >> 12) & 15]); + ss.push_back(hexDigits[(codepoint >> 8) & 15]); + ss.push_back(hexDigits[(codepoint >> 4) & 15]); + ss.push_back(hexDigits[(codepoint)&15]); + } + else { + if (codepoint < 0x010000 || codepoint > 0x10FFFF) + IGUANA_UNLIKELY { throw std::runtime_error("illegal codepoint"); } + // Surrogate pair + unsigned s = codepoint - 0x010000; + unsigned lead = (s >> 10) + 0xD800; + unsigned trail = (s & 0x3FF) + 0xDC00; + ss.push_back(hexDigits[(lead >> 12) & 15]); + ss.push_back(hexDigits[(lead >> 8) & 15]); + ss.push_back(hexDigits[(lead >> 4) & 15]); + ss.push_back(hexDigits[(lead)&15]); + if constexpr (is_xml_serialization) { + ss.append(";&#x"); + } + else { + ss.push_back('\\'); + ss.push_back('u'); + } + ss.push_back(hexDigits[(trail >> 12) & 15]); + ss.push_back(hexDigits[(trail >> 8) & 15]); + ss.push_back(hexDigits[(trail >> 4) & 15]); + ss.push_back(hexDigits[(trail)&15]); + } + if constexpr (is_xml_serialization) { + ss.push_back(';'); + } +} + // https://github.com/Tencent/rapidjson/blob/master/include/rapidjson/writer.h template -inline void write_string_with_escape(const Ch* it, SizeType length, - Stream& ss) { +IGUANA_INLINE void write_string_with_escape(const Ch* it, SizeType length, + Stream& ss) { static const char hexDigits[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; static const char escape[256] = { @@ -227,40 +280,7 @@ inline void write_string_with_escape(const Ch* it, SizeType length, std::advance(end, length); while (it < end) { if (static_cast(*it) >= 0x80) - IGUANA_UNLIKELY { - unsigned codepoint = 0; - if (!decode_utf8(it, codepoint)) - IGUANA_UNLIKELY { - throw std::runtime_error("illegal unicode character"); - } - ss.push_back('\\'); - ss.push_back('u'); - if (codepoint <= 0xD7FF || - (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { - ss.push_back(hexDigits[(codepoint >> 12) & 15]); - ss.push_back(hexDigits[(codepoint >> 8) & 15]); - ss.push_back(hexDigits[(codepoint >> 4) & 15]); - ss.push_back(hexDigits[(codepoint)&15]); - } - else { - if (codepoint < 0x010000 || codepoint > 0x10FFFF) - IGUANA_UNLIKELY { throw std::runtime_error("illegal codepoint"); } - // Surrogate pair - unsigned s = codepoint - 0x010000; - unsigned lead = (s >> 10) + 0xD800; - unsigned trail = (s & 0x3FF) + 0xDC00; - ss.push_back(hexDigits[(lead >> 12) & 15]); - ss.push_back(hexDigits[(lead >> 8) & 15]); - ss.push_back(hexDigits[(lead >> 4) & 15]); - ss.push_back(hexDigits[(lead)&15]); - ss.push_back('\\'); - ss.push_back('u'); - ss.push_back(hexDigits[(trail >> 12) & 15]); - ss.push_back(hexDigits[(trail >> 8) & 15]); - ss.push_back(hexDigits[(trail >> 4) & 15]); - ss.push_back(hexDigits[(trail)&15]); - } - } + IGUANA_UNLIKELY { write_unicode_to_string(it, ss); } else if (escape[static_cast(*it)]) IGUANA_UNLIKELY { ss.push_back('\\'); @@ -281,4 +301,41 @@ inline void write_string_with_escape(const Ch* it, SizeType length, } } +template +IGUANA_INLINE constexpr bool has_duplicate(const std::array& arr) { + for (int i = 0; i < arr.size(); i++) { + for (int j = i + 1; j < arr.size(); j++) { + if (arr[i] == arr[j]) { + return true; + } + } + } + return false; +} + +#if defined(__clang__) || defined(_MSC_VER) || \ + (defined(__GNUC__) && __GNUC__ > 8) +template +IGUANA_INLINE constexpr bool has_duplicate_type() { + std::array arr{ + iguana::type_string()...}; + return has_duplicate(arr); +} + +template +struct has_duplicate_type_in_variant : std::false_type {}; + +template +struct has_duplicate_type_in_variant> { + inline constexpr static bool value = has_duplicate_type(); +}; + +template +constexpr inline bool has_duplicate_type_v = + has_duplicate_type_in_variant::value; +#else +template +constexpr inline bool has_duplicate_type_v = false; +#endif + } // namespace iguana diff --git a/include/ylt/standalone/iguana/version.hpp b/include/ylt/standalone/iguana/version.hpp new file mode 100644 index 000000000..202ea4a3a --- /dev/null +++ b/include/ylt/standalone/iguana/version.hpp @@ -0,0 +1,8 @@ +#pragma once + +// Note: Update the version when release a new version. + +// IGUANA_VERSION % 100 is the sub-minor version +// IGUANA_VERSION / 100 % 1000 is the minor version +// IGUANA_VERSION / 100000 is the major version +#define IGUANA_VERSION 100004 // 1.0.4 \ No newline at end of file diff --git a/include/ylt/standalone/iguana/xml_reader.hpp b/include/ylt/standalone/iguana/xml_reader.hpp index 63bfdb848..209b4f894 100644 --- a/include/ylt/standalone/iguana/xml_reader.hpp +++ b/include/ylt/standalone/iguana/xml_reader.hpp @@ -28,15 +28,26 @@ template , int> = 0> IGUANA_INLINE void parse_value(U &&value, It &&begin, It &&end) { using T = std::decay_t; if constexpr (string_container_v) { - value = T(&*begin, static_cast(std::distance(begin, end))); + if constexpr (string_view_v) { + value = T(&*begin, static_cast(std::distance(begin, end))); + } + else { + // TODO: When not parsing the value in the attribute, it is not necessary + // to unescape'and " + value.clear(); + auto pre = begin; + while (advance_until_character<'&'>(begin, end)) { + value.append(T(&*pre, static_cast(std::distance(pre, begin)))); + parse_escape_xml(value, begin, end); + pre = begin; + } + value.append(T(&*pre, static_cast(std::distance(pre, begin)))); + } } else if constexpr (num_v) { auto size = std::distance(begin, end); const auto start = &*begin; - auto [p, ec] = detail::from_chars(start, start + size, value); - if (ec != std::errc{}) - IGUANA_UNLIKELY - throw std::runtime_error("Failed to parse number"); + detail::from_chars(start, start + size, value); } else if constexpr (char_v) { if (static_cast(std::distance(begin, end)) != 1) @@ -90,9 +101,19 @@ IGUANA_INLINE void parse_attr(U &&value, It &&it, It &&end) { parse_value(key, key_begin, key_end); skip_sapces_and_newline(it, end); - match<'"'>(it, end); - auto value_begin = it; - auto value_end = skip_pass<'"'>(it, end); + auto value_begin = it + 1; + auto value_end = value_begin; + if (*it == '"') + IGUANA_LIKELY { + ++it; + value_end = skip_pass<'"'>(it, end); + } + else if (*it == '\'') { + ++it; + value_end = skip_pass<'\''>(it, end); + } + else + IGUANA_UNLIKELY { throw std::runtime_error("expected quote or apos"); } value_type v; parse_value(v, value_begin, value_end); value.emplace(std::move(key), std::move(v)); @@ -121,17 +142,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, match<'<'>(it, end); if (*it == '?' || *it == '!') IGUANA_UNLIKELY { - // skip '>(it, end); - ++it; - skip_sapces_and_newline(it, end); - continue; - } + --it; + return; } auto start = it; skip_till_greater_or_space(it, end); @@ -223,24 +235,48 @@ IGUANA_INLINE void skip_object_value(It &&it, It &&end, std::string_view name) { throw std::runtime_error("unclosed tag: " + std::string(name)); } +// skip +template +IGUANA_INLINE void skip_instructions(It &&it, It &&end) { + while (*(it - 1) != '?') { + ++it; + skip_till<'>'>(it, end); + } + ++it; +} + +template +IGUANA_INLINE void skip_cdata(It &&it, It &&end) { + ++it; + skip_till<']'>(it, end); + ++it; + match<']', '>'>(it, end); +} + +template +IGUANA_INLINE void skip_comment(It &&it, It &&end) { + while (*(it - 1) != '-' || *(it - 2) != '-') { + ++it; + skip_till<'>'>(it, end); + } + ++it; +} + // return true means reach the close tag template , int> = 0> -IGUANA_INLINE auto skip_till_key(T &value, It &&it, It &&end) { - skip_sapces_and_newline(it, end); +IGUANA_INLINE auto skip_till_close_tag(T &value, It &&it, It &&end) { while (true) { + skip_sapces_and_newline(it, end); match<'<'>(it, end); if (*it == '/') IGUANA_UNLIKELY { - // - return true; // reach the close tag + // reach the close tag + return true; } else if (*it == '?') IGUANA_UNLIKELY { - // - skip_till<'>'>(it, end); - ++it; - skip_sapces_and_newline(it, end); + skip_instructions(it, end); continue; } else if (*it == '!') @@ -249,12 +285,7 @@ IGUANA_INLINE auto skip_till_key(T &value, It &&it, It &&end) { if (*it == '[') { // >()) { - ++it; - skip_till<']'>(it, end); - ++it; - match<']', '>'>(it, end); - skip_sapces_and_newline(it, end); - continue; + skip_cdata(it, end); } else { // if parse cdata @@ -274,23 +305,53 @@ IGUANA_INLINE auto skip_till_key(T &value, It &&it, It &&end) { &*vb, static_cast(std::distance(vb, ve))); } match<']', '>'>(it, end); - skip_sapces_and_newline(it, end); - continue; } } - else { + else if (*it == '-') { // - // skip_till<'>'>(it, end); ++it; - skip_sapces_and_newline(it, end); - continue; } + continue; } return false; } } +template +IGUANA_INLINE void skip_till_first_key(It &&it, It &&end) { + while (it != end) { + skip_sapces_and_newline(it, end); + match<'<'>(it, end); + if (*it == '?') + IGUANA_UNLIKELY { + skip_instructions(it, end); + continue; + } + else if (*it == '!') + IGUANA_UNLIKELY { + ++it; + if (*it == '-') { + // + skip_comment(it, end); + } + else { + // + skip_till<'>'>(it, end); + ++it; + } + continue; + } + else { + break; + } + } +} + template IGUANA_INLINE void check_required(std::string_view key_set) { if constexpr (iguana::has_iguana_required_arr_v) { @@ -313,7 +374,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, constexpr auto cdata_idx = get_type_index(); skip_till<'>'>(it, end); ++it; - if (skip_till_key(value, it, end)) { + if (skip_till_close_tag(value, it, end)) { match_close_tag(it, end, name); return; } @@ -344,7 +405,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, key_set.append(key).append(", "); } } - if (skip_till_key(value, it, end)) + if (skip_till_close_tag(value, it, end)) IGUANA_UNLIKELY { match_close_tag(it, end, name); parse_done = true; @@ -389,7 +450,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, skip_object_value(it, end, key); #endif } - if (skip_till_key(value, it, end)) { + if (skip_till_close_tag(value, it, end)) { match_close_tag(it, end, name); check_required(key_set); return; @@ -405,17 +466,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, template , int> = 0> IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { - while (it != end) { - skip_sapces_and_newline(it, end); - match<'<'>(it, end); - if (*it == '?') { - skip_till<'>'>(it, end); - ++it; - } - else { - break; - } - } + detail::skip_till_first_key(it, end); auto start = it; skip_till_greater_or_space(it, end); std::string_view key = @@ -426,17 +477,7 @@ IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { template , int> = 0> IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { - while (it != end) { - skip_sapces_and_newline(it, end); - match<'<'>(it, end); - if (*it == '?') { - skip_till<'>'>(it, end); - ++it; // skip > - } - else { - break; - } - } + detail::skip_till_first_key(it, end); auto start = it; skip_till_greater_or_space(it, end); std::string_view key = diff --git a/include/ylt/standalone/iguana/xml_util.hpp b/include/ylt/standalone/iguana/xml_util.hpp index cd2df709b..dabd47a38 100644 --- a/include/ylt/standalone/iguana/xml_util.hpp +++ b/include/ylt/standalone/iguana/xml_util.hpp @@ -2,8 +2,8 @@ #include "util.hpp" namespace iguana { -template > +template > class xml_attr_t { public: T &value() { return val_; } @@ -17,6 +17,10 @@ class xml_attr_t { map_type attr_; }; +template +using xml_attr_view_t = + xml_attr_t>; + template , int> = 0> class xml_cdata_t { @@ -72,12 +76,24 @@ inline constexpr auto has_square_bracket = 0b0101110101011101010111010101110101011101010111010101110101011101); }; +inline constexpr auto has_and = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { + return has_zero( + chunk ^ + 0b0010011000100110001001100010011000100110001001100010011000100110); +}; + inline constexpr auto has_equal = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { return has_zero( chunk ^ 0b0011110100111101001111010011110100111101001111010011110100111101); }; +inline constexpr auto has_apos = [](uint64_t chunk) IGUANA__INLINE_LAMBDA { + return has_zero( + chunk ^ + 0b0010011100100111001001110010011100100111001001110010011100100111); +}; + template IGUANA_INLINE void skip_sapces_and_newline(It &&it, It &&end) { while (it != end && (static_cast(*it) < 33)) { @@ -104,6 +120,35 @@ IGUANA_INLINE void match_close_tag(It &&it, It &&end, std::string_view key) { // ++it; } +// returns true if the specified character 'c' is found, false otherwise. +template +IGUANA_INLINE bool advance_until_character(It &&it, It &&end) { + static_assert(contiguous_iterator>); + if (std::distance(it, end) >= 7) + IGUANA_LIKELY { + const auto end_m7 = end - 7; + for (; it < end_m7; it += 8) { + const auto chunk = *reinterpret_cast(&*it); + uint64_t test; + if constexpr (c == '&') + test = has_and(chunk); + else + static_assert(!c, "not support this character"); + if (test != 0) { + it += (countr_zero(test) >> 3); + return true; + } + } + } + // Tail end of buffer. Should be rare we even get here + while (it < end) { + if (*it == c) + return true; + ++it; + } + return false; +} + template IGUANA_INLINE void skip_till(It &&it, It &&end) { static_assert(contiguous_iterator>); @@ -126,6 +171,8 @@ IGUANA_INLINE void skip_till(It &&it, It &&end) { test = has_square_bracket(chunk); else if constexpr (c == '=') test = has_equal(chunk); + else if constexpr (c == '\'') + test = has_apos(chunk); else static_assert(!c, "not support this character"); if (test != 0) { @@ -186,4 +233,104 @@ IGUANA_INLINE auto skip_pass(It &&it, It &&end) { return res + 1; } +template +IGUANA_INLINE bool is_match(It &&it, const It &end) { + const auto n = static_cast(std::distance(it, end)); + if ((n < sizeof...(C)) || (... || (*it++ != C))) { + return false; + } + return true; +} + +template , int> = 0> +IGUANA_INLINE void parse_escape_xml(U &value, It &&it, It &&end) { + static const unsigned char lookup_digits[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255}; + switch (*(it + 1)) { + // & ' + case 'a': + if (is_match<'m', 'p', ';'>(it + 2, end)) { + value.push_back('&'); + it += 5; + return; + } + if (is_match<'p', 'o', 's', ';'>(it + 2, end)) { + value.push_back('\''); + it += 6; + } + break; + // " + case 'q': + if (is_match<'u', 'o', 't', ';'>(it + 2, end)) { + value.push_back('\"'); + it += 6; + } + break; + // > + case 'g': + if (is_match<'t', ';'>(it + 2, end)) { + value.push_back('>'); + it += 4; + } + break; + // < + case 'l': + if (is_match<'t', ';'>(it + 2, end)) { + value.push_back('<'); + it += 4; + } + break; + case '#': + if (*(it + 2) == 'x') { + // &#x + unsigned long codepoint = 0; + it += 3; + while (true) { + auto digit = lookup_digits[static_cast(*it)]; + if (digit == 0xFF) + break; + codepoint = codepoint * 16 + digit; + ++it; + } + encode_utf8(value, codepoint); + } + else { + unsigned long codepoint = 0; + it += 2; + while (true) { + auto digit = lookup_digits[static_cast(*it)]; + if (digit == 0xFF) + break; + codepoint = codepoint * 10 + digit; + ++it; + } + encode_utf8(value, codepoint); + } + match<';'>(it, end); + break; + default: + // skip '&' + // loose policy: allow '&' + value.push_back(*(it++)); + break; + } +} + } // namespace iguana diff --git a/include/ylt/standalone/iguana/xml_writer.hpp b/include/ylt/standalone/iguana/xml_writer.hpp index b83a2c8bb..94e35f37b 100644 --- a/include/ylt/standalone/iguana/xml_writer.hpp +++ b/include/ylt/standalone/iguana/xml_writer.hpp @@ -6,6 +6,58 @@ namespace iguana { +#ifdef XML_ATTR_USE_APOS +#define XML_ATTR_DELIMITER '\'' +#else +#define XML_ATTR_DELIMITER '\"' +#endif + +// TODO: improve by precaculate size +template +IGUANA_INLINE void render_string_with_escape_xml(const Ch *it, SizeType length, + Stream &ss) { + auto end = it; + std::advance(end, length); + while (it < end) { +#ifdef XML_ESCAPE_UNICODE + if (static_cast(*it) >= 0x80) + IGUANA_UNLIKELY { + write_unicode_to_string(it, ss); + continue; + } +#endif + if constexpr (escape_quote_apos) { + if constexpr (XML_ATTR_DELIMITER == '\"') { + if (*it == '"') + IGUANA_UNLIKELY { + ss.append("""); + ++it; + continue; + } + } + else { + if (*it == '\'') + IGUANA_UNLIKELY { + ss.append("'"); + ++it; + continue; + } + } + } + if (*it == '&') + IGUANA_UNLIKELY { ss.append("&"); } + else if (*it == '>') + IGUANA_UNLIKELY { ss.append(">"); } + else if (*it == '<') + IGUANA_UNLIKELY { ss.append("<"); } + else { + ss.push_back(*it); + } + ++it; + } +} + template , int> = 0> IGUANA_INLINE void render_xml_value(Stream &ss, const T &value, @@ -39,10 +91,12 @@ IGUANA_INLINE void render_head(Stream &ss, std::string_view str) { ss.push_back('>'); } -template , int> = 0> +template , int> = 0> IGUANA_INLINE void render_value(Stream &ss, const T &value) { if constexpr (string_container_v) { - ss.append(value.data(), value.size()); + render_string_with_escape_xml(value.data(), value.size(), + ss); } else if constexpr (num_v) { char temp[65]; @@ -91,9 +145,9 @@ inline void render_xml_attr(Stream &ss, const T &value, std::string_view name) { ss.push_back(' '); render_value(ss, k); ss.push_back('='); - ss.push_back('"'); - render_value(ss, v); - ss.push_back('"'); + ss.push_back(XML_ATTR_DELIMITER); + render_value(ss, v); + ss.push_back(XML_ATTR_DELIMITER); } ss.push_back('>'); } diff --git a/include/ylt/standalone/iguana/yaml_reader.hpp b/include/ylt/standalone/iguana/yaml_reader.hpp index 9ad04e30a..0a0d47fa7 100644 --- a/include/ylt/standalone/iguana/yaml_reader.hpp +++ b/include/ylt/standalone/iguana/yaml_reader.hpp @@ -113,10 +113,7 @@ IGUANA_INLINE void parse_value(U &value, It &&value_begin, It &&value_end) { IGUANA_UNLIKELY { return; } auto size = std::distance(value_begin, value_end); const auto start = &*value_begin; - auto [p, ec] = detail::from_chars(start, start + size, value); - if (ec != std::errc{}) - IGUANA_UNLIKELY - throw std::runtime_error("Failed to parse number"); + detail::from_chars(start, start + size, value); } // string_view should be used for string with ' " ? From a41f755d8e09a6eb933cb339532a6f22d794c70e Mon Sep 17 00:00:00 2001 From: saipubw Date: Fri, 17 May 2024 17:59:22 +0800 Subject: [PATCH 02/12] [coro_rpc]rpc client support send_request without wait for response (#672) --- include/ylt/coro_io/client_pool.hpp | 75 +- include/ylt/coro_io/coro_io.hpp | 2 +- include/ylt/coro_io/io_context_pool.hpp | 2 +- include/ylt/coro_rpc/impl/coro_rpc_client.hpp | 869 ++++++++++++------ include/ylt/coro_rpc/impl/errno.h | 9 + include/ylt/coro_rpc/impl/expected.hpp | 5 +- .../standalone/cinatra/coro_http_client.hpp | 12 +- src/coro_io/tests/test_client_pool.cpp | 6 +- .../examples/base_examples/channel.cpp | 119 ++- .../examples/base_examples/client_pool.cpp | 112 ++- .../examples/base_examples/client_pools.cpp | 41 +- .../base_examples/concurrent_clients.cpp | 114 ++- .../examples/base_examples/rpc_service.cpp | 8 +- src/coro_rpc/tests/test_coro_rpc_client.cpp | 4 + src/coro_rpc/tests/test_coro_rpc_server.cpp | 7 - src/coro_rpc/tests/test_router.cpp | 7 +- 16 files changed, 903 insertions(+), 489 deletions(-) diff --git a/include/ylt/coro_io/client_pool.hpp b/include/ylt/coro_io/client_pool.hpp index 2f44949f2..21dc3df99 100644 --- a/include/ylt/coro_io/client_pool.hpp +++ b/include/ylt/coro_io/client_pool.hpp @@ -78,11 +78,11 @@ class client_pool : public std::enable_shared_from_this< break; } while (true) { - ELOG_DEBUG << "start collect timeout client of pool{" + ELOG_TRACE << "start collect timeout client of pool{" << self->host_name_ << "}, now client count: " << clients.size(); std::size_t is_all_cleared = clients.clear_old(clear_cnt); - ELOG_DEBUG << "finish collect timeout client of pool{" + ELOG_TRACE << "finish collect timeout client of pool{" << self->host_name_ << "}, now client cnt: " << clients.size(); if (is_all_cleared != 0) [[unlikely]] { @@ -109,36 +109,42 @@ class client_pool : public std::enable_shared_from_this< static auto rand_time(std::chrono::milliseconds ms) { static thread_local std::default_random_engine r; - std::uniform_real_distribution e(0.7f, 1.3f); + std::uniform_real_distribution e(1.0f, 1.2f); return std::chrono::milliseconds{static_cast(e(r) * ms.count())}; } - async_simple::coro::Lazy reconnect(std::unique_ptr& client) { + static async_simple::coro::Lazy reconnect( + std::unique_ptr& client, std::weak_ptr watcher) { using namespace std::chrono_literals; - for (unsigned int i = 0; i < pool_config_.connect_retry_count; ++i) { - ELOG_DEBUG << "try to reconnect client{" << client.get() << "},host:{" + std::shared_ptr self = watcher.lock(); + uint32_t i = UINT32_MAX; // (at least connect once) + do { + ELOG_TRACE << "try to reconnect client{" << client.get() << "},host:{" << client->get_host() << ":" << client->get_port() - << "}, try count:" << i - << "max retry limit:" << pool_config_.connect_retry_count; + << "}, try count:" << i << "max retry limit:" + << self->pool_config_.connect_retry_count; auto pre_time_point = std::chrono::steady_clock::now(); - bool ok = client_t::is_ok(co_await client->reconnect(host_name_)); + bool ok = client_t::is_ok(co_await client->connect(self->host_name_)); auto post_time_point = std::chrono::steady_clock::now(); auto cost_time = post_time_point - pre_time_point; - ELOG_DEBUG << "reconnect client{" << client.get() + ELOG_TRACE << "reconnect client{" << client.get() << "} cost time: " << cost_time / std::chrono::milliseconds{1} << "ms"; if (ok) { - ELOG_DEBUG << "reconnect client{" << client.get() << "} success"; + ELOG_TRACE << "reconnect client{" << client.get() << "} success"; co_return; } - ELOG_DEBUG << "reconnect client{" << client.get() + ELOG_TRACE << "reconnect client{" << client.get() << "} failed. If client close:{" << client->has_closed() << "}"; auto wait_time = rand_time( - (pool_config_.reconnect_wait_time * (i + 1) - cost_time) / 1ms * 1ms); + (self->pool_config_.reconnect_wait_time - cost_time) / 1ms * 1ms); + self = nullptr; if (wait_time.count() > 0) co_await coro_io::sleep_for(wait_time, &client->get_executor()); - } + self = watcher.lock(); + ++i; + } while (i < self->pool_config_.connect_retry_count); ELOG_WARN << "reconnect client{" << client.get() << "},host:{" << client->get_host() << ":" << client->get_port() << "} out of max limit, stop retry. connect failed"; @@ -150,30 +156,23 @@ class client_pool : public std::enable_shared_from_this< async_simple::Promise> promise_; }; - async_simple::coro::Lazy connect_client( + static async_simple::coro::Lazy connect_client( std::unique_ptr client, std::weak_ptr watcher, std::shared_ptr handler) { - ELOG_DEBUG << "try to connect client{" << client.get() - << "} to host:" << host_name_; - auto result = co_await client->connect(host_name_); - std::shared_ptr self = watcher.lock(); - if (!client_t::is_ok(result)) { - ELOG_DEBUG << "connect client{" << client.get() << "} to failed. "; - if (self) { - co_await reconnect(client); - } - } - if (client) { - ELOG_DEBUG << "connect client{" << client.get() << "} successful!"; - } + co_await reconnect(client, watcher); auto has_get_connect = handler->flag_.exchange(true); if (!has_get_connect) { handler->promise_.setValue(std::move(client)); } else { - auto conn_lim = std::min(10u, pool_config_.max_connection); - if (self && free_clients_.size() < conn_lim && client) { - enqueue(free_clients_, std::move(client), pool_config_.idle_timeout); + if (client) { + auto self = watcher.lock(); + auto conn_lim = + std::min(10u, self->pool_config_.max_connection); + if (self && self->free_clients_.size() < conn_lim) { + self->enqueue(self->free_clients_, std::move(client), + self->pool_config_.idle_timeout); + } } } } @@ -226,7 +225,7 @@ class client_pool : public std::enable_shared_from_this< } } }); - ELOG_DEBUG << "wait client by promise {" << &handler->promise_ << "}"; + ELOG_TRACE << "wait client by promise {" << &handler->promise_ << "}"; client = co_await handler->promise_.getFuture(); if (client) { executor->schedule([timer] { @@ -236,7 +235,7 @@ class client_pool : public std::enable_shared_from_this< } } else { - ELOG_DEBUG << "get free client{" << client.get() << "}. from queue"; + ELOG_TRACE << "get free client{" << client.get() << "}. from queue"; } co_return std::move(client); } @@ -248,7 +247,7 @@ class client_pool : public std::enable_shared_from_this< if (clients.enqueue(std::move(client)) == 1) { std::size_t expected = 0; if (clients.collecter_cnt_.compare_exchange_strong(expected, 1)) { - ELOG_DEBUG << "start timeout client collecter of client_pool{" + ELOG_TRACE << "start timeout client collecter of client_pool{" << host_name_ << "}"; collect_idle_timeout_client( this->weak_from_this(), clients, @@ -272,7 +271,7 @@ class client_pool : public std::enable_shared_from_this< if (!has_get_connect) { handler->promise_.setValue(std::move(client)); promise_cnt_ -= cnt; - ELOG_DEBUG << "collect free client{" << client.get() + ELOG_TRACE << "collect free client{" << client.get() << "} and wake up promise{" << &handler->promise_ << "}"; return; } @@ -282,12 +281,12 @@ class client_pool : public std::enable_shared_from_this< if (free_clients_.size() < pool_config_.max_connection) { if (client) { - ELOG_DEBUG << "collect free client{" << client.get() << "} enqueue"; + ELOG_TRACE << "collect free client{" << client.get() << "} enqueue"; enqueue(free_clients_, std::move(client), pool_config_.idle_timeout); } } else { - ELOG_DEBUG << "out of max connection limit <<" + ELOG_TRACE << "out of max connection limit <<" << pool_config_.max_connection << ", collect free client{" << client.get() << "} enqueue short connect queue"; enqueue(short_connect_clients_, std::move(client), @@ -295,7 +294,7 @@ class client_pool : public std::enable_shared_from_this< } } else { - ELOG_DEBUG << "client{" << client.get() + ELOG_TRACE << "client{" << client.get() << "} is closed. we won't collect it"; } diff --git a/include/ylt/coro_io/coro_io.hpp b/include/ylt/coro_io/coro_io.hpp index d4d114ed6..eab7727b0 100644 --- a/include/ylt/coro_io/coro_io.hpp +++ b/include/ylt/coro_io/coro_io.hpp @@ -317,7 +317,7 @@ inline async_simple::coro::Lazy sleep_for(Duration d) { template struct post_helper { void operator()(auto handler) { - asio::dispatch(e, [this, handler]() { + asio::post(e, [this, handler]() { try { if constexpr (std::is_same_v>) { func(); diff --git a/include/ylt/coro_io/io_context_pool.hpp b/include/ylt/coro_io/io_context_pool.hpp index 07eb8e522..b45c63ff9 100644 --- a/include/ylt/coro_io/io_context_pool.hpp +++ b/include/ylt/coro_io/io_context_pool.hpp @@ -75,7 +75,7 @@ class ExecutorWrapper : public async_simple::Executor { context_t &context() { return executor_.context(); } - auto get_asio_executor() { return executor_; } + auto get_asio_executor() const { return executor_; } operator ExecutorImpl() { return executor_; } diff --git a/include/ylt/coro_rpc/impl/coro_rpc_client.hpp b/include/ylt/coro_rpc/impl/coro_rpc_client.hpp index 55d03c019..53f5da8cf 100644 --- a/include/ylt/coro_rpc/impl/coro_rpc_client.hpp +++ b/include/ylt/coro_rpc/impl/coro_rpc_client.hpp @@ -22,10 +22,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +43,10 @@ #include "asio/buffer.hpp" #include "asio/dispatch.hpp" #include "asio/registered_buffer.hpp" +#include "async_simple/Executor.h" +#include "async_simple/Promise.h" +#include "async_simple/coro/Mutex.h" +#include "async_simple/coro/SpinLock.h" #include "common_service.hpp" #include "context.hpp" #include "expected.hpp" @@ -80,6 +87,42 @@ template <> struct rpc_return_type { using type = std::monostate; }; + +struct resp_body { + std::string read_buf_; + std::string resp_attachment_buf_; +}; + +template +struct async_rpc_result_value_t { + private: + T result_; + resp_body buffer_; + + public: + async_rpc_result_value_t(T &&result, resp_body &&buffer) + : result_(std::move(result)), buffer_(std::move(buffer)) {} + async_rpc_result_value_t(T &&result) : result_(std::move(result)) {} + T &result() noexcept { return result_; } + const T &result() const noexcept { return result_; } + std::string_view attachment() const noexcept { + return buffer_.resp_attachment_buf_; + } + resp_body release_buffer() { return std::move(buffer_); } +}; + +template <> +struct async_rpc_result_value_t { + resp_body buffer_; + std::string_view attachment() const noexcept { + return buffer_.resp_attachment_buf_; + } + resp_body release_buffer() { return std::move(buffer_); } +}; + +template +using async_rpc_result = expected, rpc_error>; + template using rpc_return_type_t = typename rpc_return_type::type; /*! @@ -117,6 +160,7 @@ class coro_rpc_client { std::chrono::milliseconds{5000}; std::string host; std::string port; + bool enable_tcp_no_delay_ = true; #ifdef YLT_ENABLE_SSL std::filesystem::path ssl_cert_path; std::string ssl_domain; @@ -130,7 +174,7 @@ class coro_rpc_client { coro_rpc_client(asio::io_context::executor_type executor, uint32_t client_id = 0) : control_(std::make_shared(executor, false)), - timer_(executor) { + timer_(std::make_unique(executor)) { config_.client_id = client_id; } @@ -139,11 +183,12 @@ class coro_rpc_client { * @param io_context asio io_context, async event handler */ coro_rpc_client( - coro_io::ExecutorWrapper<> &executor = *coro_io::get_global_executor(), + coro_io::ExecutorWrapper<> *executor = coro_io::get_global_executor(), uint32_t client_id = 0) : control_( - std::make_shared(executor.get_asio_executor(), false)), - timer_(executor.get_asio_executor()) { + std::make_shared(executor->get_asio_executor(), false)), + timer_(std::make_unique( + executor->get_asio_executor())) { config_.client_id = client_id; } @@ -151,6 +196,8 @@ class coro_rpc_client { std::string_view get_port() const { return config_.port; } + const config &get_config() const { return config_; } + [[nodiscard]] bool init_config(const config &conf) { config_ = conf; #ifdef YLT_ENABLE_SSL @@ -166,43 +213,8 @@ class coro_rpc_client { * * @return true if client closed, otherwise false. */ - [[nodiscard]] bool has_closed() { return has_closed_; } + [[nodiscard]] bool has_closed() { return control_->has_closed_; } - /*! - * Reconnect server - * - * If connect hasn't been closed, it will be closed first then connect to - * server, else the client will connect to server directly - * - * @param host server address - * @param port server port - * @param timeout_duration RPC call timeout - * @return error code - */ - [[nodiscard]] async_simple::coro::Lazy reconnect( - std::string host, std::string port, - std::chrono::steady_clock::duration timeout_duration = - std::chrono::seconds(5)) { - config_.host = std::move(host); - config_.port = std::move(port); - config_.timeout_duration = - std::chrono::duration_cast(timeout_duration); - reset(); - return connect(is_reconnect_t{true}); - } - - [[nodiscard]] async_simple::coro::Lazy reconnect( - std::string endpoint, - std::chrono::steady_clock::duration timeout_duration = - std::chrono::seconds(5)) { - auto pos = endpoint.find(':'); - config_.host = endpoint.substr(0, pos); - config_.port = endpoint.substr(pos + 1); - config_.timeout_duration = - std::chrono::duration_cast(timeout_duration); - reset(); - return connect(is_reconnect_t{true}); - } /*! * Connect server * @@ -218,22 +230,50 @@ class coro_rpc_client { std::string host, std::string port, std::chrono::steady_clock::duration timeout_duration = std::chrono::seconds(5)) { + auto lock_ok = connect_mutex_.tryLock(); + if (!lock_ok) { + co_await connect_mutex_.coScopedLock(); + co_return err_code{}; + // do nothing, someone has reconnect the client + } config_.host = std::move(host); config_.port = std::move(port); config_.timeout_duration = std::chrono::duration_cast(timeout_duration); - return connect(); + auto ret = co_await connect_impl(); + connect_mutex_.unlock(); + co_return std::move(ret); } [[nodiscard]] async_simple::coro::Lazy connect( std::string_view endpoint, std::chrono::steady_clock::duration timeout_duration = std::chrono::seconds(5)) { auto pos = endpoint.find(':'); + auto lock_ok = connect_mutex_.tryLock(); + if (!lock_ok) { + co_await connect_mutex_.coScopedLock(); + co_return err_code{}; + // do nothing, someone has reconnect the client + } config_.host = endpoint.substr(0, pos); config_.port = endpoint.substr(pos + 1); config_.timeout_duration = std::chrono::duration_cast(timeout_duration); - return connect(); + auto ret = co_await connect_impl(); + connect_mutex_.unlock(); + co_return std::move(ret); + } + + [[nodiscard]] async_simple::coro::Lazy connect() { + auto lock_ok = connect_mutex_.tryLock(); + if (!lock_ok) { + co_await connect_mutex_.coScopedLock(); + co_return err_code{}; + // do nothing, someone has reconnect the client + } + auto ret = co_await connect_impl(); + connect_mutex_.unlock(); + co_return std::move(ret); } #ifdef YLT_ENABLE_SSL @@ -259,10 +299,9 @@ class coro_rpc_client { * @return RPC call result */ template - async_simple::coro::Lazy< - rpc_result()), coro_rpc_protocol>> - call(Args... args) { - return call_for(std::chrono::seconds(5), std::move(args)...); + async_simple::coro::Lazy())>> call( + Args &&...args) { + return call_for(std::chrono::seconds(5), std::forward(args)...); } /*! @@ -277,62 +316,27 @@ class coro_rpc_client { * @return RPC call result */ template - async_simple::coro::Lazy< - rpc_result()), coro_rpc_protocol>> - call_for(auto duration, Args... args) { - using R = decltype(get_return_type()); - - if (has_closed_) - AS_UNLIKELY { - ELOGV(ERROR, "client has been closed, please re-connect"); - auto ret = rpc_result{ - unexpect_t{}, - rpc_error{errc::io_error, - "client has been closed, please re-connect"}}; - co_return ret; + async_simple::coro::Lazy())>> + call_for(auto duration, Args &&...args) { + using return_type = decltype(get_return_type()); + auto async_result = + co_await co_await send_request_for_with_attachment( + duration, req_attachment_, std::forward(args)...); + req_attachment_ = {}; + if (async_result) { + control_->resp_buffer_ = async_result->release_buffer(); + if constexpr (std::is_same_v) { + co_return expected{}; + } + else { + co_return expected{ + std::move(async_result->result())}; } - - rpc_result ret; -#ifdef YLT_ENABLE_SSL - if (!ssl_init_ret_) { - ret = rpc_result{ - unexpect_t{}, - rpc_error{errc::not_connected, - std::string{make_error_message(errc::not_connected)}}}; - co_return ret; - } -#endif - - static_check(); - - timeout(duration, "rpc call timer canceled").start([](auto &&) { - }); - -#ifdef YLT_ENABLE_SSL - if (!config_.ssl_cert_path.empty()) { - assert(ssl_stream_); - ret = co_await call_impl(*ssl_stream_, std::move(args)...); } else { -#endif - ret = co_await call_impl(control_->socket_, std::move(args)...); -#ifdef YLT_ENABLE_SSL + co_return expected{ + unexpect_t{}, std::move(async_result.error())}; } -#endif - - std::error_code err_code; - timer_.cancel(err_code); - - if (control_->is_timeout_) { - ret = rpc_result{ - unexpect_t{}, rpc_error{errc::timed_out, "rpc call timed out"}}; - } - -#ifdef UNIT_TEST_INJECT - ELOGV(INFO, "client_id %d call %s %s", config_.client_id, - get_func_name().data(), ret ? "ok" : "failed"); -#endif - co_return ret; } /*! @@ -343,11 +347,7 @@ class coro_rpc_client { uint32_t get_client_id() const { return config_.client_id; } void close() { - if (has_closed_) { - return; - } - has_closed_ = true; - ELOGV(INFO, "client_id %d close", config_.client_id); + // ELOGV(INFO, "client_id %d close", config_.client_id); close_socket(control_); } @@ -360,10 +360,12 @@ class coro_rpc_client { return true; } - std::string_view get_resp_attachment() const { return resp_attachment_buf_; } + std::string_view get_resp_attachment() const { + return control_->resp_buffer_.resp_attachment_buf_; + } std::string release_resp_attachment() { - return std::move(resp_attachment_buf_); + return std::move(control_->resp_buffer_.resp_attachment_buf_); } template @@ -381,37 +383,35 @@ class coro_rpc_client { control_->socket_ = asio::ip::tcp::socket(control_->executor_.get_asio_executor()); control_->is_timeout_ = false; - has_closed_ = false; + control_->has_closed_ = false; } static bool is_ok(coro_rpc::err_code ec) noexcept { return !ec; } - [[nodiscard]] async_simple::coro::Lazy connect( - is_reconnect_t is_reconnect = is_reconnect_t{false}) { + + [[nodiscard]] async_simple::coro::Lazy connect_impl() { + if (should_reset_) { + reset(); + } + else { + should_reset_ = true; + } #ifdef YLT_ENABLE_SSL if (!ssl_init_ret_) { std::cout << "ssl_init_ret_: " << ssl_init_ret_ << std::endl; co_return errc::not_connected; } #endif - if (!is_reconnect.value && has_closed_) - AS_UNLIKELY { - ELOGV(ERROR, - "a closed client is not allowed connect again, please use " - "reconnect function or create a new " - "client"); - co_return errc::io_error; - } - has_closed_ = false; + control_->has_closed_ = false; ELOGV(INFO, "client_id %d begin to connect %s", config_.client_id, config_.port.data()); - timeout(config_.timeout_duration, "connect timer canceled") + timeout(*this->timer_, config_.timeout_duration, "connect timer canceled") .start([](auto &&) { }); std::error_code ec = co_await coro_io::async_connect( &control_->executor_, control_->socket_, config_.host, config_.port); std::error_code err_code; - timer_.cancel(err_code); + timer_->cancel(err_code); if (ec) { if (control_->is_timeout_) { @@ -424,14 +424,15 @@ class coro_rpc_client { ELOGV(WARN, "client_id %d connect timeout", config_.client_id); co_return errc::timed_out; } - - control_->socket_.set_option(asio::ip::tcp::no_delay(true), ec); + if (config_.enable_tcp_no_delay_ == true) { + control_->socket_.set_option(asio::ip::tcp::no_delay(true), ec); + } #ifdef YLT_ENABLE_SSL if (!config_.ssl_cert_path.empty()) { - assert(ssl_stream_); + assert(control_->ssl_stream_); auto shake_ec = co_await coro_io::async_handshake( - ssl_stream_, asio::ssl::stream_base::client); + control_->ssl_stream_, asio::ssl::stream_base::client); if (shake_ec) { ELOGV(WARN, "client_id %d handshake failed: %s", config_.client_id, shake_ec.message().data()); @@ -461,7 +462,7 @@ class coro_rpc_client { ssl_ctx_.set_verify_mode(asio::ssl::verify_peer); ssl_ctx_.set_verify_callback( asio::ssl::host_name_verification(config_.ssl_domain)); - ssl_stream_ = + control_->ssl_stream_ = std::make_unique>( control_->socket_, ssl_ctx_); ssl_init_ret_ = true; @@ -471,10 +472,12 @@ class coro_rpc_client { return ssl_init_ret_; } #endif - async_simple::coro::Lazy timeout(auto duration, std::string err_msg) { - timer_.expires_after(duration); + + async_simple::coro::Lazy timeout(coro_io::period_timer &timer, + auto duration, std::string err_msg) { + timer.expires_after(duration); std::weak_ptr socket_watcher = control_; - bool is_timeout = co_await timer_.async_await(); + bool is_timeout = co_await timer.async_await(); if (!is_timeout) { co_return false; } @@ -530,148 +533,6 @@ class coro_rpc_client { } } - template - async_simple::coro::Lazy< - rpc_result()), coro_rpc_protocol>> - call_impl(Socket &socket, Args... args) { - using R = decltype(get_return_type()); - - auto buffer = prepare_buffer(std::move(args)...); - - rpc_result r{}; - if (buffer.empty()) { - r = rpc_result{ - unexpect_t{}, rpc_error{errc::message_too_large, - "rpc body serialize size too big"}}; - co_return r; - } -#ifdef GENERATE_BENCHMARK_DATA - std::ofstream file( - benchmark_file_path + std::string{get_func_name()} + ".in", - std::ofstream::binary | std::ofstream::out); - file << std::string_view{(char *)buffer.data(), buffer.size()}; - file.close(); -#endif - std::pair ret; -#ifdef UNIT_TEST_INJECT - if (g_action == inject_action::client_send_bad_header) { - buffer[0] = (std::byte)(uint8_t(buffer[0]) + 1); - } - if (g_action == inject_action::client_close_socket_after_send_header) { - ret = co_await coro_io::async_write( - socket, asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN)); - ELOGV(INFO, "client_id %d close socket", config_.client_id); - close(); - r = rpc_result{ - unexpect_t{}, rpc_error{errc::io_error, ret.first.message()}}; - co_return r; - } - else if (g_action == - inject_action::client_close_socket_after_send_partial_header) { - ret = co_await coro_io::async_write( - socket, - asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN - 1)); - ELOGV(INFO, "client_id %d close socket", config_.client_id); - close(); - r = rpc_result{ - unexpect_t{}, rpc_error{errc::io_error, ret.first.message()}}; - co_return r; - } - else if (g_action == - inject_action::client_shutdown_socket_after_send_header) { - ret = co_await coro_io::async_write( - socket, asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN)); - ELOGV(INFO, "client_id %d shutdown", config_.client_id); - control_->socket_.shutdown(asio::ip::tcp::socket::shutdown_send); - r = rpc_result{ - unexpect_t{}, rpc_error{errc::io_error, ret.first.message()}}; - co_return r; - } - else { -#endif - if (req_attachment_.empty()) { - ret = co_await coro_io::async_write( - socket, asio::buffer(buffer.data(), buffer.size())); - } - else { - std::array iov{ - asio::const_buffer{buffer.data(), buffer.size()}, - asio::const_buffer{req_attachment_.data(), req_attachment_.size()}}; - ret = co_await coro_io::async_write(socket, iov); - req_attachment_ = {}; - } -#ifdef UNIT_TEST_INJECT - } -#endif - if (!ret.first) { -#ifdef UNIT_TEST_INJECT - if (g_action == inject_action::client_close_socket_after_send_payload) { - ELOGV(INFO, "client_id %d client_close_socket_after_send_payload", - config_.client_id); - r = rpc_result{ - unexpect_t{}, rpc_error{errc::io_error, ret.first.message()}}; - close(); - co_return r; - } -#endif - coro_rpc_protocol::resp_header header; - ret = co_await coro_io::async_read( - socket, - asio::buffer((char *)&header, coro_rpc_protocol::RESP_HEAD_LEN)); - if (!ret.first) { - uint32_t body_len = header.length; - struct_pack::detail::resize(read_buf_, body_len); - if (header.attach_length == 0) { - ret = co_await coro_io::async_read( - socket, asio::buffer(read_buf_.data(), body_len)); - resp_attachment_buf_.clear(); - } - else { - struct_pack::detail::resize(resp_attachment_buf_, - header.attach_length); - std::array iov{ - asio::mutable_buffer{read_buf_.data(), body_len}, - asio::mutable_buffer{resp_attachment_buf_.data(), - resp_attachment_buf_.size()}}; - ret = co_await coro_io::async_read(socket, iov); - } - if (!ret.first) { -#ifdef GENERATE_BENCHMARK_DATA - std::ofstream file( - benchmark_file_path + std::string{get_func_name()} + ".out", - std::ofstream::binary | std::ofstream::out); - file << std::string_view{(char *)&header, - coro_rpc_protocol::RESP_HEAD_LEN}; - file << read_buf_; - file << resp_attachment_buf_; - file.close(); -#endif - bool ec = false; - r = handle_response_buffer(read_buf_, header.err_code, ec); - if (ec) { - close(); - } - co_return r; - } - } - } -#ifdef UNIT_TEST_INJECT - if (g_action == inject_action::force_inject_client_write_data_timeout) { - control_->is_timeout_ = true; - } -#endif - if (control_->is_timeout_) { - r = rpc_result{ - unexpect_t{}, rpc_error{.code = errc::timed_out, .msg = {}}}; - } - else { - r = rpc_result{ - unexpect_t{}, - rpc_error{.code = errc::io_error, .msg = ret.first.message()}}; - } - close(); - co_return r; - } /* * buffer layout * ┌────────────────┬────────────────┐ @@ -681,7 +542,7 @@ class coro_rpc_client { * └────────────────┴────────────────┘ */ template - std::vector prepare_buffer(Args &&...args) { + std::vector prepare_buffer(uint32_t &id, Args &&...args) { std::vector buffer; std::size_t offset = coro_rpc_protocol::REQ_HEAD_LEN; if constexpr (sizeof...(Args) > 0) { @@ -697,8 +558,11 @@ class coro_rpc_client { header.magic = coro_rpc_protocol::magic_number; header.function_id = func_id(); header.attach_length = req_attachment_.size(); + id = request_id_++; + ELOG_TRACE << "send request ID:" << id << "."; + header.seq_num = id; + #ifdef UNIT_TEST_INJECT - header.seq_num = config_.client_id; if (g_action == inject_action::client_send_bad_magic_num) { header.magic = coro_rpc_protocol::magic_number + 1; } @@ -720,9 +584,9 @@ class coro_rpc_client { } template - rpc_result handle_response_buffer(std::string &buffer, - uint8_t rpc_errc, - bool &error_happen) { + static rpc_result handle_response_buffer(std::string_view buffer, + uint8_t rpc_errc, + bool &has_error) { rpc_return_type_t ret; struct_pack::err_code ec; rpc_error err; @@ -743,23 +607,22 @@ class coro_rpc_client { err.val() = rpc_errc; ec = struct_pack::deserialize_to(err.msg, buffer); if SP_LIKELY (!ec) { - ELOGV(WARNING, "deserilaize rpc result failed"); - error_happen = true; - return rpc_result{unexpect_t{}, std::move(err)}; + has_error = true; + return rpc_result{unexpect_t{}, std::move(err)}; } } else { ec = struct_pack::deserialize_to(err, buffer); if SP_LIKELY (!ec) { - ELOGV(WARNING, "deserilaize rpc result failed"); - return rpc_result{unexpect_t{}, std::move(err)}; + return rpc_result{unexpect_t{}, std::move(err)}; } } } - error_happen = true; + has_error = true; // deserialize failed. + ELOGV(WARNING, "deserilaize rpc result failed"); err = {errc::invalid_rpc_result, "failed to deserialize rpc return value"}; - return rpc_result{unexpect_t{}, std::move(err)}; + return rpc_result{unexpect_t{}, std::move(err)}; } template @@ -768,11 +631,22 @@ class coro_rpc_client { constexpr bool has_conn_v = requires { typename First::return_type; }; return util::get_args(); } + template + static decltype(auto) add_const(U &&u) { + if constexpr (std::is_const_v>) { + return struct_pack::detail::declval(); + } + else { + return struct_pack::detail::declval(); + } + } template void pack_to_impl(Buffer &buffer, std::size_t offset, Args &&...args) { struct_pack::serialize_to_with_offset( - buffer, offset, std::forward(std::forward(args))...); + buffer, offset, + std::forward(args))>( + (std::forward(args)))...); } template @@ -790,16 +664,59 @@ class coro_rpc_client { offset, std::forward(args)...); } + struct async_rpc_raw_result_value_type { + resp_body buffer_; + uint8_t errc_; + }; + + using async_rpc_raw_result = + std::variant; + + struct control_t; + + struct handler_t { + std::unique_ptr timer_; + async_simple::Promise promise_; + handler_t(std::unique_ptr &&timer, + async_simple::Promise &&promise) + : timer_(std::move(timer)), promise_(std::move(promise)) {} + void operator()(resp_body &&buffer, uint8_t rpc_errc) { + timer_->cancel(); + promise_.setValue(async_rpc_raw_result{ + async_rpc_raw_result_value_type{std::move(buffer), rpc_errc}}); + } + void local_error(std::error_code &ec) { + timer_->cancel(); + promise_.setValue(async_rpc_raw_result{ec}); + } + }; struct control_t { - asio::ip::tcp::socket socket_; +#ifdef YLT_ENABLE_SSL + std::unique_ptr> ssl_stream_; +#endif +#ifdef GENERATE_BENCHMARK_DATA + std::string func_name_; +#endif bool is_timeout_; + std::atomic has_closed_ = false; coro_io::ExecutorWrapper<> executor_; + std::unordered_map response_handler_table_; + resp_body resp_buffer_; + asio::ip::tcp::socket socket_; + std::atomic recving_cnt_ = 0; control_t(asio::io_context::executor_type executor, bool is_timeout) - : socket_(executor), is_timeout_(is_timeout), executor_(executor) {} + : socket_(executor), + is_timeout_(is_timeout), + has_closed_(false), + executor_(executor) {} }; static void close_socket( std::shared_ptr control) { + bool expected = false; + if (!control->has_closed_.compare_exchange_strong(expected, true)) { + return; + } control->executor_.schedule([control = std::move(control)]() { asio::error_code ignored_ec; control->socket_.shutdown(asio::ip::tcp::socket::shutdown_both, @@ -816,25 +733,397 @@ class coro_rpc_client { } template - rpc_result()), coro_rpc_protocol> sync_call( - Args &&...args) { + rpc_result())> sync_call(Args &&...args) { return async_simple::coro::syncAwait( call(std::forward(args)...)); } #endif + template + async_simple::coro::Lazy send_request_for_impl( + auto duration, uint32_t &id, coro_io::period_timer &timer, + std::string_view attachment, Args &&...args) { + using R = decltype(get_return_type()); + + if (control_->has_closed_) + AS_UNLIKELY { + ELOGV(ERROR, "client has been closed, please re-connect"); + co_return rpc_error{errc::io_error, + "client has been closed, please re-connect"}; + } + +#ifdef YLT_ENABLE_SSL + if (!ssl_init_ret_) { + co_return rpc_error{errc::not_connected}; + } +#endif + + static_check(); + + if (duration.count() > 0) { + timeout(timer, duration, "rpc call timer canceled").start([](auto &&) { + }); + } + +#ifdef YLT_ENABLE_SSL + if (!config_.ssl_cert_path.empty()) { + assert(control_->ssl_stream_); + co_return co_await send_impl(*control_->ssl_stream_, id, attachment, + std::forward(args)...); + } + else { +#endif + co_return co_await send_impl(control_->socket_, id, attachment, + std::forward(args)...); +#ifdef YLT_ENABLE_SSL + } +#endif + } + + static void send_err_response(control_t *controller, std::error_code &errc) { + if (controller->is_timeout_) { + errc = std::make_error_code(std::errc::timed_out); + } + for (auto &e : controller->response_handler_table_) { + e.second.local_error(errc); + } + controller->response_handler_table_.clear(); + } + template + static async_simple::coro::Lazy recv( + std::shared_ptr controller, Socket &socket) { + std::pair ret; + do { + coro_rpc_protocol::resp_header header; + ret = co_await coro_io::async_read( + socket, + asio::buffer((char *)&header, coro_rpc_protocol::RESP_HEAD_LEN)); + if (ret.first) { + ELOG_ERROR << "read rpc head failed, error msg:" << ret.first.message() + << ". close the socket.value=" << ret.first.value(); + break; + } + uint32_t body_len = header.length; + struct_pack::detail::resize(controller->resp_buffer_.read_buf_, body_len); + if (header.attach_length == 0) { + ret = co_await coro_io::async_read( + socket, + asio::buffer(controller->resp_buffer_.read_buf_.data(), body_len)); + controller->resp_buffer_.resp_attachment_buf_.clear(); + } + else { + struct_pack::detail::resize( + controller->resp_buffer_.resp_attachment_buf_, + header.attach_length); + std::array iov{ + asio::mutable_buffer{controller->resp_buffer_.read_buf_.data(), + body_len}, + asio::mutable_buffer{ + controller->resp_buffer_.resp_attachment_buf_.data(), + controller->resp_buffer_.resp_attachment_buf_.size()}}; + ret = co_await coro_io::async_read(socket, iov); + } + if (ret.first) { + ELOG_ERROR << "read rpc body failed, error msg:" << ret.first.message() + << ". close the socket."; + break; + } +#ifdef GENERATE_BENCHMARK_DATA + std::ofstream file(benchmark_file_path + controller->func_name_ + ".out", + std::ofstream::binary | std::ofstream::out); + file << std::string_view{(char *)&header, + coro_rpc_protocol::RESP_HEAD_LEN}; + file << controller->resp_buffer_.read_buf_; + file << controller->resp_buffer_.resp_attachment_buf_; + file.close(); +#endif + --controller->recving_cnt_; + if (auto iter = controller->response_handler_table_.find(header.seq_num); + iter != controller->response_handler_table_.end()) { + ELOG_TRACE << "find request ID:" << header.seq_num + << ". start notify response handler"; + iter->second(std::move(controller->resp_buffer_), header.err_code); + controller->response_handler_table_.erase(iter); + if (controller->response_handler_table_.empty()) { + co_return; + } + } + else { + ELOG_ERROR << "unexists request ID:" << header.seq_num + << ". close the socket."; + break; + } + } while (true); + close_socket(controller); + send_err_response(controller.get(), ret.first); + co_return; + } + + template + static async_simple::coro::Lazy> deserialize_rpc_result( + async_simple::Future future, + std::weak_ptr watcher) { + auto ret_ = co_await std::move(future); + + if (ret_.index() == 1) [[unlikely]] { // local error + auto &ret = std::get<1>(ret_); + if (ret.value() == static_cast(std::errc::operation_canceled) || + ret.value() == static_cast(std::errc::timed_out)) { + co_return coro_rpc::unexpected{ + rpc_error{errc::timed_out, ret.message()}}; + } + else { + co_return coro_rpc::unexpected{ + rpc_error{errc::io_error, ret.message()}}; + } + } + + bool has_error = false; + auto &ret = std::get<0>(ret_); + auto result = + handle_response_buffer(ret.buffer_.read_buf_, ret.errc_, has_error); + if (has_error) { + if (auto w = watcher.lock(); w) { + close_socket(std::move(w)); + } + } + if (result) { + if constexpr (std::is_same_v) { + co_return async_rpc_result{ + async_rpc_result_value_t{std::move(ret.buffer_)}}; + } + else { + co_return async_rpc_result{async_rpc_result_value_t{ + std::move(result.value()), std::move(ret.buffer_)}}; + } + } + else { + co_return coro_rpc::unexpected{result.error()}; + } + } + + public: + template + async_simple::coro::Lazy())>>> + send_request(Args &&...args) { + return send_request_for_with_attachment(std::chrono::seconds{5}, {}, + std::forward(args)...); + } + + template + async_simple::coro::Lazy())>>> + send_request_with_attachment(std::string_view request_attachment, + Args &&...args) { + return send_request_for_with_attachment(std::chrono::seconds{5}, + request_attachment, + std::forward(args)...); + } + + template + async_simple::coro::Lazy())>>> + send_request_for(Args &&...args) { + return send_request_for_with_attachment(std::chrono::seconds{5}, + std::string_view{}, + std::forward(args)...); + } + + struct recving_guard { + recving_guard(control_t *ctrl) : ctrl_(ctrl) { ctrl_->recving_cnt_++; } + void release() { ctrl_ = nullptr; } + ~recving_guard() { + if (ctrl_) { + --ctrl_->recving_cnt_; + } + } + control_t *ctrl_; + }; + + private: + template + static async_simple::coro::Lazy> build_failed_rpc_result( + rpc_error err) { + co_return unexpected{err}; + } + + public: + template + async_simple::coro::Lazy())>>> + send_request_for_with_attachment(auto time_out_duration, + std::string_view request_attachment, + Args &&...args) { + using rpc_return_t = decltype(get_return_type()); + recving_guard guard(control_.get()); + uint32_t id; + auto timer = std::make_unique( + control_->executor_.get_asio_executor()); + auto result = co_await send_request_for_impl( + time_out_duration, id, *timer, request_attachment, + std::forward(args)...); + auto &control = *control_; + if (!result) { + async_simple::Promise promise; + auto future = promise.getFuture(); + bool is_empty = control.response_handler_table_.empty(); + auto &&[_, is_ok] = control.response_handler_table_.try_emplace( + id, std::move(timer), std::move(promise)); + if (!is_ok) [[unlikely]] { + close(); + co_return build_failed_rpc_result( + rpc_error{coro_rpc::errc::serial_number_conflict}); + } + else { + if (is_empty) { +#ifdef YLT_ENABLE_SSL + if (!config_.ssl_cert_path.empty()) { + assert(control.ssl_stream_); + recv(control_, *control.ssl_stream_).start([](auto &&) { + }); + } + else { +#endif + recv(control_, control.socket_).start([](auto &&) { + }); +#ifdef YLT_ENABLE_SSL + } +#endif + } + guard.release(); + co_return deserialize_rpc_result( + std::move(future), std::weak_ptr{control_}); + } + } + else { + auto i = build_failed_rpc_result(std::move(result)); + co_return build_failed_rpc_result(std::move(result)); + } + } + + uint32_t get_pipeline_size() { return control_->recving_cnt_; } + + private: + template + async_simple::coro::Lazy send_impl(Socket &socket, uint32_t &id, + std::string_view req_attachment, + Args &&...args) { + auto buffer = prepare_buffer(id, std::forward(args)...); + if (buffer.empty()) { + co_return rpc_error{errc::message_too_large}; + } +#ifdef GENERATE_BENCHMARK_DATA + control_->func_name_ = get_func_name(); + std::ofstream file(benchmark_file_path + control_->func_name_ + ".in", + std::ofstream::binary | std::ofstream::out); + file << std::string_view{(char *)buffer.data(), buffer.size()}; + file.close(); +#endif + std::pair ret; +#ifdef UNIT_TEST_INJECT + if (g_action == inject_action::client_send_bad_header) { + buffer[0] = (std::byte)(uint8_t(buffer[0]) + 1); + } + if (g_action == inject_action::client_close_socket_after_send_header) { + ret = co_await coro_io::async_write( + socket, asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN)); + ELOGV(INFO, "client_id %d close socket", config_.client_id); + close(); + co_return rpc_error{errc::io_error, ret.first.message()}; + } + else if (g_action == + inject_action::client_close_socket_after_send_partial_header) { + ret = co_await coro_io::async_write( + socket, + asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN - 1)); + ELOGV(INFO, "client_id %d close socket", config_.client_id); + close(); + co_return rpc_error{errc::io_error, ret.first.message()}; + } + else if (g_action == + inject_action::client_shutdown_socket_after_send_header) { + ret = co_await coro_io::async_write( + socket, asio::buffer(buffer.data(), coro_rpc_protocol::REQ_HEAD_LEN)); + ELOGV(INFO, "client_id %d shutdown", config_.client_id); + control_->socket_.shutdown(asio::ip::tcp::socket::shutdown_send); + co_return rpc_error{errc::io_error, ret.first.message()}; + } + else { +#endif + if (req_attachment.empty()) { + while (true) { + bool expected = false; + if (write_mutex_.compare_exchange_weak(expected, true)) { + break; + } + co_await coro_io::post( + []() { + }, + &control_->executor_); + } + ret = co_await coro_io::async_write( + socket, asio::buffer(buffer.data(), buffer.size())); + write_mutex_ = false; + } + else { + std::array iov{ + asio::const_buffer{buffer.data(), buffer.size()}, + asio::const_buffer{req_attachment.data(), req_attachment.size()}}; + while (true) { + bool expected = false; + if (write_mutex_.compare_exchange_weak(expected, true)) { + break; + } + co_await coro_io::post( + []() { + }, + &control_->executor_); + } + ret = co_await coro_io::async_write(socket, iov); + write_mutex_ = false; + } +#ifdef UNIT_TEST_INJECT + } +#endif +#ifdef UNIT_TEST_INJECT + if (g_action == inject_action::force_inject_client_write_data_timeout) { + control_->is_timeout_ = true; + } +#endif +#ifdef UNIT_TEST_INJECT + if (g_action == inject_action::client_close_socket_after_send_payload) { + ELOGV(INFO, "client_id %d client_close_socket_after_send_payload", + config_.client_id); + close(); + co_return rpc_error{errc::io_error, ret.first.message()}; + } +#endif + if (ret.first) { + close(); + if (control_->is_timeout_) { + co_return rpc_error{errc::timed_out}; + } + else { + co_return rpc_error{errc::io_error, ret.first.message()}; + } + } + co_return rpc_error{}; + } + private: - coro_io::period_timer timer_; + bool should_reset_ = false; + async_simple::coro::Mutex connect_mutex_; + std::atomic write_mutex_ = false; + std::atomic request_id_{0}; + std::unique_ptr timer_; std::shared_ptr control_; - std::string read_buf_, resp_attachment_buf_; std::string_view req_attachment_; config config_; constexpr static std::size_t default_read_buf_size_ = 256; #ifdef YLT_ENABLE_SSL asio::ssl::context ssl_ctx_{asio::ssl::context::sslv23}; - std::unique_ptr> ssl_stream_; bool ssl_init_ret_ = true; #endif - std::atomic has_closed_ = false; }; } // namespace coro_rpc diff --git a/include/ylt/coro_rpc/impl/errno.h b/include/ylt/coro_rpc/impl/errno.h index 0d7c1b6bd..2fd4dabac 100644 --- a/include/ylt/coro_rpc/impl/errno.h +++ b/include/ylt/coro_rpc/impl/errno.h @@ -35,6 +35,7 @@ enum class errc : uint16_t { message_too_large, server_has_ran, invalid_rpc_result, + serial_number_conflict, }; inline constexpr std::string_view make_error_message(errc ec) noexcept { switch (ec) { @@ -70,6 +71,8 @@ inline constexpr std::string_view make_error_message(errc ec) noexcept { return "server has ran"; case errc::invalid_rpc_result: return "invalid rpc result"; + case errc::serial_number_conflict: + return "serial number conflict"; default: return "unknown user-defined error"; } @@ -103,8 +106,14 @@ inline bool operator!(errc ec) noexcept { return ec == errc::ok; } struct rpc_error { coro_rpc::err_code code; //!< error code std::string msg; //!< error message + rpc_error() {} + rpc_error(coro_rpc::err_code code, std::string_view msg) + : code(code), msg(std::string{msg}) {} + rpc_error(coro_rpc::err_code code) + : code(code), msg(std::string{make_error_message(code)}) {} uint16_t& val() { return *(uint16_t*)&(code.ec); } const uint16_t& val() const { return *(uint16_t*)&(code.ec); } + constexpr operator bool() const noexcept { return code; } }; STRUCT_PACK_REFL(rpc_error, val(), msg); diff --git a/include/ylt/coro_rpc/impl/expected.hpp b/include/ylt/coro_rpc/impl/expected.hpp index 4a0a7e91e..dc786f780 100644 --- a/include/ylt/coro_rpc/impl/expected.hpp +++ b/include/ylt/coro_rpc/impl/expected.hpp @@ -48,8 +48,7 @@ namespace protocol { struct coro_rpc_protocol; } -template -using rpc_result = expected; +template +using rpc_result = expected; } // namespace coro_rpc \ No newline at end of file diff --git a/include/ylt/standalone/cinatra/coro_http_client.hpp b/include/ylt/standalone/cinatra/coro_http_client.hpp index 590c9c7f4..acbb2b742 100644 --- a/include/ylt/standalone/cinatra/coro_http_client.hpp +++ b/include/ylt/standalone/cinatra/coro_http_client.hpp @@ -284,6 +284,12 @@ class coro_http_client : public std::enable_shared_from_this { // only make socket connet(or handshake) to the host async_simple::coro::Lazy connect(std::string uri) { + if (should_reset_) { + reset(); + } + else { + should_reset_ = false; + } resp_data data{}; bool no_schema = !has_schema(uri); std::string append_uri; @@ -896,11 +902,6 @@ class coro_http_client : public std::enable_shared_from_this { resp_chunk_str_.clear(); } - async_simple::coro::Lazy reconnect(std::string uri) { - reset(); - co_return co_await connect(std::move(uri)); - } - std::string_view get_host() { return host_; } std::string_view get_port() { return port_; } @@ -2119,6 +2120,7 @@ class coro_http_client : public std::enable_shared_from_this { std::string redirect_uri_; bool enable_follow_redirect_ = false; bool enable_timeout_ = false; + bool should_reset_ = false; std::chrono::steady_clock::duration conn_timeout_duration_ = std::chrono::seconds(8); std::chrono::steady_clock::duration req_timeout_duration_ = diff --git a/src/coro_io/tests/test_client_pool.cpp b/src/coro_io/tests/test_client_pool.cpp index 3a9eff4ac..18d00ee5d 100644 --- a/src/coro_io/tests/test_client_pool.cpp +++ b/src/coro_io/tests/test_client_pool.cpp @@ -156,9 +156,9 @@ TEST_CASE("test reconnect") { struct mock_client : public coro_rpc::coro_rpc_client { using coro_rpc::coro_rpc_client::coro_rpc_client; - async_simple::coro::Lazy reconnect( + async_simple::coro::Lazy connect( const std::string &hostname) { - auto ec = co_await this->coro_rpc::coro_rpc_client::reconnect(hostname); + auto ec = co_await this->coro_rpc::coro_rpc_client::connect(hostname); if (ec) { co_await coro_io::sleep_for(300ms); } @@ -184,7 +184,7 @@ TEST_CASE("test reconnect retry wait time exclude reconnect cost time") { CHECK(pool->free_client_count() == 100); auto dur = std::chrono::steady_clock::now() - tp; std::cout << dur.count() << std::endl; - CHECK((dur >= 400ms && dur <= 800ms)); + CHECK((dur >= 500ms && dur <= 799ms)); server.stop(); co_return; }()); diff --git a/src/coro_rpc/examples/base_examples/channel.cpp b/src/coro_rpc/examples/base_examples/channel.cpp index 99f23c833..292696c9f 100644 --- a/src/coro_rpc/examples/base_examples/channel.cpp +++ b/src/coro_rpc/examples/base_examples/channel.cpp @@ -25,11 +25,16 @@ #include #include #include +#include #include #include #include #include +#include "ylt/coro_io/io_context_pool.hpp" +#include "ylt/coro_rpc/impl/coro_rpc_client.hpp" +#include "ylt/coro_rpc/impl/errno.h" +#include "ylt/coro_rpc/impl/expected.hpp" #include "ylt/easylog.hpp" using namespace coro_rpc; using namespace async_simple::coro; @@ -39,37 +44,74 @@ std::string echo(std::string_view sv); std::atomic qps = 0; std::atomic working_echo = 0; -/*! - * \example helloworld/concurrency_clients.main.cpp - * \brief demo for run concurrency clients - */ -Lazy call_echo(std::shared_ptr> channel, - int cnt) { - while (true) { - ++working_echo; - for (int i = 0; i < cnt; ++i) { - auto res = co_await channel->send_request( - [](coro_rpc_client &client, std::string_view hostname) -> Lazy { - auto res = co_await client.call("Hello world!"); - if (!res.has_value()) { - ELOG_ERROR << "coro_rpc err: \n" << res.error().msg; - co_return; - } - if (res.value() != "Hello world!"sv) { - ELOG_ERROR << "err echo resp: \n" << res.value(); - co_return; - } - ++qps; - co_return; - }); - if (!res) { - ELOG_ERROR << "client pool err: connect failed.\n"; - } +int request_cnt = 10000; + +// Lazy> +// call_echo(std::shared_ptr> channel) { +// std::vector result; +// result.reserve(request_cnt); +// auto tp = std::chrono::steady_clock::now(); +// ++working_echo; +// for (int i = 0; i < request_cnt; ++i) { +// auto res = co_await channel->send_request( +// [](coro_rpc_client &client, std::string_view hostname) -> Lazy +// { +// auto res = co_await client.call("Hello world!"); +// if (!res.has_value()) { +// ELOG_ERROR << "coro_rpc err: \n" << res.error().msg; +// co_return; +// } +// if (res.value() != "Hello world!"sv) { +// ELOG_ERROR << "err echo resp: \n" << res.value(); +// co_return; +// } +// co_return; +// }); +// if (!res) { +// ELOG_ERROR << "client pool err: connect failed.\n"; +// break; +// } +// ++qps; +// auto old_tp=tp; +// tp= std::chrono::steady_clock::now(); +// result.push_back(std::chrono::duration_cast( +// tp - old_tp)); +// } +// co_return std::move(result); +// } + +Lazy> call_echo( + std::shared_ptr> channel) { + std::vector result; + result.reserve(request_cnt); + auto tp = std::chrono::steady_clock::now(); + ++working_echo; + for (int i = 0; i < request_cnt; ++i) { + auto res = co_await channel->send_request( + [](coro_rpc_client &client, std::string_view hostname) { + return client.send_request("Hello world!"); + }); + if (!res) { + ELOG_ERROR << "client pool err: connect failed.\n" + << std::make_error_code(res.error()); + break; + } + auto rpc_result = co_await res.value(); + if (!rpc_result) { + ELOG_ERROR << "recv response failed\n" << rpc_result.error().msg; + break; } - --working_echo; - co_await coro_io::sleep_for(30s); + if (rpc_result->result() != "Hello world!") { + ELOG_ERROR << "error rpc reponse\n" << rpc_result->result(); + } + ++qps; + auto old_tp = tp; + tp = std::chrono::steady_clock::now(); + result.push_back( + std::chrono::duration_cast(tp - old_tp)); } + co_return std::move(result); } Lazy qps_watcher() { @@ -87,6 +129,19 @@ Lazy qps_watcher() { } } +std::vector result; +void latency_watcher() { + std::sort(result.begin(), result.end()); + auto arr = {0.1, 0.3, 0.5, 0.7, 0.9, 0.95, 0.99, 0.999, 0.9999, 0.99999, 1.0}; + for (auto e : arr) { + std::cout + << (e * 100) << "% request finished in:" + << result[std::max(0, result.size() * e - 1)].count() / + 1000.0 + << "ms" << std::endl; + } +} + int main() { auto hosts = std::vector{"127.0.0.1:8801", "localhost:8801"}; @@ -95,11 +150,17 @@ int main() { hosts, coro_io::channel::channel_config{ .pool_config{.max_connection = worker_cnt}}); auto chan_ptr = std::make_shared(std::move(chan)); + auto executor = coro_io::get_global_block_executor(); for (int i = 0; i < worker_cnt; ++i) { - call_echo(chan_ptr, 10000).start([](auto &&) { + call_echo(chan_ptr).start([=](auto &&res) { + executor->schedule([res = std::move(res.value())]() mutable { + result.insert(result.end(), res.begin(), res.end()); + --working_echo; + }); }); } syncAwait(qps_watcher()); + latency_watcher(); std::cout << "Done!" << std::endl; return 0; } \ No newline at end of file diff --git a/src/coro_rpc/examples/base_examples/client_pool.cpp b/src/coro_rpc/examples/base_examples/client_pool.cpp index 23ba2b628..165f43017 100644 --- a/src/coro_rpc/examples/base_examples/client_pool.cpp +++ b/src/coro_rpc/examples/base_examples/client_pool.cpp @@ -17,9 +17,13 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include @@ -27,77 +31,72 @@ #include "async_simple/coro/Collect.h" #include "async_simple/coro/Lazy.h" +#include "async_simple/coro/Mutex.h" #include "async_simple/coro/SyncAwait.h" #include "ylt/coro_io/io_context_pool.hpp" +#include "ylt/coro_rpc/impl/coro_rpc_client.hpp" +#include "ylt/coro_rpc/impl/errno.h" +#include "ylt/coro_rpc/impl/expected.hpp" #include "ylt/easylog.hpp" +#include "ylt/easylog/record.hpp" std::string echo(std::string_view sv); +constexpr unsigned thread_cnt = 1920; +constexpr auto request_cnt = 1000; using namespace coro_rpc; using namespace async_simple::coro; using namespace std::string_view_literals; -std::atomic qps = 0; - +auto finish_executor = coro_io::get_global_block_executor(); std::atomic working_echo = 0; -std::atomic busy_echo = 0; -struct guard { - guard(std::atomic &ref) : ref(ref) { ++ref; } - ~guard() { --ref; } - std::atomic &ref; -}; /*! * \example helloworld/concurrency_clients.main.cpp * \brief demo for run concurrency clients */ -Lazy> call_echo( - coro_io::client_pool &client_pool, int cnt) { - std::vector result; - result.reserve(cnt); +auto client_pool = + coro_io::client_pool::create("127.0.0.1:8801"); + +std::atomic qps = 0; +Lazy> send() { + std::vector latencys; + latencys.reserve(request_cnt); + auto tp = std::chrono::steady_clock::now(); ++working_echo; - for (int i = 0; i < cnt; ++i) { - auto tp = std::chrono::steady_clock::now(); - auto res = co_await client_pool.send_request( - [=](coro_rpc_client &client) -> Lazy { - guard g{busy_echo}; - if (client.has_closed()) { - co_return; - } - auto res = co_await client.call("Hello world!"); - if (!res.has_value()) { - ELOG_ERROR << "coro_rpc err: \n" << res.error().msg; - client.close(); - co_return; - } - if (res.value() != "Hello world!"sv) { - ELOG_ERROR << "err echo resp: \n" << res.value(); - co_return; - } - ++qps; - co_return; + int id = 0; + for (int i = 0; i < request_cnt; ++i) { + auto result = co_await client_pool->send_request( + [](coro_rpc_client& client) -> Lazy> { + co_return co_await client.call("Hello world!"); }); - if (!res) { - ELOG_ERROR << "client pool err: connect failed.\n"; + if (!result) { + ELOG_ERROR << "get client form client pool failed: \n" + << std::make_error_code(result.error()).message(); + continue; } - else { - result.push_back(std::chrono::duration_cast( - std::chrono::steady_clock::now() - tp)); + auto& call_result = result.value(); + if (!call_result) { + ELOG_ERROR << "call err: \n" << call_result.error().msg; + break; } + qps.fetch_add(1, std::memory_order::release); + auto old_tp = tp; + tp = std::chrono::steady_clock::now(); + latencys.push_back( + std::chrono::duration_cast(tp - old_tp)); } - co_return std::move(result); + co_return std::move(latencys); } -Lazy qps_watcher(coro_io::client_pool &clients) { +Lazy qps_watcher() { using namespace std::chrono_literals; - while (working_echo > 0) { + do { co_await coro_io::sleep_for(1s); uint64_t cnt = qps.exchange(0); std::cout << "QPS:" << cnt - << " free connection: " << clients.free_client_count() - << " working echo:" << working_echo << " busy echo:" << busy_echo - << std::endl; - cnt = 0; - } + << " free connection: " << client_pool->free_client_count() + << " working echo:" << working_echo << std::endl; + } while (working_echo > 0); } std::vector result; void latency_watcher() { @@ -112,23 +111,18 @@ void latency_watcher() { } } int main() { - auto thread_cnt = std::thread::hardware_concurrency(); - auto client_pool = coro_io::client_pool::create( - "localhost:8801", - coro_io::client_pool::pool_config{ - .max_connection = thread_cnt * 20, - .client_config = {.timeout_duration = std::chrono::seconds{50}}}); - - auto finish_executor = coro_io::get_global_block_executor(); - for (int i = 0, lim = thread_cnt * 20; i < lim; ++i) { - call_echo(*client_pool, 10000).start([finish_executor](auto &&res) { - finish_executor->schedule([res = std::move(res.value())] { - result.insert(result.end(), res.begin(), res.end()); - --working_echo; + auto executor = coro_io::get_global_block_executor(); + for (int i = 0, lim = thread_cnt * 10; i < lim; ++i) { + coro_io::get_global_executor()->schedule([=]() { + send().start([executor](auto&& res) { + executor->schedule([res = std::move(res.value())]() mutable { + result.insert(result.end(), res.begin(), res.end()); + --working_echo; + }); }); }); } - syncAwait(qps_watcher(*client_pool)); + syncAwait(qps_watcher()); latency_watcher(); std::cout << "Done!" << std::endl; return 0; diff --git a/src/coro_rpc/examples/base_examples/client_pools.cpp b/src/coro_rpc/examples/base_examples/client_pools.cpp index 8bf414d60..dbbe114c7 100644 --- a/src/coro_rpc/examples/base_examples/client_pools.cpp +++ b/src/coro_rpc/examples/base_examples/client_pools.cpp @@ -26,6 +26,8 @@ #include #include #include + +#include "ylt/coro_io/io_context_pool.hpp" std::string echo(std::string_view sv); using namespace coro_rpc; using namespace async_simple::coro; @@ -39,10 +41,15 @@ std::atomic working_echo = 0; * \brief demo for run concurrency clients */ -Lazy call_echo(coro_io::client_pools &client_pools, - int cnt) { +int request_cnt = 10000; + +Lazy> call_echo( + coro_io::client_pools &client_pools) { ++working_echo; - for (int i = 0; i < cnt; ++i) { + std::vector result; + result.reserve(request_cnt); + auto tp = std::chrono::steady_clock::now(); + for (int i = 0; i < request_cnt; ++i) { auto res = co_await client_pools.send_request( i % 2 ? "localhost:8801" : "127.0.0.1:8801", [=](coro_rpc_client &client) -> Lazy { @@ -60,9 +67,14 @@ Lazy call_echo(coro_io::client_pools &client_pools, }); if (!res) { ELOG_ERROR << "client pool err: connect failed.\n"; + break; } + auto old_tp = tp; + tp = std::chrono::steady_clock::now(); + result.push_back( + std::chrono::duration_cast(tp - old_tp)); } - --working_echo; + co_return std::move(result); } Lazy qps_watcher(coro_io::client_pools &clients) { @@ -78,15 +90,32 @@ Lazy qps_watcher(coro_io::client_pools &clients) { cnt = 0; } } - +std::vector result; +void latency_watcher() { + std::sort(result.begin(), result.end()); + auto arr = {0.1, 0.3, 0.5, 0.7, 0.9, 0.95, 0.99, 0.999, 0.9999, 0.99999, 1.0}; + for (auto e : arr) { + std::cout + << (e * 100) << "% request finished in:" + << result[std::max(0, result.size() * e - 1)].count() / + 1000.0 + << "ms" << std::endl; + } +} int main() { auto thread_cnt = std::thread::hardware_concurrency(); auto &clients = coro_io::g_clients_pool(); + auto executor = coro_io::get_global_block_executor(); for (int i = 0, lim = thread_cnt * 20; i < lim; ++i) { - call_echo(clients, 10000).start([](auto &&) { + call_echo(clients).start([=](auto &&res) { + executor->schedule([res = std::move(res.value())]() mutable { + result.insert(result.end(), res.begin(), res.end()); + --working_echo; + }); }); } syncAwait(qps_watcher(clients)); + latency_watcher(); std::cout << "Done!" << std::endl; return 0; } \ No newline at end of file diff --git a/src/coro_rpc/examples/base_examples/concurrent_clients.cpp b/src/coro_rpc/examples/base_examples/concurrent_clients.cpp index c8e8e7a20..bf087a659 100644 --- a/src/coro_rpc/examples/base_examples/concurrent_clients.cpp +++ b/src/coro_rpc/examples/base_examples/concurrent_clients.cpp @@ -13,80 +13,114 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include -#include -#include #include #include #include +#include #include -#include +#include +#include +#include +#include #include #include #include #include +#include "async_simple/coro/Collect.h" +#include "async_simple/coro/Lazy.h" +#include "async_simple/coro/Mutex.h" +#include "async_simple/coro/SyncAwait.h" +#include "ylt/coro_io/io_context_pool.hpp" #include "ylt/coro_rpc/impl/coro_rpc_client.hpp" +#include "ylt/coro_rpc/impl/errno.h" +#include "ylt/coro_rpc/impl/expected.hpp" +#include "ylt/easylog.hpp" std::string echo(std::string_view sv); + +constexpr auto thread_cnt = 96 * 20; using namespace coro_rpc; using namespace async_simple::coro; using namespace std::string_view_literals; -using namespace std::chrono_literals; -std::atomic qps = 0; +auto finish_executor = coro_io::get_global_block_executor(); std::atomic working_echo = 0; -/*! - * \example helloworld/concurrency_clients.main.cpp - * \brief demo for run concurrency clients - */ -Lazy call_echo(int cnt) { +std::vector> clients; + +std::atomic& get_qps(int id) { + static std::atomic ar[thread_cnt * 8]; + return ar[id * 8]; +} + +Lazy> send(int id, int cnt) { + std::vector result; + auto& cli = *clients[id]; + auto& qps = get_qps(id); + result.reserve(cnt); ++working_echo; - coro_rpc_client client; - auto ec = co_await client.connect("localhost:8801"); - for (int i = 0; i < 3 && !ec; ++i) { - co_await coro_io::sleep_for(rand() % 10000 * 1ms); - ec = co_await client.reconnect("localhost:8801"); - } - if (!ec) { - for (int i = 0; i < cnt; ++i) { - auto res = co_await client.call("Hello world!"); - if (!res.has_value()) { - ELOG_ERROR << "coro_rpc err: \n" << res.error().msg; - co_return; - } - if (res.value() != "Hello world!"sv) { - ELOG_ERROR << "err echo resp: \n" << res.value(); - co_return; - } - ++qps; + auto tp = std::chrono::steady_clock::now(); + for (int i = 0; i < cnt; ++i) { + auto res_ = co_await cli.call("Hello world!"); + if (!res_.has_value()) { + ELOG_ERROR << "coro_rpc err: \n" << res_.error().msg; + continue; } - } - else { - std::cout << "connect failed \n"; + ++qps; + auto old_tp = tp; + tp = std::chrono::steady_clock::now(); + result.push_back( + std::chrono::duration_cast(tp - old_tp)); } --working_echo; + co_return std::move(result); } Lazy qps_watcher() { using namespace std::chrono_literals; - while (working_echo > 0) { + do { co_await coro_io::sleep_for(1s); - uint64_t cnt = qps.exchange(0); - std::cout << "QPS:" << cnt << " working echo:" << working_echo << std::endl; + uint64_t cnt = 0; + for (int i = 0; i < thread_cnt; ++i) { + auto& qps = get_qps(i); + uint64_t tmp = qps.exchange(0); + cnt += tmp; + } + std::cout << "QPS:" + << cnt + // << " free connection: " << clients.free_client_count() + << " working echo:" << working_echo << std::endl; cnt = 0; + } while (working_echo > 0); +} +std::vector result; +void latency_watcher() { + std::sort(result.begin(), result.end()); + auto arr = {0.1, 0.3, 0.5, 0.7, 0.9, 0.95, 0.99, 0.999, 0.9999, 0.99999, 1.0}; + for (auto e : arr) { + std::cout + << (e * 100) << "% request finished in:" + << result[std::max(0, result.size() * e - 1)].count() / + 1000.0 + << "ms" << std::endl; } } - int main() { - auto thread_cnt = std::thread::hardware_concurrency(); - for (int i = 0, lim = thread_cnt * 20; i < lim; ++i) { - call_echo(100000).start([](auto &&) { + for (int i = 0; i < thread_cnt; ++i) { + clients.emplace_back(std::make_unique( + coro_io::get_global_executor()->get_asio_executor())); + syncAwait(clients.back()->connect("localhost:8801")); + } + for (int i = 0, lim = thread_cnt; i < lim; ++i) { + send(i, 20000).via(&clients[i]->get_executor()).start([](auto&& res) { + finish_executor->schedule([res = std::move(res.value())] { + result.insert(result.end(), res.begin(), res.end()); + }); }); } syncAwait(qps_watcher()); + latency_watcher(); std::cout << "Done!" << std::endl; return 0; } \ No newline at end of file diff --git a/src/coro_rpc/examples/base_examples/rpc_service.cpp b/src/coro_rpc/examples/base_examples/rpc_service.cpp index 27f04db59..da6eb6db3 100644 --- a/src/coro_rpc/examples/base_examples/rpc_service.cpp +++ b/src/coro_rpc/examples/base_examples/rpc_service.cpp @@ -102,9 +102,11 @@ Lazy nested_echo(std::string_view sv) { coro_io::g_clients_pool().at("127.0.0.1:8802"); assert(client != nullptr); ELOGV(INFO, "connect another server"); - auto ret = co_await client->send_request([sv](coro_rpc_client &client) { - return client.call(sv); - }); + auto ret = co_await client->send_request( + [sv](coro_rpc_client &client) + -> Lazy> { + co_return co_await client.call(sv); + }); co_return ret.value().value(); } diff --git a/src/coro_rpc/tests/test_coro_rpc_client.cpp b/src/coro_rpc/tests/test_coro_rpc_client.cpp index 71b69eab4..cd5314001 100644 --- a/src/coro_rpc/tests/test_coro_rpc_client.cpp +++ b/src/coro_rpc/tests/test_coro_rpc_client.cpp @@ -56,6 +56,8 @@ Lazy> create_client( co_return client; } +void show(auto& s) { return; } + TEST_CASE("testing client") { { coro_rpc::coro_rpc_client client; @@ -146,6 +148,7 @@ TEST_CASE("testing client") { std::string arg; arg.resize(2048); auto ret = co_await client->template call(arg); + show(ret); CHECK(ret.value() == arg); co_return; }; @@ -205,6 +208,7 @@ TEST_CASE("testing client with inject server") { auto client = co_await create_client(io_context, port); g_action = inject_action::close_socket_after_send_length; auto ret = co_await client->template call(); + show(ret); REQUIRE_MESSAGE(ret.error().code == coro_rpc::errc::io_error, ret.error().msg); }; diff --git a/src/coro_rpc/tests/test_coro_rpc_server.cpp b/src/coro_rpc/tests/test_coro_rpc_server.cpp index 6cf512043..23f522204 100644 --- a/src/coro_rpc/tests/test_coro_rpc_server.cpp +++ b/src/coro_rpc/tests/test_coro_rpc_server.cpp @@ -346,13 +346,6 @@ TEST_CASE("test server accept error") { REQUIRE_MESSAGE(ret.error().code == coro_rpc::errc::io_error, ret.error().msg); REQUIRE(client.has_closed() == true); - - ec = syncAwait(client.connect("127.0.0.1", "8810")); - REQUIRE_MESSAGE(ec == coro_rpc::errc::io_error, - std::to_string(client.get_client_id()).append(ec.message())); - ret = syncAwait(client.call()); - CHECK(!ret); - REQUIRE(client.has_closed() == true); g_action = {}; } diff --git a/src/coro_rpc/tests/test_router.cpp b/src/coro_rpc/tests/test_router.cpp index 9c7aaac0d..c344bfe51 100644 --- a/src/coro_rpc/tests/test_router.cpp +++ b/src/coro_rpc/tests/test_router.cpp @@ -67,12 +67,11 @@ struct RPC_trait { }; using coro_rpc_protocol = coro_rpc::protocol::coro_rpc_protocol; template -rpc_result, coro_rpc_protocol> -get_result(const auto &pair) { +rpc_result> get_result( + const auto &pair) { auto &&[rpc_errc, buffer] = pair; using T = util::function_return_type_t; - using return_type = rpc_result, - coro_rpc_protocol>; + using return_type = rpc_result>; rpc_return_type_t ret; struct_pack::err_code ec; rpc_error err; From f786c5a8b97cf1f180d946eaf8e45e600ae1ee95 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 21 May 2024 17:20:30 +0800 Subject: [PATCH 03/12] fix and update (#679) --- .../standalone/cinatra/coro_http_client.hpp | 80 +------------------ .../cinatra/coro_http_connection.hpp | 16 +++- .../standalone/cinatra/coro_http_request.hpp | 10 ++- include/ylt/standalone/cinatra/multipart.hpp | 7 +- .../zh/coro_http/coro_http_introduction.md | 10 +-- 5 files changed, 36 insertions(+), 87 deletions(-) diff --git a/include/ylt/standalone/cinatra/coro_http_client.hpp b/include/ylt/standalone/cinatra/coro_http_client.hpp index acbb2b742..ce76a3572 100644 --- a/include/ylt/standalone/cinatra/coro_http_client.hpp +++ b/include/ylt/standalone/cinatra/coro_http_client.hpp @@ -288,7 +288,7 @@ class coro_http_client : public std::enable_shared_from_this { reset(); } else { - should_reset_ = false; + should_reset_ = true; } resp_data data{}; bool no_schema = !has_schema(uri); @@ -515,7 +515,6 @@ class coro_http_client : public std::enable_shared_from_this { #ifdef BENCHMARK_TEST void set_bench_stop() { stop_bench_ = true; } - void set_read_fix() { read_fix_ = 1; } #endif async_simple::coro::Lazy async_patch( @@ -558,73 +557,6 @@ class coro_http_client : public std::enable_shared_from_this { std::string uri, std::unordered_map headers = {}) { resp_data data{}; -#ifdef BENCHMARK_TEST - if (!req_str_.empty()) { - if (has_closed()) { - data.net_err = std::make_error_code(std::errc::not_connected); - data.status = 404; - co_return data; - } - - std::error_code ec{}; - size_t size = 0; - if (std::tie(ec, size) = co_await async_write(asio::buffer(req_str_)); - ec) { - data.net_err = ec; - data.status = 404; - close_socket(*socket_); - co_return data; - } - - if (read_fix_ == 0) { - req_context<> ctx{}; - bool is_keep_alive = true; - data = co_await handle_read(ec, size, is_keep_alive, std::move(ctx), - http_method::GET); - handle_result(data, ec, is_keep_alive); - if (ec) { - if (!stop_bench_) - CINATRA_LOG_ERROR << "do_bench_read error:" << ec.message(); - data.net_err = ec; - data.status = 404; - } - else { - data.status = 200; - data.total = total_len_; - } - - co_return data; - } - - std::tie(ec, size) = co_await async_read(head_buf_, total_len_); - - if (ec) { - if (!stop_bench_) - CINATRA_LOG_ERROR << "do_bench_read error:" << ec.message(); - data.net_err = ec; - data.status = 404; - close_socket(*socket_); - co_return data; - } - else { - const char *data_ptr = - asio::buffer_cast(head_buf_.data()); - head_buf_.consume(total_len_); - // check status - if (data_ptr[9] > '3') { - data.status = 404; - co_return data; - } - } - - head_buf_.consume(total_len_); - data.status = 200; - data.total = total_len_; - - co_return data; - } -#endif - req_context<> ctx{}; data = co_await async_request(std::move(uri), http_method::GET, std::move(ctx), std::move(headers)); @@ -892,7 +824,6 @@ class coro_http_client : public std::enable_shared_from_this { } #endif #ifdef BENCHMARK_TEST - req_str_.clear(); total_len_ = 0; #endif @@ -1160,9 +1091,6 @@ class coro_http_client : public std::enable_shared_from_this { vec.push_back(asio::buffer(ctx.content.data(), ctx.content.size())); } -#ifdef BENCHMARK_TEST - req_str_ = req_head_str; -#endif #ifdef CORO_HTTP_PRINT_REQ_HEAD CINATRA_LOG_DEBUG << req_head_str; #endif @@ -1640,7 +1568,7 @@ class coro_http_client : public std::enable_shared_from_this { std::string boundary = std::string{parser_.get_boundary()}; multipart_reader_t multipart(this); while (true) { - auto part_head = co_await multipart.read_part_head(); + auto part_head = co_await multipart.read_part_head(boundary); if (part_head.ec) { co_return part_head.ec; } @@ -2120,7 +2048,6 @@ class coro_http_client : public std::enable_shared_from_this { std::string redirect_uri_; bool enable_follow_redirect_ = false; bool enable_timeout_ = false; - bool should_reset_ = false; std::chrono::steady_clock::duration conn_timeout_duration_ = std::chrono::seconds(8); std::chrono::steady_clock::duration req_timeout_duration_ = @@ -2128,6 +2055,7 @@ class coro_http_client : public std::enable_shared_from_this { bool enable_tcp_no_delay_ = true; std::string resp_chunk_str_; std::span out_buf_; + bool should_reset_ = false; #ifdef CINATRA_ENABLE_GZIP bool enable_ws_deflate_ = false; @@ -2136,10 +2064,8 @@ class coro_http_client : public std::enable_shared_from_this { #endif #ifdef BENCHMARK_TEST - std::string req_str_; bool stop_bench_ = false; size_t total_len_ = 0; - int read_fix_ = 0; #endif }; } // namespace cinatra diff --git a/include/ylt/standalone/cinatra/coro_http_connection.hpp b/include/ylt/standalone/cinatra/coro_http_connection.hpp index 3fdd794ac..356fc4562 100644 --- a/include/ylt/standalone/cinatra/coro_http_connection.hpp +++ b/include/ylt/standalone/cinatra/coro_http_connection.hpp @@ -288,8 +288,19 @@ class coro_http_connection if (!response_.get_delay()) { if (head_buf_.size()) { - // handle pipeling, only support GET and HEAD method now. - if (parser_.method()[0] != 'G' && parser_.method()[0] != 'H') { + if (type == content_type::multipart) { + response_.set_status_and_content( + status_type::not_implemented, + "mutipart handler not implemented or incorrect implemented"); + co_await reply(); + close(); + CINATRA_LOG_ERROR + << "mutipart handler not implemented or incorrect implemented" + << ec.message(); + break; + } + else if (parser_.method()[0] != 'G' && parser_.method()[0] != 'H') { + // handle pipeling, only support GET and HEAD method now. response_.set_status_and_content(status_type::method_not_allowed, "method not allowed"); co_await reply(); @@ -343,6 +354,7 @@ class coro_http_connection co_return; } } + head_buf_.consume(head_buf_.size()); } else { handle_session_for_response(); diff --git a/include/ylt/standalone/cinatra/coro_http_request.hpp b/include/ylt/standalone/cinatra/coro_http_request.hpp index ea6574fd8..a41df18e3 100644 --- a/include/ylt/standalone/cinatra/coro_http_request.hpp +++ b/include/ylt/standalone/cinatra/coro_http_request.hpp @@ -184,7 +184,13 @@ class coro_http_request { if (content_type.empty()) { return {}; } - return content_type.substr(content_type.rfind("=") + 1); + + auto pos = content_type.rfind("="); + if (pos == std::string_view::npos) { + return ""; + } + + return content_type.substr(pos + 1); } coro_http_connection *get_conn() { return conn_; } @@ -278,7 +284,7 @@ class coro_http_request { http_parser &parser_; std::string_view body_; coro_http_connection *conn_; - bool is_websocket_; + bool is_websocket_ = false; std::vector aspect_data_; std::string cached_session_id_; }; diff --git a/include/ylt/standalone/cinatra/multipart.hpp b/include/ylt/standalone/cinatra/multipart.hpp index d40aaa711..b85b5001f 100644 --- a/include/ylt/standalone/cinatra/multipart.hpp +++ b/include/ylt/standalone/cinatra/multipart.hpp @@ -11,7 +11,12 @@ class multipart_reader_t { head_buf_(conn_->head_buf_), chunked_buf_(conn_->chunked_buf_) {} - async_simple::coro::Lazy read_part_head() { + async_simple::coro::Lazy read_part_head( + std::string_view boundary) { + if (boundary.empty()) { + co_return part_head_t{std::make_error_code(std::errc::protocol_error)}; + } + if (head_buf_.size() > 0) { const char *data_ptr = asio::buffer_cast(head_buf_.data()); chunked_buf_.sputn(data_ptr, head_buf_.size()); diff --git a/website/docs/zh/coro_http/coro_http_introduction.md b/website/docs/zh/coro_http/coro_http_introduction.md index d1e3ec7ce..20075a982 100644 --- a/website/docs/zh/coro_http/coro_http_introduction.md +++ b/website/docs/zh/coro_http/coro_http_introduction.md @@ -739,9 +739,9 @@ int main() { 见[example中的例子](example/main.cpp) ### 示例5:RESTful服务端路径参数设置 -本代码演示如何使用RESTful路径参数。下面设置了两个RESTful API。第一个API当访问,比如访问这样的url`http://127.0.0.1:8080/numbers/1234/test/5678`时服务器可以获取到1234和5678这两个参数,第一个RESTful API的参数是`(\d+)`是一个正则表达式表明只能参数只能为数字。获取第一个参数的代码是`req.get_matches()[1]`。因为每一个req不同所以每一个匹配到的参数都放在`request`结构体中。 +本代码演示如何使用RESTful路径参数。下面设置了两个RESTful API。第一个API当访问,比如访问这样的url`http://127.0.0.1:8080/numbers/1234/test/5678`时服务器可以获取到1234和5678这两个参数,第一个RESTful API的参数是`(\d+)`是一个正则表达式表明只能参数只能为数字。获取第一个参数的代码是`req.matches_[1]`。因为每一个req不同所以每一个匹配到的参数都放在`request`结构体中。 -同时还支持任意字符的RESTful API,即示例的第二种RESTful API`"/string/{:id}/test/{:name}"`,要获取到对应的参数使用`req.get_query_value`函数即可,其参数只能为注册的变量(如果不为依然运行但是有报错),例子中参数名是id和name,要获取id参数调用`req.get_query_value("id")`即可。示例代码运行后,当访问`http://127.0.0.1:8080/string/params_1/test/api_test`时,浏览器会返回`api_test`字符串。 +同时还支持任意字符的RESTful API,即示例的第二种RESTful API`"/string/:id/test/:name"`,要获取到对应的参数使用`req.get_query_value`函数即可,其参数只能为注册的变量(如果不为依然运行但是有报错),例子中参数名是id和name,要获取id参数调用`req.get_query_value("id")`即可。示例代码运行后,当访问`http://127.0.0.1:8080/string/params_1/test/api_test`时,浏览器会返回`api_test`字符串。 ```c++ #include "ylt/coro_http/coro_http_client.hpp" @@ -754,14 +754,14 @@ int main() { server.set_http_handler( R"(/numbers/(\d+)/test/(\d+))", [](request &req, response &res) { - std::cout << " matches[1] is : " << req.get_matches()[1] - << " matches[2] is: " << req.get_matches()[2] << std::endl; + std::cout << " matches[1] is : " << req.matches_[1] + << " matches[2] is: " << req.matches_[2] << std::endl; res.set_status_and_content(status_type::ok, "hello world"); }); server.set_http_handler( - "/string/{:id}/test/{:name}", [](request &req, response &res) { + "/string/:id/test/:name", [](request &req, response &res) { std::string id = req.get_query_value("id"); std::cout << "id value is: " << id << std::endl; std::cout << "name value is: " << std::string(req.get_query_value("name")) << std::endl; From 5f3bd02292e83bd0f734d664db50b53163ab298e Mon Sep 17 00:00:00 2001 From: saipubw Date: Fri, 24 May 2024 10:58:27 +0800 Subject: [PATCH 04/12] [doc] add coro_rpc doc (#681) * add coro_rpc doc * fix doc * update en doc * fix code --- include/ylt/coro_rpc/impl/context.hpp | 6 +- include/ylt/coro_rpc/impl/coro_rpc_client.hpp | 19 +- include/ylt/coro_rpc/impl/coro_rpc_server.hpp | 65 ++- .../impl/default_config/coro_rpc_config.hpp | 15 +- src/coro_io/tests/test_channel.cpp | 12 +- src/coro_io/tests/test_client_pool.cpp | 10 +- src/coro_rpc/benchmark/data_gen.cpp | 4 +- .../examples/base_examples/rpc_service.cpp | 2 +- .../examples/base_examples/server.cpp | 2 +- .../examples/file_transfer/rpc_service.cpp | 4 +- src/coro_rpc/tests/rpc_api.cpp | 8 +- src/coro_rpc/tests/test_coro_rpc_client.cpp | 24 +- src/coro_rpc/tests/test_coro_rpc_server.cpp | 18 +- src/coro_rpc/tests/test_variadic.cpp | 2 +- website/Doxyfile | 2 + website/Doxyfile_cn | 4 +- website/docs/en/coro_rpc/coro_rpc_client.md | 261 +++++++++++ .../docs/en/coro_rpc/coro_rpc_introduction.md | 75 +-- website/docs/en/coro_rpc/coro_rpc_server.md | 433 ++++++++++++++++++ website/docs/zh/coro_rpc/coro_rpc_client.md | 265 +++++++++++ .../docs/zh/coro_rpc/coro_rpc_introduction.md | 172 +------ website/docs/zh/coro_rpc/coro_rpc_server.md | 431 +++++++++++++++++ 22 files changed, 1525 insertions(+), 309 deletions(-) create mode 100644 website/docs/en/coro_rpc/coro_rpc_client.md create mode 100644 website/docs/en/coro_rpc/coro_rpc_server.md create mode 100644 website/docs/zh/coro_rpc/coro_rpc_client.md create mode 100644 website/docs/zh/coro_rpc/coro_rpc_server.md diff --git a/include/ylt/coro_rpc/impl/context.hpp b/include/ylt/coro_rpc/impl/context.hpp index 84fde1aa2..46f806903 100644 --- a/include/ylt/coro_rpc/impl/context.hpp +++ b/include/ylt/coro_rpc/impl/context.hpp @@ -130,10 +130,12 @@ class context_base { /*finish here*/ self_->status_ = context_status::finish_response; } - const context_info_t *get_context() const noexcept { + const context_info_t *get_context_info() const noexcept { + return self_.get(); + } + context_info_t *get_context_info() noexcept { return self_.get(); } - context_info_t *get_context() noexcept { return self_.get(); } }; template diff --git a/include/ylt/coro_rpc/impl/coro_rpc_client.hpp b/include/ylt/coro_rpc/impl/coro_rpc_client.hpp index 53f5da8cf..cc2fa890d 100644 --- a/include/ylt/coro_rpc/impl/coro_rpc_client.hpp +++ b/include/ylt/coro_rpc/impl/coro_rpc_client.hpp @@ -73,6 +73,11 @@ class client_pool; namespace coro_rpc { +inline uint64_t get_global_client_id() { + static std::atomic cid = 0; + return cid.fetch_add(1, std::memory_order::relaxed); +} + #ifdef GENERATE_BENCHMARK_DATA std::string benchmark_file_path = "./"; #endif @@ -105,7 +110,7 @@ struct async_rpc_result_value_t { async_rpc_result_value_t(T &&result) : result_(std::move(result)) {} T &result() noexcept { return result_; } const T &result() const noexcept { return result_; } - std::string_view attachment() const noexcept { + std::string_view get_attachment() const noexcept { return buffer_.resp_attachment_buf_; } resp_body release_buffer() { return std::move(buffer_); } @@ -155,12 +160,12 @@ class coro_rpc_client { const inline static rpc_error connect_error = {errc::io_error, "client has been closed"}; struct config { - uint32_t client_id = 0; + uint64_t client_id = get_global_client_id(); std::chrono::milliseconds timeout_duration = std::chrono::milliseconds{5000}; std::string host; std::string port; - bool enable_tcp_no_delay_ = true; + bool enable_tcp_no_delay = true; #ifdef YLT_ENABLE_SSL std::filesystem::path ssl_cert_path; std::string ssl_domain; @@ -172,7 +177,7 @@ class coro_rpc_client { * @param io_context asio io_context, async event handler */ coro_rpc_client(asio::io_context::executor_type executor, - uint32_t client_id = 0) + uint64_t client_id = get_global_client_id()) : control_(std::make_shared(executor, false)), timer_(std::make_unique(executor)) { config_.client_id = client_id; @@ -184,7 +189,7 @@ class coro_rpc_client { */ coro_rpc_client( coro_io::ExecutorWrapper<> *executor = coro_io::get_global_executor(), - uint32_t client_id = 0) + uint64_t client_id = get_global_client_id()) : control_( std::make_shared(executor->get_asio_executor(), false)), timer_(std::make_unique( @@ -424,7 +429,7 @@ class coro_rpc_client { ELOGV(WARN, "client_id %d connect timeout", config_.client_id); co_return errc::timed_out; } - if (config_.enable_tcp_no_delay_ == true) { + if (config_.enable_tcp_no_delay == true) { control_->socket_.set_option(asio::ip::tcp::no_delay(true), ec); } @@ -738,7 +743,7 @@ class coro_rpc_client { call(std::forward(args)...)); } #endif - + private: template async_simple::coro::Lazy send_request_for_impl( auto duration, uint32_t &id, coro_io::period_timer &timer, diff --git a/include/ylt/coro_rpc/impl/coro_rpc_server.hpp b/include/ylt/coro_rpc/impl/coro_rpc_server.hpp index b74bb7a8c..3b59f6957 100644 --- a/include/ylt/coro_rpc/impl/coro_rpc_server.hpp +++ b/include/ylt/coro_rpc/impl/coro_rpc_server.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -68,29 +69,36 @@ class coro_rpc_server_base { * TODO: add doc * @param thread_num the number of io_context. * @param port the server port to listen. + * @param listen address of server * @param conn_timeout_duration client connection timeout. 0 for no timeout. * default no timeout. + * @param is_enable_tcp_no_delay is tcp socket allow */ - coro_rpc_server_base(size_t thread_num, unsigned short port, + coro_rpc_server_base(size_t thread_num = std::thread::hardware_concurrency(), + unsigned short port = 9001, std::string address = "0.0.0.0", std::chrono::steady_clock::duration - conn_timeout_duration = std::chrono::seconds(0)) + conn_timeout_duration = std::chrono::seconds(0), + bool is_enable_tcp_no_delay = true) : pool_(thread_num), acceptor_(pool_.get_executor()->get_asio_executor()), port_(port), conn_timeout_duration_(conn_timeout_duration), - flag_{stat::init} { + flag_{stat::init}, + is_enable_tcp_no_delay_(is_enable_tcp_no_delay) { init_address(std::move(address)); } - coro_rpc_server_base(size_t thread_num, - std::string address /* = "0.0.0.0:9001" */, + coro_rpc_server_base(size_t thread_num = std::thread::hardware_concurrency(), + std::string address = "0.0.0.0:9001", std::chrono::steady_clock::duration - conn_timeout_duration = std::chrono::seconds(0)) + conn_timeout_duration = std::chrono::seconds(0), + bool is_enable_tcp_no_delay = true) : pool_(thread_num), acceptor_(pool_.get_executor()->get_asio_executor()), conn_timeout_duration_(conn_timeout_duration), - flag_{stat::init} { + flag_{stat::init}, + is_enable_tcp_no_delay_(is_enable_tcp_no_delay) { init_address(std::move(address)); } @@ -99,7 +107,13 @@ class coro_rpc_server_base { acceptor_(pool_.get_executor()->get_asio_executor()), port_(config.port), conn_timeout_duration_(config.conn_timeout_duration), - flag_{stat::init} { + flag_{stat::init}, + is_enable_tcp_no_delay_(config.is_enable_tcp_no_delay) { +#ifdef YLT_ENABLE_SSL + if (config.ssl_config) { + init_ssl_context_helper(context_, config.ssl_config.value()); + } +#endif init_address(config.address); } @@ -109,7 +123,7 @@ class coro_rpc_server_base { } #ifdef YLT_ENABLE_SSL - void init_ssl_context(const ssl_configure &conf) { + void init_ssl(const ssl_configure &conf) { use_ssl_ = init_ssl_context_helper(context_, conf); } #endif @@ -122,19 +136,19 @@ class coro_rpc_server_base { * @return error code if start failed, otherwise block until server stop. */ [[nodiscard]] coro_rpc::err_code start() noexcept { - auto ret = async_start(); - if (ret) { - ret.value().wait(); - return ret.value().value(); - } - else { - return ret.error(); - } + return async_start().get(); } - [[nodiscard]] coro_rpc::expected, - coro_rpc::err_code> - async_start() noexcept { + private: + async_simple::Future make_error_future( + coro_rpc::err_code &&err) { + async_simple::Promise p; + p.setValue(std::move(err)); + return p.getFuture(); + } + + public: + async_simple::Future async_start() noexcept { { std::unique_lock lock(start_mtx_); if (flag_ != stat::init) { @@ -144,8 +158,8 @@ class coro_rpc_server_base { else if (flag_ == stat::stop) { ELOGV(INFO, "has stoped"); } - return coro_rpc::unexpected{ - coro_rpc::errc::server_has_ran}; + return make_error_future( + coro_rpc::err_code{coro_rpc::errc::server_has_ran}); } errc_ = listen(); if (!errc_) { @@ -177,7 +191,7 @@ class coro_rpc_server_base { return std::move(future); } else { - return coro_rpc::unexpected{errc_}; + return make_error_future(coro_rpc::err_code{errc_}); } } @@ -387,7 +401,9 @@ class coro_rpc_server_base { int64_t conn_id = ++conn_id_; ELOGV(INFO, "new client conn_id %d coming", conn_id); - socket.set_option(asio::ip::tcp::no_delay(true), error); + if (is_enable_tcp_no_delay_) { + socket.set_option(asio::ip::tcp::no_delay(true), error); + } auto conn = std::make_shared(executor, std::move(socket), conn_timeout_duration_); conn->set_quit_callback( @@ -459,6 +475,7 @@ class coro_rpc_server_base { std::atomic port_; std::string address_; + bool is_enable_tcp_no_delay_; coro_rpc::err_code errc_ = {}; std::chrono::steady_clock::duration conn_timeout_duration_; diff --git a/include/ylt/coro_rpc/impl/default_config/coro_rpc_config.hpp b/include/ylt/coro_rpc/impl/default_config/coro_rpc_config.hpp index cc9185eee..f65895885 100644 --- a/include/ylt/coro_rpc/impl/default_config/coro_rpc_config.hpp +++ b/include/ylt/coro_rpc/impl/default_config/coro_rpc_config.hpp @@ -25,19 +25,22 @@ namespace coro_rpc { -namespace config { -struct coro_rpc_config_base { - uint16_t port = 8801; +struct config_base { + bool is_enable_tcp_no_delay = true; + uint16_t port = 9001; unsigned thread_num = std::thread::hardware_concurrency(); std::chrono::steady_clock::duration conn_timeout_duration = std::chrono::seconds{0}; + std::string address = "0.0.0.0"; +#ifdef YLT_ENABLE_SSL + std::optional ssl_config = std::nullopt; +#endif }; -struct coro_rpc_default_config : public coro_rpc_config_base { +struct config_t : public config_base { using rpc_protocol = coro_rpc::protocol::coro_rpc_protocol; using executor_pool_t = coro_io::io_context_pool; }; -} // namespace config -using coro_rpc_server = coro_rpc_server_base; +using coro_rpc_server = coro_rpc_server_base; } // namespace coro_rpc diff --git a/src/coro_io/tests/test_channel.cpp b/src/coro_io/tests/test_channel.cpp index 3f78e9434..eb688fcac 100644 --- a/src/coro_io/tests/test_channel.cpp +++ b/src/coro_io/tests/test_channel.cpp @@ -23,7 +23,7 @@ TEST_CASE("test RR") { async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { coro_rpc::coro_rpc_server server(1, 8801); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); auto hosts = std::vector{"127.0.0.1:8801", "localhost:8801"}; auto channel = coro_io::channel::create(hosts); @@ -62,10 +62,10 @@ TEST_CASE("test WRR") { coro_rpc::coro_rpc_server server1(1, 8801); auto res = server1.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); coro_rpc::coro_rpc_server server2(1, 8802); auto res2 = server2.async_start(); - REQUIRE_MESSAGE(res2, "server start failed"); + REQUIRE_MESSAGE(!res2.hasResult(), "server start failed"); async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { auto hosts = @@ -119,7 +119,7 @@ TEST_CASE("test Random") { async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { coro_rpc::coro_rpc_server server(1, 8801); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); auto hosts = std::vector{"127.0.0.1:8801", "localhost:8801"}; auto channel = coro_io::channel::create( @@ -148,7 +148,7 @@ TEST_CASE("test single host") { async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { coro_rpc::coro_rpc_server server(1, 8801); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); auto hosts = std::vector{"127.0.0.1:8801"}; auto channel = coro_io::channel::create(hosts); for (int i = 0; i < 100; ++i) { @@ -168,7 +168,7 @@ TEST_CASE("test send_request config") { async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { coro_rpc::coro_rpc_server server(1, 9813); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); auto hosts = std::vector{"127.0.0.1:9813"}; auto channel = coro_io::channel::create(hosts); for (int i = 0; i < 100; ++i) { diff --git a/src/coro_io/tests/test_client_pool.cpp b/src/coro_io/tests/test_client_pool.cpp index 18d00ee5d..a2878a5da 100644 --- a/src/coro_io/tests/test_client_pool.cpp +++ b/src/coro_io/tests/test_client_pool.cpp @@ -87,7 +87,7 @@ TEST_CASE("test client pool") { async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { coro_rpc::coro_rpc_server server(1, 8801); auto is_started = server.async_start(); - REQUIRE(is_started); + REQUIRE(is_started.hasResult() == false); auto pool = coro_io::client_pool::create( "127.0.0.1:8801", {.max_connection = 100, .idle_timeout = 300ms, @@ -114,7 +114,7 @@ TEST_CASE("test idle timeout yield") { async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { coro_rpc::coro_rpc_server server(1, 8801); auto is_started = server.async_start(); - REQUIRE(is_started); + REQUIRE(!is_started.hasResult()); auto pool = coro_io::client_pool::create( "127.0.0.1:8801", {.max_connection = 100, .idle_queue_per_max_clear_count = 1, @@ -142,7 +142,7 @@ TEST_CASE("test reconnect") { async_simple::Promise p; coro_io::sleep_for(700ms).start([&server, &p](auto &&) { auto server_is_started = server.async_start(); - REQUIRE(server_is_started); + REQUIRE(!server_is_started.hasResult()); }); auto res = co_await event(100, *pool, cv, lock); @@ -177,7 +177,7 @@ TEST_CASE("test reconnect retry wait time exclude reconnect cost time") { async_simple::Promise p; coro_io::sleep_for(350ms).start([&server, &p](auto &&) { auto server_is_started = server.async_start(); - REQUIRE(server_is_started); + REQUIRE(!server_is_started.hasResult()); }); auto res = co_await event(100, *pool, cv, lock); CHECK(res); @@ -196,7 +196,7 @@ TEST_CASE("test collect_free_client") { async_simple::coro::syncAwait([]() -> async_simple::coro::Lazy { coro_rpc::coro_rpc_server server(1, 8801); auto is_started = server.async_start(); - REQUIRE(is_started); + REQUIRE(!is_started.hasResult()); auto pool = coro_io::client_pool::create( "127.0.0.1:8801", {.max_connection = 100, .idle_timeout = 300ms}); diff --git a/src/coro_rpc/benchmark/data_gen.cpp b/src/coro_rpc/benchmark/data_gen.cpp index da330a656..e090bb9c3 100644 --- a/src/coro_rpc/benchmark/data_gen.cpp +++ b/src/coro_rpc/benchmark/data_gen.cpp @@ -31,7 +31,7 @@ int main() { coro_rpc::coro_rpc_server server(std::thread::hardware_concurrency(), 0); register_handlers(server); auto started = server.async_start(); - if (!started) { + if (started.hasResult()) { ELOGV(ERROR, "server started failed"); return -1; } @@ -118,7 +118,7 @@ int main() { server.stop(); - started->wait(); + started.wait(); pool.stop(); thd.join(); diff --git a/src/coro_rpc/examples/base_examples/rpc_service.cpp b/src/coro_rpc/examples/base_examples/rpc_service.cpp index da6eb6db3..1414f0758 100644 --- a/src/coro_rpc/examples/base_examples/rpc_service.cpp +++ b/src/coro_rpc/examples/base_examples/rpc_service.cpp @@ -52,7 +52,7 @@ void async_echo_by_callback( /* rpc function runs in global io thread pool */ coro_io::post([conn, data]() mutable { /* send work to global non-io thread pool */ - auto *ctx = conn.get_context(); + auto *ctx = conn.get_context_info(); conn.response_msg(data); /*response here*/ }).start([](auto &&) { }); diff --git a/src/coro_rpc/examples/base_examples/server.cpp b/src/coro_rpc/examples/base_examples/server.cpp index c7afd710a..6c9c3e02f 100644 --- a/src/coro_rpc/examples/base_examples/server.cpp +++ b/src/coro_rpc/examples/base_examples/server.cpp @@ -39,7 +39,7 @@ int main() { server2.register_handler(); // async start server auto res = server2.async_start(); - assert(res.has_value()); + assert(!res.hasResult()); // sync start server & sync await server stop return !server.start(); diff --git a/src/coro_rpc/examples/file_transfer/rpc_service.cpp b/src/coro_rpc/examples/file_transfer/rpc_service.cpp index e034218a5..6b1a759d4 100644 --- a/src/coro_rpc/examples/file_transfer/rpc_service.cpp +++ b/src/coro_rpc/examples/file_transfer/rpc_service.cpp @@ -6,7 +6,7 @@ std::string echo(std::string str) { return str; } void upload_file(coro_rpc::context conn, file_part part) { - auto &ctx = *conn.get_context(); + auto &ctx = *conn.get_context_info(); if (!ctx.tag().has_value()) { auto filename = std::to_string(std::time(0)) + std::filesystem::path(part.filename).extension().string(); @@ -27,7 +27,7 @@ void upload_file(coro_rpc::context conn, file_part part) { void download_file(coro_rpc::context conn, std::string filename) { - auto &ctx = *conn.get_context(); + auto &ctx = *conn.get_context_info(); if (!ctx.tag().has_value()) { std::string actual_filename = std::filesystem::path(filename).filename().string(); diff --git a/src/coro_rpc/tests/rpc_api.cpp b/src/coro_rpc/tests/rpc_api.cpp index 7ed6c6bc2..6f1982a8a 100644 --- a/src/coro_rpc/tests/rpc_api.cpp +++ b/src/coro_rpc/tests/rpc_api.cpp @@ -50,9 +50,9 @@ int long_run_func(int val) { void echo_with_attachment(coro_rpc::context conn) { ELOGV(INFO, "call function echo_with_attachment, conn ID:%d", - conn.get_context()->get_connection_id()); - auto str = conn.get_context()->release_request_attachment(); - conn.get_context()->set_response_attachment(std::move(str)); + conn.get_context_info()->get_connection_id()); + auto str = conn.get_context_info()->release_request_attachment(); + conn.get_context_info()->set_response_attachment(std::move(str)); conn.response_msg(); } template @@ -81,7 +81,7 @@ void test_context() { return; } void test_callback_context(coro_rpc::context conn) { - auto *ctx = conn.get_context(); + auto *ctx = conn.get_context_info(); test_ctx_impl(ctx, "test_callback_context"); [](coro_rpc::context conn) -> async_simple::coro::Lazy { co_await coro_io::sleep_for(514ms); diff --git a/src/coro_rpc/tests/test_coro_rpc_client.cpp b/src/coro_rpc/tests/test_coro_rpc_client.cpp index cd5314001..7ced03611 100644 --- a/src/coro_rpc/tests/test_coro_rpc_client.cpp +++ b/src/coro_rpc/tests/test_coro_rpc_client.cpp @@ -84,12 +84,12 @@ TEST_CASE("testing client") { future.wait(); coro_rpc_server server(2, coro_rpc_server_port); #ifdef YLT_ENABLE_SSL - server.init_ssl_context( + server.init_ssl( ssl_configure{"../openssl_files", "server.crt", "server.key"}); #endif auto res = server.async_start(); - CHECK_MESSAGE(res, "server start failed"); + CHECK_MESSAGE(!res.hasResult(), "server start failed"); SUBCASE("call rpc, function not registered") { g_action = {}; @@ -172,11 +172,11 @@ TEST_CASE("testing client with inject server") { }); coro_rpc_server server(2, coro_rpc_server_port); #ifdef YLT_ENABLE_SSL - server.init_ssl_context( + server.init_ssl( ssl_configure{"../openssl_files", "server.crt", "server.key"}); #endif auto res = server.async_start(); - CHECK_MESSAGE(res, "server start failed"); + CHECK_MESSAGE(!res.hasResult(), "server start failed"); server.register_handler(); @@ -242,10 +242,10 @@ class SSLClientTester { inject("server key", server_key_path, server_key); inject("dh", dh_path, dh); ssl_configure config{base_path, server_crt_path, server_key_path, dh_path}; - server.init_ssl_context(config); + server.init_ssl(config); server.template register_handler(); auto res = server.async_start(); - CHECK_MESSAGE(res, "server start timeout"); + CHECK_MESSAGE(!res.hasResult(), "server start timeout"); std::promise promise; auto future = promise.get_future(); @@ -371,7 +371,7 @@ TEST_CASE("testing client with eof") { coro_rpc_server server(2, 8801); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); auto ec = client.sync_connect("127.0.0.1", "8801"); REQUIRE_MESSAGE(!ec, ec.message()); @@ -393,7 +393,7 @@ TEST_CASE("testing client with attachment") { coro_rpc_server server(2, 8801); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); auto ec = client.sync_connect("127.0.0.1", "8801"); REQUIRE_MESSAGE(!ec, ec.message()); @@ -418,7 +418,7 @@ TEST_CASE("testing client with context response user-defined error") { g_action = {}; coro_rpc_server server(2, 8801); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); auto ec = client.sync_connect("127.0.0.1", "8801"); REQUIRE(!ec); @@ -437,7 +437,7 @@ TEST_CASE("testing client with shutdown") { g_action = {}; coro_rpc_server server(2, 8801); auto res = server.async_start(); - CHECK_MESSAGE(res, "server start timeout"); + CHECK_MESSAGE(!res.hasResult(), "server start timeout"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); auto ec = client.sync_connect("127.0.0.1", "8801"); REQUIRE_MESSAGE(!ec, ec.message()); @@ -502,7 +502,7 @@ TEST_CASE("testing client sync connect, unit test inject only") { g_action = {}; coro_rpc_server server(2, 8801); auto res = server.async_start(); - CHECK_MESSAGE(res, "server start timeout"); + CHECK_MESSAGE(!res.hasResult(), "server start timeout"); coro_rpc_client client2(*coro_io::get_global_executor(), g_client_id++); bool ok = client2.init_ssl("../openssl_files", "server.crt"); CHECK(ok == true); @@ -537,7 +537,7 @@ TEST_CASE("testing client call timeout") { server.register_handler(); server.register_handler(); auto res = server.async_start(); - CHECK_MESSAGE(res, "server start timeout"); + CHECK_MESSAGE(!res.hasResult(), "server start timeout"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); auto ec_lazy = client.connect("127.0.0.1", "8801"); auto ec = syncAwait(ec_lazy); diff --git a/src/coro_rpc/tests/test_coro_rpc_server.cpp b/src/coro_rpc/tests/test_coro_rpc_server.cpp index 23f522204..444776be0 100644 --- a/src/coro_rpc/tests/test_coro_rpc_server.cpp +++ b/src/coro_rpc/tests/test_coro_rpc_server.cpp @@ -37,12 +37,12 @@ struct CoroServerTester : ServerTester { server(2, config.port, config.address, config.conn_timeout_duration) { #ifdef YLT_ENABLE_SSL if (use_ssl) { - server.init_ssl_context( + server.init_ssl( ssl_configure{"../openssl_files", "server.crt", "server.key"}); } #endif auto res = server.async_start(); - CHECK_MESSAGE(res, "server start timeout"); + CHECK_MESSAGE(!res.hasResult(), "server start timeout"); } ~CoroServerTester() { server.stop(); } @@ -231,9 +231,9 @@ struct CoroServerTester : ServerTester { { auto new_server = coro_rpc_server(2, std::stoi(this->port_)); auto ec = new_server.async_start(); - REQUIRE(!ec); - REQUIRE_MESSAGE(ec.error() == coro_rpc::errc::address_in_used, - ec.error().message()); + REQUIRE(ec.hasResult()); + REQUIRE_MESSAGE(ec.value() == coro_rpc::errc::address_in_used, + ec.value().message()); } ELOGV(INFO, "OH NO"); } @@ -312,7 +312,7 @@ TEST_CASE("testing coro rpc server stop") { ELOGV(INFO, "run testing coro rpc server stop"); coro_rpc_server server(2, 8810); auto res = server.async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); SUBCASE("stop twice") { server.stop(); server.stop(); @@ -335,7 +335,7 @@ TEST_CASE("test server accept error") { coro_rpc_server server(2, 8810); server.register_handler(); auto res = server.async_start(); - CHECK_MESSAGE(res, "server start timeout"); + CHECK_MESSAGE(!res.hasResult(), "server start timeout"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); ELOGV(INFO, "run test server accept error, client_id %d", client.get_client_id()); @@ -356,7 +356,7 @@ TEST_CASE("test server write queue") { coro_rpc_server server(2, 8810); server.register_handler(); auto res = server.async_start(); - CHECK_MESSAGE(res, "server start timeout"); + CHECK_MESSAGE(!res.hasResult(), "server start timeout"); std::string buffer; buffer.reserve(coro_rpc_protocol::REQ_HEAD_LEN + struct_pack::get_needed_size(std::monostate{})); @@ -420,7 +420,7 @@ TEST_CASE("testing coro rpc write error") { coro_rpc_server server(2, 8810); server.register_handler(); auto res = server.async_start(); - CHECK_MESSAGE(res, "server start failed"); + CHECK_MESSAGE(!res.hasResult(), "server start failed"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); ELOGV(INFO, "run testing coro rpc write error, client_id %d", client.get_client_id()); diff --git a/src/coro_rpc/tests/test_variadic.cpp b/src/coro_rpc/tests/test_variadic.cpp index 79a8b0153..040a41674 100644 --- a/src/coro_rpc/tests/test_variadic.cpp +++ b/src/coro_rpc/tests/test_variadic.cpp @@ -31,7 +31,7 @@ TEST_CASE("test varadic param") { std::thread::hardware_concurrency(), 8808); server->register_handler(); auto res = server->async_start(); - REQUIRE_MESSAGE(res, "server start failed"); + REQUIRE_MESSAGE(!res.hasResult(), "server start failed"); coro_rpc_client client(*coro_io::get_global_executor(), g_client_id++); syncAwait(client.connect("localhost", std::to_string(server->port()))); diff --git a/website/Doxyfile b/website/Doxyfile index ca2b1e5fc..5b3ef1679 100644 --- a/website/Doxyfile +++ b/website/Doxyfile @@ -5,6 +5,8 @@ INPUT=../include/ylt/struct_pack.hpp \ ../include/ylt/coro_rpc/coro_rpc_server.hpp \ ../include/ylt/coro_rpc/coro_rpc_client.hpp \ docs/en/coro_rpc/coro_rpc_introduction.md \ + docs/en/coro_rpc/coro_rpc_server.md \ + docs/en/coro_rpc/coro_rpc_client.md \ docs/en/struct_pack/struct_pack_intro.md MARKDOWN_SUPPORT = YES diff --git a/website/Doxyfile_cn b/website/Doxyfile_cn index d8c709133..a424a6ce4 100644 --- a/website/Doxyfile_cn +++ b/website/Doxyfile_cn @@ -2,7 +2,9 @@ PROJECT_NAME=yaLanTingLibs GENERATE_HTML=yes GENERATE_LATEX=no INPUT=docs/zh/coro_rpc/coro_rpc_doc.hpp \ - docs/zh/coro_rpc/coro_rpc_intro.md \ + docs/zh/coro_rpc/coro_rpc_introduction.md \ + docs/zh/coro_rpc/coro_rpc_server.md \ + docs/zh/coro_rpc/coro_rpc_client.md \ docs/zh/struct_pack/struct_pack_doc.hpp \ docs/zh/struct_pack/struct_pack_intro.md diff --git a/website/docs/en/coro_rpc/coro_rpc_client.md b/website/docs/en/coro_rpc/coro_rpc_client.md new file mode 100644 index 000000000..4b3daf5ac --- /dev/null +++ b/website/docs/en/coro_rpc/coro_rpc_client.md @@ -0,0 +1,261 @@ +# Introduction to coro_rpc Client + +## Base Usage + +class `coro_rpc::coro_rpc_client` is the client side of coro_rpc, allowing users to send RPC requests to the server. + +Below, we will demonstrate the basic usage of rpc_client. + +```cpp +using namespace async_simple; +using namespace coro_rpc; +int add(int a,int b); +Lazy example() { + coro_rpc_client client; + coro_rpc::err_code ec = co_await client.connect("localhost:9001"); + if (ec) { /*check if connection error*/ + std::cout<(1,2); + /*rpc_result is type of expected, which T is rpc return type*/ + if (!result.has_value()) { + /*call result.error() to get rpc error message*/ + std::cout<<"error code:"<set_resp_attachment(ctx->get_req_attachment()); +} +Lazy example(coro_rpc_client& client, std::string_view attachment) { + client.set_req_attachment(attachment); + rpc_result result = co_await client.call(); + if (result.has_value()) { + assert(result.get_resp_attachment()==attachment); + co_return std::move(result.release_resp_attachment()); + } + co_return ""; +} +``` + +By default, the RPC client will wait for 5 seconds after sending a request/establishing a connection. If no response is received after 5 seconds, it will return a timeout error. Users can also customize the wait duration by calling the `call_for` function. + +```cpp +client.connect("127.0.0.1:9001", std::chrono::seconds{10}); +auto result = co_await client.call_for(std::chrono::seconds{10},1,2); +assert(result.value() == 3); +``` + +The duration can be any `std::chrono::duration`` type, common examples include `std::chrono::seconds`` and `std::chrono::milliseconds``. Notably, if the duration is set to zero, it indicates that the function call will never time out. + +## SSL support + +coro_rpc supports using OpenSSL to encrypt connections. After installing OpenSSL and importing yalantinglibs into your project with CMake's `find_package` or `fetch_content`, you can enable SSL support by setting the CMake option YLT_ENABLE_SSL=ON. Alternatively, you might manually add the YLT_ENABLE_SSL macro and manually link to OpenSSL. + +Once SSL support has been enabled, users can invoke the `init_ssl`` function before establishing a connection to the server. This will create an encrypted link between the client and the server. It’s important to note that the coro_rpc server must also be compiled with SSL support enabled, and the `init_ssl` method must be called to enable SSL support before starting the server. + +```cpp +client.init_ssl("./","server.crt"); +``` + + +The first string represents the base path where the SSL certificate is located, the second string represents the relative path of the SSL certificate relative to the base path. + +## Conversion and compile-time checking of RPC parameters + +coro_rpc will perform compile-time checks on the validity of arguments during invocation. For example, for the following rpc function: + +```cpp +inline std::string echo(std::string str) { return str; } +``` + +Next, when the current client invokes the rpc function: + +```cpp +client.call(42); // Parameter does not match, compilation error +client.call(); // Missing parameter, compilation error +client.call("", 0); // Extra parameters, compilation error +client.call("hello, coro_rpc"); // The string literal can be converted to std::string, compilation succeeds +``` + +## Connect Option + +The `coro_rpc_client` provides an `init_config`` function for configuring connection options. The following code snippet lists the configurable options. + +```cpp +using namespace coro_rpc; +using namespace std::chrono; +void set_config(coro_rpc_client& client) { + client.init_config(config{ + .timeout_duration = 5s, // Timeout duration for requests and connections + .host = "localhost", // Server hostname + .port = "9001", // Server port + .enable_tcp_no_delay = true, // Whether to disable socket-level delayed sending of requests + /* The following options are available only when SSL support is activated */ + .ssl_cert_path = "./server.crt", // Path to the SSL certificate + .ssl_domain = "localhost" + }); +} +``` + +## Calling Model + +Each `coro_rpc_client` is bound to a specific IO thread. By default, it selects a connection via round-robin from the global IO thread pool. Users can also manually bind it to a specific IO thread. + +```cpp +auto executor=coro_io::get_global_executor(); +coro_rpc_client client(executor),client2(executor); +// Both clients are bound to the same IO thread. +``` + +Each time a coroutine-based IO task is initiated (such as `connect`, `call`, `send_request`), the client internally submits the IO event to the operating system. When the IO event is completed, the coroutine is then resumed on the bound IO thread to continue execution. For example, in the following code, the task switches to the IO thread for execution after calling connect. + +```cpp +/*run in thread 1*/ +coro_rpc_client cli; +co_await cli.connect("localhost:9001"); +/*run in thread 2*/ +do_something(); +``` + +## Connection Pool and Load Balancing + +`coro_io` offers a connection pool `client_pool` and a load balancer `channel`. Users can manage `coro_rpc`/`coro_http` connections through the `client_pool`, and can use `channel` to achieve load balancing among multiple hosts. For more details, please refer to the documentation of `coro_io`. + +## Connection Reuse + +The `coro_rpc_client` can achieve connection reuse through the `send_request`` function. This function is thread-safe, allowing multiple threads to call the `send_request` method on the same client concurrently. The return value of the function is `Lazy>>`. The first `co_await` waits for the request to be sent, and the second `co_await` waits for the rpc result to return. + + +Connection reuse allows us to reduce the number of connections under high concurrency, eliminating the need to create new connections. It also improves the throughput of each connection. + +Here's a simple example code snippet: + +```cpp +using namespace coro_rpc; +using namespace async_simple::coro; +std::string_view echo(std::string_view); +Lazy example(coro_rpc_client& client) { + // Wait for the request to be fully sent + Lazy handler = co_await client.send_request("Hello"); + // Then wait for the server to return the RPC request result + async_rpc_result result = co_await handler; + if (result) { + assert(result->result() == "Hello"); + } + else { + // error handle + std::cout< example(coro_rpc_client& client) { + std::vector> handlers; + // First, send 10 requests consecutively + for (int i=0;i<10;++i) { + handlers.push_back(co_await client.send_request(std::to_string(i))); + } + // Next, wait for all the requests to return + std::vector results = co_await collectAll(std::move(handlers)); + for (int i=0;i<10;++i) { + assert(results[i]->result() == std::to_string(i)); + } + co_return; +} +``` + +### Attachment + +When using the `send_request` method, since multiple requests might be sent simultaneously, we should not call the `set_req_attachment` method to send an attachment to the server, nor should we call the `get_resp_attachment` and `release_resp_attachment` methods to get the attachment returned by the server. + +Instead, we can set the attachment when sending a request by calling the `send_request_with_attachment` function. Additionally, we can retrieve the attachment by calling the `->get_attachment()` and `->release_buffer()` methods of `async_rpc_result`. + + + +```cpp +using namespace coro_rpc; +using namespace async_simple::coro; +int add(int a, int b); +Lazy example(coro_rpc_client& client) { + async_rpc_result result = co_await co_await client.send_request_with_attachment("Hello", 1, 2); + assert(result->result() == 3); + assert(result->get_attachment() == "Hello"); + co_return std::move(result->release_buffer().resp_attachment_buf_); +} +``` + + +### Execution order + +When the called rpc function is a coroutine rpc function or a callback rpc function, the rpc requests may not necessarily be executed in order. The server might execute multiple rpc requests simultaneously. +For example, suppose there is the following code: + +```cpp +using namespace async_simple::coro; +Lazy sleep(int seconds) { + co_await coro_io::sleep(1s * seconds); // Yield the coroutine here + co_return; +} +``` + +Server registration and startup: +```cpp +using namespace coro_rpc; +void start() { + coro_rpc_server server(/* thread = */1,/* port = */ 8801); + server.register_handler(); + server.start(); +} +``` + +The client consecutively calls the sleep function twice on the same connection, sleeping for 2 seconds the first time and 1 second the second time. +```cpp +using namespace async_simple::coro; +using namespace coro_rpc; +Lazy call() { + coro_rpc_client cli,cli2; + co_await cli.connect("localhost:8801"); + co_await cli2.connect("localhost:8801"); + auto handler1 = co_await cli.send_request(2); + auto handler2 = co_await cli.send_request(1); + auto handler3 = co_await cli2.send_request(0); + handler2.start([](auto&&){ + std::cout<<"handler2 return"< -Lazy say_hello(){ +Lazy say_hello() { coro_rpc_client client; co_await client.connect("localhost", /*port =*/"9000"); while (true){ @@ -262,77 +262,6 @@ Lazy say_hello(){ One core feature of coro_rpc is stackless coroutine where users could write asynchronous code in a synchronous manner, which is more simple and easy to understand. -# More features - -## Real-time Tasks and Non-Real-time Tasks - -The examples shown earlier do not demonstrate how responses are sent back to the client with the results, because by default the coro_rpc framework will help the user to serialize and send the results to client automatically. And the user is completely unaware and only needs to focus on the business logic. It should be noted that, in this scenario, the response callback is executed in the I/O thread, which is suitable for real-time critical scenarios, with the disadvantage of blocking the I/O thread. What if the user does not want to execute the business logic in the io thread, but rather in a thread or thread pool and delays sending messages? - -coro_rpc has taken this problem into account. coro_rpc considers that RPC tasks are divided into real-time and Non-real-time tasks. real-time tasks are executed in the I/O thread and sent to the client immediately, with better timeliness and lower latency; Non-real-time tasks can be scheduled in a separate thread, and the requests are sent to the server at some point in the future; coro_rpc supports both kinds of tasks. - - -Switch to time-delayed task - -```cpp -#include -#include - -//Real-time tasks -std::string echo(std::string str) { return str; } - -//Non-Real-time tasks, requests handled in separate thread -void delay_echo(coro_connection conn, std::string str) { - std::thread([conn, str]{ - conn.response_msg(str); //requests handled in separate thread - }).detach(); -} -``` - -## Asynchronous mode - -It is recommended to use coroutine on server development. However, the asynchronous call mode is also supported if user does not prefer coroutine. - -- coroutine based rpc server -```cpp -#include -std::string hello() { return "hello coro_rpc"; } - -int main() { - coro_rpc_server server(/*thread_num =*/10, /*port =*/9000); - server.register_handler(); - server.start(); -} -``` - -- Asynchronous rpc server - -```cpp -#include -std::string hello() { return "hello coro_rpc"; } - -int main() { - async_rpc_server server(/*thread_num =*/10, /*port =*/9000); - server.register_handler(); - server.start(); -} -``` - -Compile-time syntax checks -coro_rpc does a compile-time check on the legality of the arguments when it is called, e.g.: - -```cpp -inline std::string echo(std::string str) { return str; } -``` - -When client is called via: - -```cpp -client.call(42); //Parameter mismatch, compile error -client.call(); //Missing parameters, compile error -client.call("", 0); //Redundant parameters, compile error -client.call("hello, coro_rpc");//Parameters match, OK -``` - # Benchmark ## System Configuration diff --git a/website/docs/en/coro_rpc/coro_rpc_server.md b/website/docs/en/coro_rpc/coro_rpc_server.md new file mode 100644 index 000000000..f18f646f4 --- /dev/null +++ b/website/docs/en/coro_rpc/coro_rpc_server.md @@ -0,0 +1,433 @@ +# coro_rpc Server Introduction + +## Server registration and startup + +### Function registration + +Before starting the RPC server, we need to call the `register_handler<>` function to register all RPC functions. Registration is not thread-safe and cannot be done after the RPC server has started. + +```cpp +void hello(); +Lazy echo(std::string_view); +int add(int a, int b); +int regist_rpc_funtion(coro_rpc_server& server) { + server.register_handler(); +} +``` + +### Start the server + +We can start a server by calling the `.start()` method, which will block the current thread until the server exits. + +```cpp +int start_server() { + coro_rpc_server server; + regist_rpc_funtion(server); + coro_rpc::err_code ec = server.start(); + /*block util server down*/ +} +``` + +If you do not want to block the current thread, we also allow asynchronously starting a server by calling `async_start()`. After this function returns, it ensures that the server has already started listening on the port (or an error has occurred). Users can check `async_simple::Future::hasResult()` to determine whether the server is currently started successfully and running normally. Calling the `async_simple::Future::get()` method can then be used to wait for the server to stop. + +```cpp +int start_server() { + coro_rpc_server server; + regist_rpc_funtion(server); + async_simple::Future ec = server.async_start(); /*won't block here */ + assert(!ec.hasResult()) /* check if server start success */ + auto err = ec.get(); /*block here util server down then return err code*/ +} +``` + +coro_rpc supports the registration and calling of three types of RPC functions: + +1. Ordinary RPC Functions +2. Coroutine RPC Functions +3. Callback RPC Functions + +## Ordinary RPC Functions + +If a function is neither a coroutine nor its first parameter is of type `coro_rpc::context`, then this RPC function is an ordinary function. +For example, the following functions are ordinary functions: + + +```cpp +int add(int a, int b); +std::string_view echo(std::string_view str); +struct dummy { + std::string_view echo(std::string_view str) { return str; } +}; +``` + +### Calling model + +Synchronous execution is a definite characteristic of ordinary functions. When a connection submits a request for an ordinary function, the server will execute that function on the I/O thread associated with that connection, and it will continue to do so until the function has been completed. Only then will the result be sent back to the client, and subsequent requests from that connection will be addressed. For instance, if a client sends two requests, A and B, in sequence, we guarantee that B will be executed only after A has finished. + +It's important to note that performing time-consuming operations within a function can not only block the current connection but may also impede other connections that are bound to the same I/O thread. Therefore, in scenarios where performance is of high concern, one should not register ordinary functions that are too taxing. Instead, one might want to consider the use of coroutine functions or callback functions as an alternative. + +### Retrieving Context Information + +When a function is called by coro_rpc_server, the following code can be used to obtain context information about the connection. + +```cpp +using namespace coro_rpc; +void test() { + context_info_t* ctx = coro_rpc::get_context(); + if (ctx->has_closed()) { // Check if the connection has been closed + throw std::runtime_error("Connection is closed!"); + } + // Retrieve the connection ID and request ID + ELOGV(INFO, "Call function echo_with_attachment, connection ID: %d, request ID: %d", + ctx->get_connection_id(), ctx->get_request_id()); + // Obtain the client's IP and port as well as the server's IP and port + ELOGI << "Remote endpoint: " << ctx->get_remote_endpoint() << ", local endpoint: " + << ctx->get_local_endpoint(); + // Get the name of the RPC function + ELOGI << "RPC function name: " << ctx->get_rpc_function_name(); + // Get the request attachment + std::string_view sv{ctx->get_request_attachment()}; + // Release the request attachment + std::string str = ctx->release_request_attachment(); + // Set the response attachment + ctx->set_response_attachment(std::move(str)); +} +``` + +An attachment is an additional piece of data that accompanies an RPC request. coro_rpc does not serialize it. Users can obtain a view of the request's accompanying attachment or release it from the context for separate manipulation. Similarly, users can also set the attachment to be sent back to the RPC client in the response. + +### Error Handling + +We allow the termination of an RPC call and the return of RPC error codes and error messages to the user by throwing a `coro_rpc::rpc_error` exception. + +```cpp +void rpc() { + throw coro_rpc::rpc_error{coro_rpc::errc::io_error}; // Return a custom error code + throw coro_rpc::rpc_error{10404}; // Return a custom error code + throw coro_rpc::rpc_error{10404, "404 Not Found"}; // Return a custom error code and error message +} +``` + +An RPC error code is a 16-bit unsigned integer. The range 0-255 is reserved for error codes used by the RPC framework itself, whereas user-defined error codes can be any integer within [256, 65535]. When an RPC returns a user-defined error code, the connection will not be closed. However, if the returned error code is one reserved by the RPC framework and indicates a severe RPC error, it will result in the disconnection of the RPC link. + + +## Coroutine RPC Functions + +If an RPC function has a return type of `async_simple::coro::Lazy`, then it's considered a coroutine function. Compared to ordinary functions, coroutine functions are asynchronous, which means they can yield the I/O thread while waiting for events to complete, thus improving concurrency performance. + +For instance, the following RPC function uses a coroutine to submit a heavy computation task to the global thread pool, thereby avoiding blocking the current I/O thread. + +```cpp +using namespace async_simple::coro; +int heavy_calculate(int value); +Lazy calculate(int value) { + auto val = co_await coro_io::post([value](){return heavy_calculate(value);}); //将任务提交到全局线程池执行,让出当前IO线程,直到任务完成。 + co_return val; +} +``` + +Users can also use async_simple::Promise to submit tasks to a custom thread pool: + +```cpp +using namespace async_simple::coro; +void heavy_calculate(int value); +Lazy calculate(int value) { + async_simple::Promise p; + std::thread th([&p,value](){ + auto ret = heavy_calculate(value); + p.setValue(ret); // Task completed, wake up the RPC function + }); + th.detach(); + auto ret = co_await p.get_future(); // Wait for the task to complete + co_return ret; +} +``` + +### Calling Model + +When a connection submits a coroutine function request, the server will start a new coroutine on the I/O thread that the connection is bound to and execute the function within this new coroutine. Once the coroutine function completes, the server will send the RPC result back to the client based on its return value. If the coroutine yields during execution, the I/O thread will continue to execute other tasks, such as handling the next request or managing other connections bound to the same I/O thread. + +For example, consider the following code: + +```cpp +using namespace async_simple::coro; +Lazy sleep(int seconds) { + co_await coro_io::sleep(1s * seconds); // Yield the coroutine here + co_return; +} +``` + +Then the server register and start: +```cpp +using namespace coro_rpc; +void start() { + coro_rpc_server server(/* thread = */1,/* port = */ 8801); + server.register_handler(); + server.start(); +} +``` + +The client invokes the sleep function twice consecutively on the same connection, sleeping for 2 seconds the first time and 1 second the second time. + +```cpp +using namespace async_simple::coro; +using namespace coro_rpc; +Lazy call() { + coro_rpc_client cli,cli2; + co_await cli.connect("localhost:8801"); + co_await cli2.connect("localhost:8801"); + auto handler1 = co_await cli.send_request(2); + auto handler2 = co_await cli.send_request(1); + auto handler3 = co_await cli2.send_request(0); + handler2.start([](auto&&){ + std::cout<<"handler2 return"< test() { + context_info_t* ctx = co_await coro_rpc::get_context_in_coro(); +} +``` + +### Error Handling + +Similar to regular functions, we can return RPC errors by throwing the `coro_rpc::rpc_error` exception, allowing for customized RPC error codes and messages. + + +## Callback RPC Functions + +We also support the more traditional callback functions to implement asynchronous RPC calls. The syntax for a callback function is as follows: +```cpp +void echo(coro_rpc::context, std::string_view param); +``` + +If a function's return type is `void` and the first parameter is of type `coro_rpc::context`, then this function is a callback function. The `coro_rpc::context` is similar to a smart pointer, holding the callback handle and context information for this RPC call. + +For example, in the code below, we copy `coro_rpc::context` to another thread, which then sleeps for 30 seconds before returning the result to the RPC client by calling `coro_rpc::context::response_msg()`. + +```cpp +using namespace std::chrono; +void echo(coro_rpc::context ctx, std::string_view param) { + std::thread th([ctx, param](){ + std::this_thread::sleep_for(30s); + ctx.response_msg(param); + }); + return; +} +``` + +It should be noted that view types in the RPC function parameters, such as std::string_view and std::span, will have their underlying data become invalid after all copies of the coro_rpc::context object for this RPC call are destructed. + +### Calling Model + +When a connection receives a request for a callback function, the I/O thread allocated to that connection will immediately execute the function until it is completed, after which other requests will be processed. Since callback functions do not have return values, the server does not immediately reply to the client after the RPC function is executed. + +When the user calls `coro_rpc::context::response_msg` or `coro_rpc::context::response_error`, the RPC server will be notified, and only then will the result be sent to the client. Therefore, users must ensure that they actively call one of the callback functions at some point in their code. + + +### Obtaining Context Information + +In callback functions, we can call `coro_rpc::context::get_context_info()` to obtain the coroutine's context information. Additionally, `coro_io::get_context()` can be used to obtain context information before the RPC function returns. However, after the RPC function has returned, the context information pointed to by `coro_io::get_context()` may be modified or invalid. Therefore, it's recommended to use `coro_rpc::context::get_context_info()` to obtain context information. + +```cpp +void echo(coro_rpc::context ctx) { + context_info_t* info = ctx.get_context_info(); + return; +} +``` + +### Error Handling + +In callback functions, one should not and cannot return RPC errors by throwing exceptions, because the error might not occur within the call stack of the RPC function. Instead, we can use the coro_rpc::context::response_error() function to return RPC errors. + +```cpp +void echo(coro_rpc::context ctx) { + ctx.response_error(10015); // Custom RPC error code + ctx.response_error(10015, "my error msg"); // Custom RPC error code and error message + ctx.response_error(coro_rpc::errc::io_error); // Using the built-in error code of the RPC framework + return; +} +``` + +The RPC error code is a 16-bit unsigned integer. The range 0-255 is reserved for error codes used by the RPC framework, and user-defined error codes can be any integer between [256, 65535]. When an RPC returns a user-defined error code, the connection will not be terminated. However, if an error code from the RPC framework is returned, it is considered a serious RPC error, leading to the disconnection of the RPC link. + +## Connections and I/O Threads + +The server internally has an I/O thread pool, the size of which defaults to the number of logical threads of the CPU. After the server starts, it launches a listening task on one of the I/O threads to accept connections from clients. Each time a connection is accepted, the server selects an I/O thread through round-robin to bind it to. Subsequently, all steps including data transmission, serialization, RPC routing, etc., of that connection are executed on this I/O thread. The RPC functions are also executed on the same I/O thread. + +This means if your RPC functions will block the current thread (e.g., thread sleep, synchronous file read/write), it is better to make them asynchronous to avoid blocking the I/O thread, thereby preventing other requests from being blocked. For example, `async_simple` provides coroutine locks such as `Mutex` and `Spinlock`, and components such as `Promise` and `Future` that wrap asynchronous tasks as coroutine tasks. `coro_io` offers coroutine-based asynchronous file read/write, asynchronous read/write of sockets, sleep, and the `period_timer` timer. It also allows submitting high-CPU-load tasks to the global blocking task thread pool through `coro_io::post`. coro_rpc/coro_http offer coroutine-based asynchronous RPC and HTTP calls, respectively. easylog by default submits log content to a background thread for writing, ensuring the foreground does not block. + + +## Parameter and Return Value Types + +coro_rpc allows users to register rpc functions with multiple parameters (up to 64), and the types of arguments and return values can be user-defined aggregate structures. They also support various data structures provided by the C++ standard library and many third-party libraries. For details, see: [struct_pack type system](https://alibaba.github.io/yalantinglibs/en/struct_pack/struct_pack_type_system.html) + +If your rpc argument or return value type is not supported by the struct_pack type system, we also allow users to register their own structures or custom serialization algorithms. For more details, see: [Custom feature](https://alibaba.github.io/yalantinglibs/en/struct_pack/struct_pack_intro.html#custom-type) + +## RPC Return Value Construction and Checking + +Furthermore, for callback functions, coro_rpc will try to construct the return value type from the parameter list. If it fails to construct, it will lead to a compilation failure. + +```cpp +void echo(coro_rpc::context ctx) { + ctx.response_msg(); // Unable to construct std::string. Compilation fails. + ctx.response_msg(42); // Unable to construct std::string. Compilation fails. + ctx.response_msg(42,'A'); // Able to construct std::string, compilation passes. + ctx.response_msg("Hello"); // Able to construct std::string, compilation passes. + return; +} +``` + +## SSL Support + +coro_rpc supports encrypting connections with OpenSSL. After installing OpenSSL and importing yalantinglibs into your project using cmake's `find_package/fetch_content`, you can enable SSL support by turning on the cmake option `YLT_ENABLE_SSL=ON`. Alternatively, you can manually add the macro `YLT_ENABLE_SSL` and manually link OpenSSL. + +Once SSL support is enabled, users can call the `init_ssl` function before connecting to the server. This will establish an encrypted link between the client and the server. It should be noted that the coro_rpc server also must have SSL support enabled at compile time. + +```cpp +coro_rpc_server server; +server.init_ssl({ + .base_path = "./", // Base path of ssl files. + .cert_file = "server.crt", // Path of the certificate relative to base_path. + .key_file = "server.key" // Path of the private key relative to base_path. +}); +``` + +After enabling SSL support, the server will reject all non-SSL connections. + +## Advanced Settings + +We provide the coro_rpc::config_t class, which allows users to set the details of the server: + +```cpp +struct config_base { + bool is_enable_tcp_no_delay = true; /* Whether to respond immediately to tcp requests */ + uint16_t port = 9001; /* Listening port */ + unsigned thread_num = std::thread::hardware_concurrency(); /* Number of connections used internally by rpc server, default is the number of logical cores */ + std::chrono::steady_clock::duration conn_timeout_duration = + std::chrono::seconds{0}; /* Timeout duration for rpc requests, 0 seconds means rpc requests will not automatically timeout */ + std::string address="0.0.0.0"; /* Listening address */ + /* The following settings are only applicable if SSL is enabled */ + std::optional ssl_config = std::nullopt; // Configure whether to enable ssl +}; +struct ssl_configure { + std::string base_path; // Base path of ssl files. + std::string cert_file; // Path of the certificate relative to base_path. + std::string key_file; // Path of the private key relative to base_path. + std::string dh_file; // Path of the dh_file relative to base_path (optional). +} +int start() { + coro_rpc::config_t config{}; + coro_rpc_server server(config); + /* Register rpc function here... */ + server.start(); +} +``` + + +## Registration and Invocation of Special RPC Functions + +### Registration and Invocation of Member Functions + +coro_rpc supports registering and invoking member functions: + +For example, consider the following function: + +```cpp +struct dummy { + std::string_view echo(std::string_view str) { return str; } + Lazy coroutine_echo(std::string_view str) {co_return str;} + void callback_echo(coro_rpc::context ctx, std::string_view str) { + ctx.response_msg(str); + } +}; +``` + +The server can register these functions like this: + +```cpp +#include "rpc_service.h" +#include +int main() { + coro_rpc_server server; + dummy d{}; + server.register_handler<&dummy::echo,&dummy::coroutine_echo,&dummy::callback_echo>(&d); // regist member function + server.start(); +} +``` + +It's important to note that the lifecycle of the registered dummy type must be considered to ensure it remains alive while the server is running. Otherwise, the invoking behavior is undefined. + +The client can call these functions like this: + +```cpp +#include "rpc_service.h" +#include + +Lazy test_client() { + coro_rpc_client client; + co_await client.connect("localhost", /*port =*/"9000"); + + // calling RPC + { + auto result = co_await client.call<&dummy::echo>("hello"); + assert(result.value() == "hello"); + } + { + auto result = co_await client.call<&dummy::coroutine_echo>("hello"); + assert(result.value() == "hello"); + } + { + auto result = co_await client.call<&dummy::callback_echo>("hello"); + assert(result.value() == "hello"); + } +} +``` + +### Specialized Template Functions + +coro_rpc allows users to register and call specialized template functions. + +For example, consider the following function: + +```cpp +template +T echo(T param) { return param; } +``` + +The server can register these functions like this: + +```cpp +#include +using namespace coro_rpc; +int main() { + coro_rpc_server server; + server.register_handler,echo,echo>>(&d); // Register specialized template functions + server.start(); +} +``` + +The client can call like this: +```cpp +using namespace coro_rpc; +using namespace async_simple::coro; +Lazy rpc_call(coro_rpc_client& cli) { + assert(co_await cli.call>(42).value() == 42); + assert(co_await cli.call>("Hello").value() == "Hello"); + assert(co_await cli.call>(std::vector{1,2,3}).value() == std::vector{1,2,3}); +} +``` \ No newline at end of file diff --git a/website/docs/zh/coro_rpc/coro_rpc_client.md b/website/docs/zh/coro_rpc/coro_rpc_client.md new file mode 100644 index 000000000..c3251bbf3 --- /dev/null +++ b/website/docs/zh/coro_rpc/coro_rpc_client.md @@ -0,0 +1,265 @@ +# coro_rpc客户端介绍 + +## 基本使用 + +类`coro_rpc::coro_rpc_client`是coro_rpc的客户端,用户可以通过它向服务器发送rpc请求。 + +下面我们展示rpc_client的基本使用方法。 + +```cpp +using namespace async_simple; +using namespace coro_rpc; +int add(int a,int b); +Lazy example() { + coro_rpc_client client; + coro_rpc::err_code ec = co_await client.connect("localhost:9001"); + if (ec) { /*判断连接是否出错*/ + std::cout<(1,2); + /*rpc_result是一个expected类型,其中T为rpc返回值*/ + if (!result.has_value()) { + /*调用result.error()获取rpc错误信息*/ + std::cout<<"error code:"<set_resp_attachment(ctx->get_req_attachment()); +} +Lazy example(coro_rpc_client& client, std::string_view attachment) { + client.set_req_attachment(attachment); + rpc_result result = co_await client.call(); + if (result.has_value()) { + assert(result.get_resp_attachment()==attachment); + co_return std::move(result.release_resp_attachment()); + } + co_return ""; +} +``` + +默认情况下,rpc客户端发送请求/建立连接后会等待5秒,如果5秒后仍未收到响应,则会返回超时错误。 +用户也可以通过调用`call_for`函数自定义等待的时长。 + +```cpp +client.connect("127.0.0.1:9001", std::chrono::seconds{10}); +auto result = co_await client.call_for(std::chrono::seconds{10},1,2); +assert(result.value() == 3); +``` + +时长可以是任一的`std::chrono::duration`类型,常见的如`std::chrono::seconds`,`std::chrono::millseconds`。 +特别的,如果时长为0,代表该函数调用永远也不会超时。 + +## SSL支持 + +coro_rpc支持使用openssl对连接进行加密。在安装openssl并使用cmake find_package/fetch_content 将yalantinglibs导入到你的工程后,可以打开cmake选项`YLT_ENABLE_SSL=ON`启用ssl支持。或者,你也可以手动添加宏`YLT_ENABLE_SSL`并手动链接openssl。 + +当启用ssl支持后,用户可以调用`init_ssl`函数,然后再连接到服务器。这会使得客户端与服务器之间建立加密的链接。需要注意的是,coro_rpc服务端在编译时也必须启用ssl支持,并且在启动服务器之前也需要调用`init_ssl`方法来启用SSL支持。 + +```cpp +client.init_ssl("./","server.crt"); +``` + +第一个字符串代表SSL证书所在的基本路径,第二个字符串代表SSL证书相对于基本路径的相对路径。 + +当建立连接时,客户端会使用该证书校验服务端发来的证书,以避免中间人攻击。因此,客户端必须持有服务端使用的证书或其根证书。 + +## RPC参数的转换与编译期检查 + +coro_rpc会在调用的时候对参数的合法性做编译期检查,比如,对于如下rpc函数: + +```cpp +inline std::string echo(std::string str) { return str; } +``` + +接下来,当前client调用rpc函数时: + +```cpp +client.call(42);// The argument does not match, a compilation error occurs. +client.call();// Missing argument, compilation error occurs. +client.call("", 0);// There are too many arguments, a compilation error occurs. +client.call("hello, coro_rpc");// The string literal can be converted to std::string, compilation succeeds. +``` + +## 连接选项 + +coro_rpc_client提供了`init_config`函数,用于配置连接选项。下面这份代码会列出可配置的选项。 + +```cpp +using namespace coro_rpc; +using namespace std::chrono; +void set_config(coro_rpc_client& client) { + client.init_config(config{ + .timeout_duration = 5s //请求和连接的超时时间 + .host = "localhost" // 服务器域名 + .port = "9001" // 服务器端口 + .enable_tcp_no_delay = true //是否禁止socket底层延迟发送请求 + /*以下选项只在激活ssl支持后可用*/ + .ssl_cert_path = "./server.crt" //ssl证书路径 + .ssl_domain = "localhost" + }); +} +``` + +## 调用模型 + +每一个`coro_rpc_client`都会绑定到某个IO线程上,默认通过轮转法从全局IO线程池中选择一个连接,用户也可以手动绑定到特定的IO线程上。 + +```cpp +auto executor=coro_io::get_global_executor(); +coro_rpc_client client(executor),client2(executor); +// 两个客户端都被绑定到同一个io线程上 +``` + +每次发起一个基于协程的IO任务(如`connect`,`call`,`send_request`),客户端内部会将IO事件提交给操作系统,当IO事件完成后,再将协程恢复到绑定的IO线程上继续执行。 + +例如以下代码,调用connect之后任务将切换到IO线程执行。 + +```cpp +/*run in thread 1*/ +coro_rpc_client cli; +co_await cli.connect("localhost:9001"); +/*run in thread 2*/ +do_something(); +``` + +## 连接池与负载均衡 + +`coro_io`提供了连接池`client_pool`与负载均衡器`channel`。用户可以通过连接池`client_pool`来管理`coro_rpc`/`coro_http`连接,可以使用`channel`实现多个host之间的负载均衡。具体请见`coro_io`的文档。 + +## 连接复用 + +`coro_rpc_client` 可以通过 `send_request`函数实现连接复用。该函数是线程安全的,允许多个线程同时调用同一个client的 `send_request`方法。该函数返回值为`Lazy`。第一次`co_await`可以等待请求发送,再次`co_await`则等待rpc返回结果。 + + +连接复用允许我们在高并发下减少连接的个数,无需创建新的连接。同时也能提高每个连接的吞吐量。 + +下面是一段简单的示例代码: + +```cpp +using namespace coro_rpc; +using namespace async_simple::coro; +std::string_view echo(std::string_view); +Lazy example(coro_rpc_client& client) { + //先等待请求发送完毕 + Lazy handler = co_await client.send_request("Hello"); + //然后等待服务器返回rpc请求结果 + async_rpc_result result = co_await handler; + if (result) { + assert(result->result() == "Hello"); + } + else { + // error handle + std::cout< example(coro_rpc_client& client) { + std::vector> handlers; + //首先连续发送10个请求 + for (int i=0;i<10;++i) { + handlers.push_back(co_await client.send_request(std::to_string(i))); + } + //接下来等待所有的请求返回 + std::vector results = co_await collectAll(std::move(handlers)); + for (int i=0;i<10;++i) { + assert(results[i]->result() == std::to_string(i)); + } + co_return; +} +``` + +### Attachment + +使用`send_request`方法时,由于可能同时发送多个请求,因此我们不能调用`set_req_attachment`方法向服务器发送attachment,同样也不能调用`get_resp_attachment`和`release_resp_attachment`方法来获取服务器返回的attachment。 + +我们可以通过调用`send_request_with_attachment`函数,在发送请求时设置attachment。我们也可以通过调用async_rpc_result的`->get_attachment()`方法和`->release_buffer()`方法来获取attachment。 + +```cpp +using namespace coro_rpc; +using namespace async_simple::coro; +int add(int a, int b); +Lazy example(coro_rpc_client& client) { + async_rpc_result result = co_await co_await client.send_request_with_attachment("Hello", 1, 2); + assert(result->result() == 3); + assert(result->get_attachment() == "Hello"); + co_return std::move(result->release_buffer().resp_attachment_buf_); +} +``` + + +### 执行顺序 + +当调用的rpc函数是协程rpc函数或回调rpc函数时,rpc请求不一定会按顺序执行,服务端可能会同时执行多个rpc请求。 + +例如,假如有以下代码: + +```cpp +using namespace async_simple::coro; +Lazy sleep(int seconds) { + co_await coro_io::sleep(1s * seconds); // 在此处让出协程 + co_return; +} +``` + +服务器注册并启动: +```cpp +using namespace coro_rpc; +void start() { + coro_rpc_server server(/* thread = */1,/* port = */ 8801); + server.register_handler(); + server.start(); +} +``` + +客户端连续在同一个连接上调用两次sleep函数,第一次sleep2秒,第二次sleep1秒。 +```cpp +using namespace async_simple::coro; +using namespace coro_rpc; +Lazy call() { + coro_rpc_client cli,cli2; + co_await cli.connect("localhost:8801"); + co_await cli2.connect("localhost:8801"); + auto handler1 = co_await cli.send_request(2); + auto handler2 = co_await cli.send_request(1); + auto handler3 = co_await cli2.send_request(0); + handler2.start([](auto&&){ + std::cout<<"handler2 return"< +using namespace coro_rpc; + int main() { // 初始化服务器 @@ -46,10 +48,12 @@ rpc_client端 #include "rpc_service.hpp" #include +using namespace coro_rpc; +using namespace async_simple::coro; + Lazy test_client() { coro_rpc_client client; co_await client.connect("localhost", /*port =*/"9000"); - auto r = co_await client.call("hello coro_rpc"); //传参数调用rpc函数 std::cout << r.result.value() << "\n"; //will print "hello coro_rpc" } @@ -64,84 +68,6 @@ client调用rpc函数也同样简单,5,6行代码就可以实现rpc调用了 相信上面的这个简单的例子已经充分展示了coro_rpc的易用性和特点了,也体现了rpc的本质,即用户可以像调用本地函数那样调用远程函数,用户只需要关注rpc函数的业务逻辑即可。 -coro_rpc的接口易用性还体现在rpc函数几乎没有任何限制,rpc函数可以拥有任意多个参数,参数的序列化和反序列化由rpc库自动完成,用户无需关心。rpc库支持的参数类型相当广泛详见:[struct_pack的类型系统](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_type_system.html) - -## rpc函数支持任意参数 - -```cpp -// rpc_service.h -// 客户端只需要包含这个头文件即可,无需把rpc的定义暴露给客户端。 -void hello(){}; -int get_value(int a, int b){return a + b;} - -struct person { - int id; - std::string name; - int age; -}; -person get_person(person p, int id); - -struct dummy { - std::string echo(std::string str) { return str; } -}; - -// rpc_service.cpp -#include "rpc_service.h" - -int get_value(int a, int b){return a + b;} - -person get_person(person p, int id) { - p.id = id; - return p; -} -``` - -server端 - -```cpp -#include "rpc_service.h" -#include - -int main() { - - coro_rpc_server server(/*thread_num =*/10, /*port =*/9000); - - server.register_handler();//注册任意参数类型的普通函数 - - dummy d{}; - server.register_handler<&dummy::echo>(&d); //注册成员函数 - - server.start(); // 启动server -} -``` - -client端 - -```cpp -# include "rpc_service.h" -# include - -Lazy test_client() { - coro_rpc_client client; - co_await client.connect("localhost", /*port =*/"9000"); - - //RPC调用 - co_await client.call(); - co_await client.call(1, 2); - - person p{}; - co_await client.call(p, /*id =*/1); - - auto r = co_await client.call<&dummy::echo>("hello coro_rpc"); - std::cout << r.result.value() << "\n"; //will print "hello coro_rpc" -} - -int main() { - syncAwait(test_client()); -} -``` - -这里面get_person函数的参数和返回值都是结构体,通过编译期反射的序列化库[struct_pack](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_intro.html)实现自动的序列化和反序列化,用户无感知,省心省力。 # 和grpc、brpc比较易用性 @@ -259,93 +185,33 @@ example::EchoService_Stub stub(&channel); } ``` -coro_rpc协程 - +coro_rpc协程 +客户端: ```cpp -# include - +std::string_view echo(std::string_view); +#include Lazy say_hello(){ coro_rpc_client client; - co_await client.connect("localhost", /*port =*/"9000"); + co_await client.connect("localhost", /*port =*/"9000"); while (true){ auto r = co_await client.call("hello coro_rpc"); assert(r.result.value() == "hello coro_rpc"); } } ``` - -coro_rpc的一大特色就是支持无栈协程,让用户以同步方式编写异步代码,简洁易懂! - -# coro_rpc更多特色 - -## 同时支持实时任务和延时任务 - -前面展示的例子里没有看到如何将rpc函数的结果response到客户端,因为默认情况下coro_rpc框架会帮助用户自动的将rpc函数的结果自动序列化并发送到客户端,让用户完全无感知,只需要专注于业务逻辑。需要说明的是这种场景下,rpc函数的业务逻辑是在io线程中执行的,这适合对于实时性要求较高的场景下使用,缺点是会阻塞IO线程。如果用户不希望在io线程中去执行业务逻辑,而是放到线程或线程池中去执行并延迟发送消息该怎么做呢? - -coro_rpc已经考虑到了这个问题,coro_rpc认为rpc任务分为实时任务和延时的任务,实时任务在io线程中执行完成后立即发送给客户端,实时性最好,延时最低;延时任务则可以放到独立线程中执行,延时处理,在未来某个时刻再将结果发送给客户端;coro_rpc同时支持这两种任务。 - -将之前实时任务改成延时任务 - +服务端: ```cpp -#include - -//实时任务,io线程中实时处理和发送结果 -std::string echo(std::string str) { return str; } - -//延时任务,在另外的独立线程中处理并发送结果 -void delay_echo(coro_rpc::context conn, std::string str) { - std::thread([conn, str]{ - conn.response_msg(str); //在独立线程中发送rpc结果 - }).detach(); +std::string_view echo(std::string_view sv) { + return sv; } -``` - -## 服务端同时支持协程和异步回调 - -coro_rpc server推荐使用协程去开发,但同时也支持异步回调模式,用户如果不希望使用协程,则可以使用经典的异步回调模式。 - -基于协程的rpc server - -```cpp -#include -std::string hello() { return "hello coro_rpc"; } - -int main() { - coro_rpc_server server(/*thread_num =*/10, /*port =*/9000); - server.register_handler(); - +void start() { + coro_rpc_server server(/*thread num = */10,/* listen port = */9000); + server.register_handler(); server.start(); } ``` -基于异步回调的rpc server - -```cpp -#include -std::string hello() { return "hello coro_rpc"; } - -int main() { - async_rpc_server server(/*thread_num =*/10, /*port =*/9000); - server.register_handler(); - server.start(); -} -``` - -rpc调用编译期安全检查 -coro_rpc会在调用的时候对参数的合法性做编译期检查,比如: - -```cpp -inline std::string echo(std::string str) { return str; } -``` - -client调用rpc - -```cpp -client.call(42);//参数不匹配,编译报错 -client.call();//缺少参数,编译报错 -client.call("", 0);//多了参数,编译报错 -client.call("hello, coro_rpc");//参数匹配,ok -``` +coro_rpc的一大特色就是支持无栈协程,让用户以同步方式编写异步代码,简洁易懂! # benchmark diff --git a/website/docs/zh/coro_rpc/coro_rpc_server.md b/website/docs/zh/coro_rpc/coro_rpc_server.md new file mode 100644 index 000000000..3400c17c1 --- /dev/null +++ b/website/docs/zh/coro_rpc/coro_rpc_server.md @@ -0,0 +1,431 @@ +# coro_rpc服务端介绍 + +## 服务器的注册与启动 + +### 函数注册 +在启动rpc服务器之前,我们需要调用`register_handler<>`函数注册所有的rpc函数。注册不是线程安全的,不能在启动rpc服务器后再注册。 + +```cpp +void hello(); +Lazy echo(std::string_view); +int add(int a, int b); +int regist_rpc_funtion(coro_rpc_server& server) { + server.register_handler(); +} +``` + +### 启动服务器 + +我们可以通过调用`.start()`方法,启动一个服务器,这会阻塞当前线程直到服务器退出为止。 +```cpp +int start_server() { + coro_rpc_server server; + regist_rpc_funtion(server); + coro_rpc::err_code ec = server.start(); + /*block util server down*/ +} +``` + +如果不想阻塞当前线程,我们也允许通过`async_start()`异步启动一个服务器,该函数返回后,保证服务器已经开始监听端口(或发生错误)。用户可以通过检查`async_simple::Future::hasResult()`来判断服务器当前是否启动成功并正常运行。调用`async_simple::Future::get()`方法则可以等待服务器停止。 + +```cpp +int start_server() { + coro_rpc_server server; + regist_rpc_funtion(server); + async_simple::Future ec = server.async_start(); /*won't block here */ + assert(!ec.hasResult()) /* check if server start success */ + auto err = ec.get(); /*block here util server down then return err code*/ +} +``` + +coro_rpc支持注册并调用的rpc函数有三种: +1. 普通函数 +2. 协程函数 +3. 回调函数 + +## 普通rpc函数 + +如果一个函数既不是协程,同时函数的第一个参数也不是`coro_rpc::context`类型,那么这个rpc函数就是一个普通函数。 + +例如,以下函数都是普通函数: + +```cpp +int add(int a, int b); +std::string_view echo(std::string_view str); +struct dummy { + std::string_view echo(std::string_view str) { return str; } +}; +``` + +### 调用模型 + +普通函数一定是同步执行的。当某个连接发来一个普通函数请求时,服务器会在该连接绑定的IO线程上执行该函数,直到函数执行完毕,然后向客户端返回结果,随后才会处理该连接的下一个请求。例如,客户端按顺序发送了两个请求A和B,则我们保证B一定在A之后执行。 + +需要注意的是,如果在函数内执行长时间的耗时操作,不但会阻塞当前连接,还有可能会阻塞其他被绑定到该IO线程上的连接。因此,在对性能有较高要求的场景中,不应该注册过于耗时的普通函数。可以考虑使用协程函数或回调函数来代替。 + +### 获取上下文信息 + +当函数被coro_rpc_server调用时,可以用下面代码来获取连接的上下文信息。 + +```cpp +using namespace coro_rpc; +void test() { + context_info_t* ctx = coro_rpc::get_context(); + if (ctx->has_closed()) { //检查连接是否被关闭 + throw std::runtime_error("connection is close!"); + } + //获取连接ID和请求ID + ELOGV(INFO, "call function echo_with_attachment, conn ID:%d, request ID:%d", + ctx->get_connection_id(), ctx->get_request_id()); + //获取客户端的ip和端口与服务端的ip和端口 + ELOGI << "remote endpoint: " << ctx->get_remote_endpoint() << "local endpoint" + << ctx->get_local_endpoint(); + //获取rpc函数名 + ELOGI << "rpc function name:" << ctx->get_rpc_function_name(); + //获取请求attachment + std::string_view sv{ctx->get_request_attachment()}; + //释放请求attachment + std::string str = ctx->release_request_attachment(); + //设置响应attachment + ctx->set_response_attachment(std::move(str)); +} +``` + +An attachment is an additional piece of data that comes with an RPC request. Coro_rpc does not serialize it, allowing users to obtain a view of the attachment that accompanies the request, or to release it from the context and move it separately. Similarly, users can also set the attachment to be sent back to the RPC client. + +### 错误处理 + +我们允许通过抛出`coro_rpc::rpc_error`异常的方式来终止rpc调用,并将rpc错误码和错误信息返回给用户。 + +```cpp +void rpc() { + throw coro_rpc::rpc_error{coro_rpc::errc::io_error}; // 返回自定义错误码 + throw coro_rpc::rpc_error{10404}; // 返回自定义错误码 + throw coro_rpc::rpc_error{10404,"404 Not Found"}; // 返回自定义错误码和错误消息 +} +``` + +rpc错误码是一个16位的无符号整数。其中,0-255是保留给rpc框架使用的错误码,用户自定义的错误码可以是[256,65535]之间的任一整数。当rpc返回用户自定义错误码时,连接不会断开。如果返回的是rpc框架自带的错误码,则视为发生了严重的rpc错误,会导致rpc连接断开。 + + +## 协程rpc函数 + +如果一个rpc函数,其返回值类型是`async_simple::coro::Lazy`,则我们该函数是协程函数。相比普通函数,协程函数是异步的,它可以在等待事件完成的时候暂时让出IO线程,从而提高并发性能。 + +例如,下面这个rpc函数,通过协程,将重计算任务提交到全局线程池,从而避免阻塞当前I/O线程。 + +```cpp +using namespace async_simple::coro; +int heavy_calculate(int value); +Lazy calculate(int value) { + auto val = co_await coro_io::post([value](){return heavy_calculate(value);}); //将任务提交到全局线程池执行,让出当前IO线程,直到任务完成。 + co_return val; +} +``` +用户也可以使用`async_simple::Promise`将任务提交到自定义线程池: + +```cpp +using namespace async_simple::coro; +void heavy_calculate(int value); +Lazy calculate(int value) { + async_simple::Promise p; + std::thread th([&p,value](){ + auto ret = heavy_calculate(value); + p.setValue(ret); //任务已完成,唤醒rpc函数 + }); + th.detach(); + auto ret = co_await p.get_future(); //等待任务完成 + co_return ret; +} +``` + +### 调用模型 + +当某个连接发来一个协程函数请求时,服务器会在该连接绑定的IO线程上启动一个新的协程,在新的协程上执行该函数。当协程函数执行完毕后,根据其返回值将rpc结果返回给客户端。如果协程在执行的过程中暂停让出,则该IO线程就会继续执行其他的任务(如处理下一个请求,又例如处理其他绑定在该IO线程上的连接)。 + +例如,假定有以下代码: + +```cpp +using namespace async_simple::coro; +Lazy sleep(int seconds) { + co_await coro_io::sleep(1s * seconds); //在此处让出协程 + co_return; +} +``` + +服务器注册并启动: +```cpp +using namespace coro_rpc; +void start() { + coro_rpc_server server(/* thread = */1,/* port = */ 8801); + server.register_handler(); + server.start(); +} +``` + +客户端连续在同一个连接上调用两次sleep函数,第一次sleep2秒,第二次sleep1秒。 +```cpp +using namespace async_simple::coro; +using namespace coro_rpc; +Lazy call() { + coro_rpc_client cli,cli2; + co_await cli.connect("localhost:8801"); + co_await cli2.connect("localhost:8801"); + auto handler1 = co_await cli.send_request(2); + auto handler2 = co_await cli.send_request(1); + auto handler3 = co_await cli2.send_request(0); + handler2.start([](auto&&){ + std::cout<<"handler2 return"< test() { + context_info_t* ctx = co_await coro_rpc::get_context_in_coro(); +} +``` + +### 错误处理 + +和普通函数相同,我们可以通过抛出`coro_rpc::rpc_error`异常的方式返回rpc错误,允许自定义rpc错误码和错误信息。 + + +## 回调rpc函数 + +我们同样支持更为传统的回调函数来实现异步RPC调用。回调函数的写法如下: +```cpp +void echo(coro_rpc::context, std::string_view param); +``` + +如果一个函数的返回值是void类型,并且第一个参数是`coro_rpc::context`类型,那么这个函数就是回调函数。`coro_rpc::context`类似于一个智能指针,持有本次rpc调用的回调句柄和上下文信息。 + +例如,在下面的代码中,我们将`coro_rpc::context`拷贝到另外一个线程,该线程睡眠30秒后再通过调用`coro_rpc::context::response_msg()`将结果返回给rpc客户端。 + +```cpp +using namespace std::chrono; +void echo(coro_rpc::context ctx, std::string_view param) { + std::thread th([ctx, param](){ + std::this_thread::sleep_for(30s); + ctx.response_msg(param); + }); + return; +} +``` + +需要说明的是,rpc函数参数中的std::string_view,std::span等视图类型,其指向的内容,会在本次rpc调用的`coro_rpc::context`对象的拷贝副本全部被析构后失效。 + +### 调用模型 + +当某个连接发来一个回调函数请求时,分配给该连接的IO线程会立即执行该函数,直到该函数执行完毕。随后处理其他请求。由于回调函数没有返回值,因此rpc函数执行完毕后服务器不会立即回复客户端。 + +当用户调用回调函数`coro_rpc::context::response_msg()`或`coro_rpc::context::response_error()`后,rpc服务器会接收到通知,此时才会将结果发送给客户端。因此用户必须保证在代码的某个位置主动调用回调函数。 + + +### 获取上下文信息 + +在回调函数中,我们可以调用`coro_rpc::context::get_context_info()`来获取协程的上下文信息。此外,在rpc函数返回之前也可以使用`coro_io::get_context()`获取上下文信息。但是当rpc函数返回以后,通过`coro_io::get_context()`指向的上下文信息可能会被修改或变得无效,因此我们还是建议使用`coro_rpc::context::get_context_info()`来获取上下文信息。 + +```cpp +void echo(coro_rpc::context ctx) { + context_info_t* info = ctx.get_context_info(); + return; +} +``` + +### 错误处理 + +在回调函数中,不应该也不能通过抛出异常的形式来返回rpc错误,因为错误可能不会发生在rpc函数的调用栈中。 + +作为代替,我们可以调用`coro_rpc::context::response_error()`函数来返回rpc错误。 + +```cpp +void echo(coro_rpc::context ctx) { + ctx.response_error(10015); //自定义rpc错误码 + ctx.response_error(10015, "my error msg"); //自定义rpc错误码和错误消息 + ctx.response_error(coro_rpc::errc::io_error); //使用rpc框架自带的错误码 + return; +} +``` + +rpc错误码是一个16位的无符号整数。其中,0-255是保留给rpc框架使用的错误码,用户自定义的错误码可以是[256,65535]之间的任一整数。当rpc返回用户自定义错误码时,连接不会断开。如果返回的是rpc框架自带的错误码,则视为发生了严重的rpc错误,会导致rpc连接断开。 + +## 连接与IO线程 + +服务器内部有一个IO线程池,其大小默认为cpu的逻辑线程数目。当服务器启动后,它会在某个IO线程上启动一个监听任务,接收客户端发来的连接。每次接收连接时,服务器会通过轮转法,选择一个IO线程将其绑定到连接上。随后,该连接上各请求收发数据,序列化,rpc路由等步骤都会在该IO线程上执行。rpc函数也同样会在该IO线程上执行。 + +这意味着,如果你的rpc函数会阻塞当前线程(例如线程sleep,同步读写文件),那么最好通过异步化来避免阻塞io线程,从而避免阻塞其他请求。例如,`async_simple::coro`提供了协程锁`Mutex`和`Spinlock`,提供了将异步任务包装为协程任务的`Promise`和`Future`组件。`coro_io`提供了基于协程的异步文件读写,socket的异步读写,`sleep`和定时器`period_timer`,还可通过`coro_io::post`将重CPU任务提交给全局的阻塞任务线程池。`coro_rpc`/`coro_http`提供了基于协程的异步rpc调用和http调用。`easylog`默认会将日志内容提交给后台线程写入,从而保证前台不阻塞。 + + + +## 参数与返回值类型 + +coro_rpc允许用户注册的rpc函数具有多个参数(最多64个),参数和返回值的类型可以是用户自定义的聚合结构体,也支持了各种c++标准库提供的数据结构和许多第三方库提供的数据结构。详见:[struct_pack的类型系统](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_type_system.html) + +如果你的rpc参数或返回值类型不属于struct_pack的类型系统支持的类型,我们也允许用户注册自己的结构体或者自定义序列化算法,详见:[自定义功能支持](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_intro.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96) + +## RPC返回值的构造与检查 + +此外,对于回调函数,coro_rpc会尝试通过参数列表构造返回值类型。如果无法构造则会导致编译失败。 + +```cpp +void echo(coro_rpc::context ctx) { + ctx.response_msg(); //无法构造std::string。编译失败。 + ctx.response_msg(42); //无法构造std::string。编译失败。 + ctx.response_msg(42,'A'); //可以构造std::string,编译通过。 + ctx.response_msg("Hello"); //可以构造std::string,编译通过。 + return; +} +``` + +## SSL支持 + +coro_rpc支持使用openssl对连接进行加密。在安装openssl并使用cmake find_package/fetch_content 将yalantinglibs导入到你的工程后,可以打开cmake选项`YLT_ENABLE_SSL=ON`启用ssl支持。或者,你也可以手动添加宏`YLT_ENABLE_SSL`并手动链接openssl。 + +当启用ssl支持后,用户可以调用`init_ssl`函数,然后再连接到服务器。这会使得客户端与服务器之间建立加密的链接。需要注意的是,coro_rpc服务端在编译时也必须启用ssl支持。 + +```cpp +coro_rpc_server server; +server.init_ssl({ + .base_path = "./", // ssl文件的基本路径 + .cert_file = "server.crt", // 证书相对于base_path的路径 + .key_file = "server.key" // 私钥相对于base_path的路径 +}); +``` + +启用ssl支持后,服务器将拒绝一切非ssl连接。 + +## 高级设置 + +我们提供了coro_rpc::config_t类,用户可以通过该类型设置server的细节: + +```cpp +struct config_base { + bool is_enable_tcp_no_delay = true; /*tcp请求是否立即响应*/ + uint16_t port = 9001; /*监听端口*/ + unsigned thread_num = std::thread::hardware_concurrency(); /*rpc server内部使用的连接数,默认为逻辑核数*/ + std::chrono::steady_clock::duration conn_timeout_duration = + std::chrono::seconds{0}; /*rpc请求的超时时间,0秒代表rpc请求不会自动超时*/ + std::string address="0.0.0.0"; /*监听地址*/ + /*下面设置只有启用SSL才有*/ + std::optional ssl_config = std::nullopt; // 配置是否启用ssl +}; +struct ssl_configure { + std::string base_path; // ssl文件的基本路径 + std::string cert_file; // 证书相对于base_path的路径 + std::string key_file; // 私钥相对于base_path的路径 + std::string dh_file; // dh_file相对于base_path的路径(可选) +} +int start() { + coro_rpc::config_t config{}; + coro_rpc_server server(config); + /*regist rpc function here... */ + server.start(); +} +``` + + +## 特殊rpc函数的注册与调用 + +### 成员函数的注册与调用 + +coro_rpc支持注册并调用成员函数: + +例如,假如有以下函数: + +```cpp +struct dummy { + std::string_view echo(std::string_view str) { return str; } + Lazy coroutine_echo(std::string_view str) {co_return str;} + void callback_echo(coro_rpc::context ctx, std::string_view str) { + ctx.response_msg(str); + } +}; +``` + +则服务端可以这样注册这些函数。 + +```cpp +#include "rpc_service.h" +#include +int main() { + coro_rpc_server server; + dummy d{}; + server.register_handler<&dummy::echo,&dummy::coroutine_echo,&dummy::callback_echo>(&d); // 注册成员函数 + server.start(); +} +``` + +需要注意的时,必须注意被注册的dummy类型的生命周期,保证在服务器启动时dummy始终存活。否则调用行为是未定义的。 + +客户端可以这样调用这些函数: + +```cpp +#include "rpc_service.h" +#include + +Lazy test_client() { + coro_rpc_client client; + co_await client.connect("localhost", /*port =*/"9000"); + + //RPC调用 + { + auto result = co_await client.call<&dummy::echo>("hello"); + assert(result.value() == "hello"); + } + { + auto result = co_await client.call<&dummy::coroutine_echo>("hello"); + assert(result.value() == "hello"); + } + { + auto result = co_await client.call<&dummy::callback_echo>("hello"); + assert(result.value() == "hello"); + } +} +``` + +### 特化的模板函数 + +coro_rpc允许用户注册并调用特化的模板函数。 + +例如,假如有以下函数: + +```cpp +template +T echo(T param) { return param; } +``` + +则服务端可以这样注册这些函数。 + +```cpp +#include +using namespace coro_rpc; +int main() { + coro_rpc_server server; + server.register_handler,echo,echo>>(&d); // 注册特化的模板函数 + server.start(); +} +``` + +客户端可以这样调用: +```cpp +using namespace coro_rpc; +using namespace async_simple::coro; +Lazy rpc_call(coro_rpc_client& cli) { + assert(co_await cli.call>(42).value() == 42); + assert(co_await cli.call>("Hello").value() == "Hello"); + assert(co_await cli.call>(std::vector{1,2,3}).value() == std::vector{1,2,3}); +} +``` \ No newline at end of file From 85a0d70bf50ef87e368cc06eea105dc33e5a428f Mon Sep 17 00:00:00 2001 From: saipubw Date: Fri, 24 May 2024 11:25:26 +0800 Subject: [PATCH 05/12] [no ci] fix doc (#682) --- website/docs/en/coro_rpc/coro_rpc_client.md | 8 ++++---- website/generate.sh | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/website/docs/en/coro_rpc/coro_rpc_client.md b/website/docs/en/coro_rpc/coro_rpc_client.md index 4b3daf5ac..46c1fc937 100644 --- a/website/docs/en/coro_rpc/coro_rpc_client.md +++ b/website/docs/en/coro_rpc/coro_rpc_client.md @@ -56,13 +56,13 @@ auto result = co_await client.call_for(std::chrono::seconds{10},1,2); assert(result.value() == 3); ``` -The duration can be any `std::chrono::duration`` type, common examples include `std::chrono::seconds`` and `std::chrono::milliseconds``. Notably, if the duration is set to zero, it indicates that the function call will never time out. +The duration can be any `std::chrono::duration` type, common examples include `std::chrono::seconds` and `std::chrono::milliseconds`. Notably, if the duration is set to zero, it indicates that the function call will never time out. ## SSL support coro_rpc supports using OpenSSL to encrypt connections. After installing OpenSSL and importing yalantinglibs into your project with CMake's `find_package` or `fetch_content`, you can enable SSL support by setting the CMake option YLT_ENABLE_SSL=ON. Alternatively, you might manually add the YLT_ENABLE_SSL macro and manually link to OpenSSL. -Once SSL support has been enabled, users can invoke the `init_ssl`` function before establishing a connection to the server. This will create an encrypted link between the client and the server. It’s important to note that the coro_rpc server must also be compiled with SSL support enabled, and the `init_ssl` method must be called to enable SSL support before starting the server. +Once SSL support has been enabled, users can invoke the `init_ssl` function before establishing a connection to the server. This will create an encrypted link between the client and the server. It’s important to note that the coro_rpc server must also be compiled with SSL support enabled, and the `init_ssl` method must be called to enable SSL support before starting the server. ```cpp client.init_ssl("./","server.crt"); @@ -90,7 +90,7 @@ client.call("hello, coro_rpc"); // The string literal can be converted to ## Connect Option -The `coro_rpc_client` provides an `init_config`` function for configuring connection options. The following code snippet lists the configurable options. +The `coro_rpc_client` provides an `init_config` function for configuring connection options. The following code snippet lists the configurable options. ```cpp using namespace coro_rpc; @@ -134,7 +134,7 @@ do_something(); ## Connection Reuse -The `coro_rpc_client` can achieve connection reuse through the `send_request`` function. This function is thread-safe, allowing multiple threads to call the `send_request` method on the same client concurrently. The return value of the function is `Lazy>>`. The first `co_await` waits for the request to be sent, and the second `co_await` waits for the rpc result to return. +The `coro_rpc_client` can achieve connection reuse through the `send_request` function. This function is thread-safe, allowing multiple threads to call the `send_request` method on the same client concurrently. The return value of the function is `Lazy>>`. The first `co_await` waits for the request to be sent, and the second `co_await` waits for the rpc result to return. Connection reuse allows us to reduce the number of connections under high concurrency, eliminating the need to create new connections. It also improves the throughput of each connection. diff --git a/website/generate.sh b/website/generate.sh index b061d298e..e6fc00e69 100755 --- a/website/generate.sh +++ b/website/generate.sh @@ -16,7 +16,6 @@ mkdir dist # Commands without errors : copy images from english to chinese dir set +e # Disable -e option temporarily cp -r docs/en/coro_rpc/images docs/zh/coro_rpc -cp -r docs/en/guide/images docs/zh/guide cp -r docs/en/struct_pack/images docs/zh/struct_pack cp -r docs/en/struct_pb/images docs/zh/struct_pb set -e # Re-enable -e option From ca8f1341bb023226c2689789c1feb7c40dab1e0b Mon Sep 17 00:00:00 2001 From: saipubw Date: Fri, 24 May 2024 11:52:15 +0800 Subject: [PATCH 06/12] [no ci] fix doc (#683) --- README.md | 6 +- .../docs/en/guide/what_is_yalantinglibs.md | 6 +- .../zh/coro_http/coro_http_introduction.md | 68 +++++++++---------- .../docs/zh/easylog/easylog_introduction.md | 10 +-- .../zh/struct_xxx/struct_xxx_introduction.md | 28 ++++---- 5 files changed, 59 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 33a8d9a04..e7a8bdaeb 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ void basic_usage() { coro_http is a C++20 coroutine http(https) library, include server and client, functions: get/post, websocket, multipart file upload, chunked and ranges download etc. [more examples](https://github.com/alibaba/yalantinglibs/blob/main/src/coro_http/examples/example.cpp) ### get/post -```c++ +```cpp #include "ylt/coro_http/coro_http_server.hpp" #include "ylt/coro_http/coro_http_client.hpp" using namespace coro_http; @@ -379,7 +379,7 @@ int main() { ``` ### websocket -```c++ +```cpp async_simple::coro::Lazy websocket(coro_http_client &client) { // connect to your websocket server. bool r = co_await client.async_connect("ws://example.com/ws"); @@ -401,7 +401,7 @@ async_simple::coro::Lazy websocket(coro_http_client &client) { ``` ### upload/download -```c++ +```cpp async_simple::coro::Lazy upload_files(coro_http_client &client) { std::string uri = "http://example.com"; diff --git a/website/docs/en/guide/what_is_yalantinglibs.md b/website/docs/en/guide/what_is_yalantinglibs.md index 1a0e6dd15..3c253e96f 100644 --- a/website/docs/en/guide/what_is_yalantinglibs.md +++ b/website/docs/en/guide/what_is_yalantinglibs.md @@ -332,7 +332,7 @@ void basic_usage() { coro_http is a C++20 coroutine http(https) library, include server and client, functions: get/post, websocket, multipart file upload, chunked and ranges download etc. [more examples](https://github.com/alibaba/yalantinglibs/blob/main/src/coro_http/examples/example.cpp) ### get/post -```c++ +```cpp #include "ylt/coro_http/coro_http_server.hpp" #include "ylt/coro_http/coro_http_client.hpp" using namespace coro_http; @@ -379,7 +379,7 @@ int main() { ``` ### websocket -```c++ +```cpp async_simple::coro::Lazy websocket(coro_http_client &client) { // connect to your websocket server. bool r = co_await client.async_connect("ws://example.com/ws"); @@ -401,7 +401,7 @@ async_simple::coro::Lazy websocket(coro_http_client &client) { ``` ### upload/download -```c++ +```cpp async_simple::coro::Lazy upload_files(coro_http_client &client) { std::string uri = "http://example.com"; diff --git a/website/docs/zh/coro_http/coro_http_introduction.md b/website/docs/zh/coro_http/coro_http_introduction.md index 20075a982..1211c656e 100644 --- a/website/docs/zh/coro_http/coro_http_introduction.md +++ b/website/docs/zh/coro_http/coro_http_introduction.md @@ -4,13 +4,13 @@ coro_http_cient 是yalantinglibgs 的子库,yalantinglibs 是header only的,下载yalantinglibgs 库之后,在自己的工程中包含目录: -```c++ +```cpp include_directories(include) include_directories(include/ylt/thirdparty) ``` 如果是gcc 编译器还需要设置以启用C++20 协程: -```c++ +```cpp if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines") #-ftree-slp-vectorize with coroutine cause link error. disable it util gcc fix. @@ -20,7 +20,7 @@ coro_http_cient 是yalantinglibgs 的子库,yalantinglibs 是header only的, 最后在你的工程里引用coro_http_client 的头文件即可: -```c++ +```cpp #include #include "ylt/coro_http/coro_http_client.hpp" @@ -41,7 +41,7 @@ int main() { ## http 同步请求 ### http 同步请求接口 -```c++ +```cpp /// http header /// \param name header 名称 /// \param value header 值 @@ -91,7 +91,7 @@ resp_data post(std::string uri, std::string content, ### http 同步请求的用法 简单的请求一个网站一行代码即可: -```c++ +```cpp coro_http_client client{}; auto result = client.get("http://www.example.com"); if(result.net_err) { @@ -105,7 +105,7 @@ if(result.status == 200) { ``` 请求返回之后需要检查是否有网络错误和状态码,如果都正常则可以处理获取的响应body和响应头了。 -```c++ +```cpp void test_sync_client() { { std::string uri = "http://www.baidu.com"; @@ -133,7 +133,7 @@ void test_sync_client() { ## http 异步请求接口 -```c++ +```cpp async_simple::coro::Lazy async_get(std::string uri); async_simple::coro::Lazy async_post( @@ -142,14 +142,14 @@ async_simple::coro::Lazy async_post( async_get和get 接口参数一样,async_post 和 post 接口参数一样,只是返回类型不同,同步接口返回的是一个普通的resp_data,而异步接口返回的是一个Lazy 协程对象。事实上,同步接口内部就是调用对应的协程接口,用法上接近,多了一个co_await 操作。 事实上你可以把任意异步协程接口通过syncAwait 方法同步阻塞调用的方式转换成同步接口,以同步接口get 为例: -```c++ +```cpp resp_data get(std::string uri) { return async_simple::coro::syncAwait(async_get(std::move(uri))); } ``` 同步请求例子: -```c++ +```cpp async_simple::coro::Lazy test_async_client() { std::string uri = "http://www.baidu.com"; @@ -174,7 +174,7 @@ option(CINATRA_ENABLE_SSL "Enable ssl support" OFF) ``` client 只需要调用init_ssl 方法即可,之后便可以和之前一样发起https 请求了。 -```c++ +```cpp const int verify_none = SSL_VERIFY_NONE; const int verify_peer = SSL_VERIFY_PEER; const int verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT; @@ -190,7 +190,7 @@ const int verify_client_once = SSL_VERIFY_CLIENT_ONCE; const std::string &sni_hostname = ""); ``` -```c++ +```cpp #ifdef CINATRA_ENABLE_SSL void test_coro_http_client() { coro_http_client client{}; @@ -217,7 +217,7 @@ void test_coro_http_client() { 如果host 已经通过请求连接成功之后,后面发请求的时候只传入path 而不用传入完整的路径,这样可以获得更好的性能,coro_http_client 对于已经连接的host,当传入path 的时候不会再重复去解析已经解析过的uri。 -```c++ +```cpp async_simple::coro::Lazy test_async_client() { std::string uri = "http://www.baidu.com"; @@ -241,7 +241,7 @@ async_simple::coro::Lazy test_async_client() { ## http 重连 当http 请求失败之后,这个http client是不允许复用的,因为内部的socket 都已经关闭了,除非你调用reconnect 去重连host,这样就可以复用http client 了。 -```c++ +```cpp coro_http_client client1{}; // 连接了一个非法的uri 会失败 r = async_simple::coro::syncAwait( @@ -257,7 +257,7 @@ async_simple::coro::Lazy test_async_client() { # 其它http 接口 http_method -```c++ +```cpp enum class http_method { UNKNOW, DEL, @@ -273,7 +273,7 @@ enum class http_method { ``` coro_http_client 提供了这些http_method 对应的请求接口: -```c++ +```cpp async_simple::coro::Lazy async_delete( std::string uri, std::string content, req_content_type content_type); @@ -302,7 +302,7 @@ async_simple::coro::Lazy async_trace(std::string uri); 除了http method 对应的接口之外,coro_http_client 还提供了常用文件上传和下载接口。 ## chunked 格式上传 -```c++ +```cpp template async_simple::coro::Lazy async_upload_chunked( S uri, http_method method, File file, @@ -317,7 +317,7 @@ chunked 每块的大小默认为1MB,如果希望修改分块大小可以通过 multipart 上传有两个接口,一个是一步实现上传,一个是分两步实现上传。 一步上传接口 -```c++ +```cpp async_simple::coro::Lazy async_upload_multipart( std::string uri, std::string name, std::string filename); ``` @@ -326,7 +326,7 @@ name 是multipart 里面的name 参数,filename 需要上传的带路径的文 一步上传接口适合纯粹上传文件用,如果要上传多个文件,或者既有字符串也有文件的场景,那就需要两步上传的接口。 两步上传接口 -```c++ +```cpp // 设置要上传的字符串key-value bool add_str_part(std::string name, std::string content); // 设置要上传的文件 @@ -337,7 +337,7 @@ async_simple::coro::Lazy async_upload_multipart(std::string uri); ``` 两步上传,第一步是准备要上传的字符串或者文件,第二步上传; -```c++ +```cpp std::string uri = "http://127.0.0.1:8090/multipart"; coro_http_client client{}; @@ -347,7 +347,7 @@ async_simple::coro::Lazy async_upload_multipart(std::string uri); ``` ## chunked 格式下载 -```c++ +```cpp async_simple::coro::Lazy async_download(std::string uri, std::string filename, std::string range = ""); @@ -356,7 +356,7 @@ async_simple::coro::Lazy async_download(std::string uri, ## ranges 格式下载 ranges 下载接口和chunked 下载接口相同,需要填写ranges: -```c++ +```cpp coro_http_client client{}; std::string uri = "http://uniquegoodshiningmelody.neverssl.com/favicon.ico"; @@ -379,7 +379,7 @@ ranges 按照"m-n,x-y,..." 的格式填写,下载的内容将会保存到文 # http client 配置项 client 配置项: -```c++ +```cpp struct config { // 连接超时时间,默认8 秒 std::optional conn_timeout_duration; @@ -413,7 +413,7 @@ client 配置项: ``` 把config项设置之后,调用init_config 设置http client 的参数。 -```c++ +```cpp coro_http_client client{}; coro_http_client::config conf{.req_timeout_duration = 60s}; client.init_config(conf); @@ -427,15 +427,15 @@ websocket 的支持需要3步: - 读websocket 数据; websocket 读数据接口: -```c++ +```cpp async_simple::coro::Lazy read_websocket(); ``` websocket 连接服务器接口: -```c++ +```cpp async_simple::coro::Lazy connect(std::string uri); ``` websocket 发送数据接口: -```c++ +```cpp enum opcode : std::uint8_t { cont = 0, text = 1, @@ -464,7 +464,7 @@ async_simple::coro::Lazy write_websocket(std::string msg, websocket 例子: -```c++ +```cpp coro_http_client client; // 连接websocket 服务器 async_simple::coro::syncAwait( @@ -495,7 +495,7 @@ client 不是线程安全的,要确保只有一个线程在调用client,如 通过多个协程去请求服务端, 每个协程都在内部线程池的某个线程中执行。去请求服务端 -```c++ +```cpp std::vector> clients; std::vector> futures; for (int i = 0; i < 10; ++i) { @@ -514,7 +514,7 @@ for (auto &item : out) { ## 设置解析http response 的最大header 数量 默认情况下,最多可以解析100 个http header,如果希望解析更多http header 需要define一个宏CINATRA_MAX_HTTP_HEADER_FIELD_SIZE,通过它来设置解析的最大header 数, 在include client 头文件之前定义: -```c++ +```cpp #define CINATRA_MAX_HTTP_HEADER_FIELD_SIZE 200 // 将解析的最大header 数设置为200 ``` @@ -535,7 +535,7 @@ cmake -DENABLE_SIMD=AARCH64 .. # arm环境下,启用neon指令集 ### 快速示例 ### 示例1:一个简单的hello world -```c++ +```cpp #include "ylt/coro_http/coro_http_client.hpp" #include "ylt/coro_http/coro_http_server.hpp" using namespace coro_http; @@ -555,7 +555,7 @@ cmake -DENABLE_SIMD=AARCH64 .. # arm环境下,启用neon指令集 5行代码就可以实现一个简单http服务器了,用户不需要关注多少细节,直接写业务逻辑就行了。 ### 示例2:基本用法 -```c++ +```cpp #include "ylt/coro_http/coro_http_client.hpp" #include "ylt/coro_http/coro_http_server.hpp" using namespace coro_http; @@ -675,7 +675,7 @@ int main() { ``` ### 示例3:面向切面的http服务器 -```c++ +```cpp #include "ylt/coro_http/coro_http_client.hpp" #include "ylt/coro_http/coro_http_server.hpp" using namespace coro_http; @@ -743,7 +743,7 @@ int main() { 同时还支持任意字符的RESTful API,即示例的第二种RESTful API`"/string/:id/test/:name"`,要获取到对应的参数使用`req.get_query_value`函数即可,其参数只能为注册的变量(如果不为依然运行但是有报错),例子中参数名是id和name,要获取id参数调用`req.get_query_value("id")`即可。示例代码运行后,当访问`http://127.0.0.1:8080/string/params_1/test/api_test`时,浏览器会返回`api_test`字符串。 -```c++ +```cpp #include "ylt/coro_http/coro_http_client.hpp" #include "ylt/coro_http/coro_http_server.hpp" using namespace coro_http; @@ -777,7 +777,7 @@ int main() { 目前支持random, round robin 和 weight round robin三种负载均衡三种算法,设置代理服务器时指定算法类型即可。 假设需要代理的服务器有三个,分别是"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003",coro_http_server设置路径、代理服务器列表和算法类型即可实现反向代理。 - ```c++ + ```cpp void http_proxy() { cinatra::coro_http_server web_one(1, 9001); diff --git a/website/docs/zh/easylog/easylog_introduction.md b/website/docs/zh/easylog/easylog_introduction.md index f79a7aac1..9c871d839 100644 --- a/website/docs/zh/easylog/easylog_introduction.md +++ b/website/docs/zh/easylog/easylog_introduction.md @@ -15,7 +15,7 @@ easylog 是C++17 实现的高性能易用的 header only 日志库,它支持 # 基本用法 -```c++ +```cpp // 流式输出 ELOG_INFO << "easylog " << 42; ELOG(INFO) << "easylog " << 42; @@ -32,7 +32,7 @@ ELOGV(INFO, "easylog %d", 42); 流式输出的ELOG_INFO 等价于ELOG(INFO)。 easylog 定义了如下日志级别: -```c++ +```cpp enum class Severity { NONE, TRACE, @@ -58,7 +58,7 @@ easylog 默认不会每次flush 日志,可以通过调用API ```easylog::flush # 输出到文件 easylog 默认会将日志输出到控制台,如果希望easylog 将日志输出到文件则需要调用easylog::init 接口做初始化。 -```c++ +```cpp /// \param Id 日志实例的唯一id,默认为0 /// \param min_severity 最低的日志级别 /// \param filename 日志文件名称 @@ -76,7 +76,7 @@ void init_log(Severity min_severity, const std::string &filename = "", 如果日志文件大小达到了max_file_size 旧的日志文件将会被覆盖,如果max_files 设置为1,当大小达到了max_file_size 时,日志文件会被覆盖。 -```c++ +```cpp easylog::init_log(Severity::DEBUG, filename, false, true, 5, 3); ELOG_INFO << "long string test, long string test"; ELOG_INFO << "long string test, long string test"; @@ -90,7 +90,7 @@ ELOG_INFO << "long string test, long string test"; 默认的日志实例只有一个,如果希望创建更多日志实例,则通过唯一的日志ID 来创建新的日志实例。 -```c++ +```cpp constexpr size_t Id = 2; easylog::init_log(Severity::DEBUG, "testlog.txt"); MELOG_INFO(Id) << "test"; diff --git a/website/docs/zh/struct_xxx/struct_xxx_introduction.md b/website/docs/zh/struct_xxx/struct_xxx_introduction.md index 9594d5740..7edb31020 100644 --- a/website/docs/zh/struct_xxx/struct_xxx_introduction.md +++ b/website/docs/zh/struct_xxx/struct_xxx_introduction.md @@ -13,7 +13,7 @@ include_directories(include/ylt/thirdparty) ``` 写代码的时候包含对应的头文件即可: -```c++ +```cpp #include "ylt/struct_json/json_reader.h" #include "ylt/struct_json/json_writer.h" ``` @@ -25,7 +25,7 @@ gcc9+、clang11+、msvc2019+ # json 序列化/反序列化 序列化需要先定义一个可反射的对象,通过REFLECTION 可以轻松定义一个可反射对象。 -```c++ +```cpp struct person { std::string_view name; @@ -35,7 +35,7 @@ REFLECTION(person, name, age); // 通过这个宏定义元数据让person 成为 ``` 通过REFLECTION 宏定义元数据之后就可以一行代码实现json 的序列化与反序列化了。 -```c++ +```cpp person p = { "tom", 28 }; std::string ss; @@ -54,7 +54,7 @@ assert(p1.name == "tom"); ## json 的dom 解析 json 解析也提供了dom 解析接口,使用parse 接口时,不需要定义json 对应的结构体。 -```c++ +```cpp std::string_view str = R"(false)"; struct_json::jvalue val; struct_json::parse(val, str.begin(), str.end()); @@ -73,7 +73,7 @@ CHECK(!b); # 最佳实践 ## 零拷贝的反序列化 通过零拷贝的反序列化,可以完全消除内存分配的开销。 -```c++ +```cpp struct some_obj { std::string_view name; struct_json::numeric_str age; @@ -109,7 +109,7 @@ void test_view(){ # xml 序列化/反序列化 和json 类似,先定义xml 数据对应的结构体,再通过to_xml/from_xml 实现序列化和反序列化。 -```c++ +```cpp struct some_obj { std::string_view name; int age; @@ -134,7 +134,7 @@ void test() { ``` ## pretty 格式化xml -```c++ +```cpp struct person { std::string_view name; int age; @@ -162,7 +162,7 @@ to_xml 模式输出的xml 字符串在一行,如果希望pretty 输出则传tr ## xml 属性解析 -```c++ +```cpp struct book_t { std::string title; std::string author; @@ -205,7 +205,7 @@ TEST_CASE("test library with attr") { # 字段别名 一般情况下序列化/反序列化要求定义的结构体字段和被解析字符串如xml 字符串中的标签名称一一对应,比如下面的例子: -```c++ +```cpp struct some_obj { std::string_view name; int age; @@ -228,7 +228,7 @@ xml 标签name 和 age 对应的就是结构体some_obj::name, some_obj::age, 有时候这个约束对于一些已经存在的结构体可能存在一些不便之处,已有的结构体字段名可能和xml 标签名字不相同,这时候可以通过字段别名来保证正确解析。 -```c++ +```cpp std::string xml_str = R"( @@ -261,7 +261,7 @@ REFLECTION_ALIAS 中需要填写结构体的别名和字段的别名,通过别 # 如何处理私有字段 如果类里面有私有字段,在外面定义REFLECTION 宏会出错,因为无法访问私有字段,这时候把宏定义到类里面即可,但要保证宏是public的。 -```c++ +```cpp class person { std::string name; int age; @@ -272,7 +272,7 @@ public: # yaml 序列化/反序列化 和json,xml 类似: -```c++ +```cpp enum class enum_status { start, stop, @@ -288,7 +288,7 @@ struct plain_type_t { REFLECTION(plain_type_t, isok, status, c, hasprice, num, price); ``` -```c++ +```cpp // deserialization the structure from the string std::string str = R"( isok: false @@ -310,7 +310,7 @@ std::cout << ss << "\n"; # 如何将enum 作为字符串处理 一般情况下enum 将按照int 去处理,如果希望将enum 按照字符串名称去处理,则需要定义enum_value来做适配。 -```c++ +```cpp enum class Status { STOP = 10, START }; struct enum_t { Status a; From 2e5396cbc8ba420537ae8c7855eb970d9c2bc4e1 Mon Sep 17 00:00:00 2001 From: saipubw Date: Fri, 24 May 2024 12:13:38 +0800 Subject: [PATCH 07/12] [no ci] fix doc (#684) --- .gitignore | 3 +++ website/.vitepress/config/en_data.ts | 4 +++- website/.vitepress/config/zh_data.ts | 2 ++ website/README.md | 2 +- website/docs/en/coro_rpc/coro_rpc_server.md | 6 +++--- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c205ec471..05c4269e5 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,6 @@ node_modules bazel-* !BUILD.bazel cdb.json + +# website +website/docs/zh/*/images/ diff --git a/website/.vitepress/config/en_data.ts b/website/.vitepress/config/en_data.ts index 5c8b04faa..76b640ecb 100644 --- a/website/.vitepress/config/en_data.ts +++ b/website/.vitepress/config/en_data.ts @@ -23,7 +23,9 @@ export const struct_pack_Links = [ ]; export const coro_rpc_Links = [ - {text: 'What is coro_rpc?', link: '/en/coro_rpc/coro_rpc_introduction'}, + {text: 'coro_rpc introduction', link: '/en/coro_rpc/coro_rpc_introduction'}, + {text: 'coro_rpc client', link: '/en/coro_rpc/coro_rpc_client'}, + {text: 'coro_rpc server', link: '/en/coro_rpc/coro_rpc_server'}, ]; export const aboutLinks = [ diff --git a/website/.vitepress/config/zh_data.ts b/website/.vitepress/config/zh_data.ts index 08b8ae81a..5ef2088f0 100644 --- a/website/.vitepress/config/zh_data.ts +++ b/website/.vitepress/config/zh_data.ts @@ -24,6 +24,8 @@ export const struct_pack_Links = [ export const coro_rpc_Links = [ { text: 'coro_rpc简介', link: '/zh/coro_rpc/coro_rpc_introduction' }, + { text: 'coro_rpc客户端介绍', link: '/zh/coro_rpc/coro_rpc_client' }, + { text: 'coro_rpc服务端介绍', link: '/zh/coro_rpc/coro_rpc_server' }, ]; export const easylog_Links = [ diff --git a/website/README.md b/website/README.md index cc631083d..50f08ed40 100644 --- a/website/README.md +++ b/website/README.md @@ -36,7 +36,7 @@ yarn install - generate website ``` -bash gen_doc.sh +bash generate.sh ``` the script will copy all markdown files and images to website folder diff --git a/website/docs/en/coro_rpc/coro_rpc_server.md b/website/docs/en/coro_rpc/coro_rpc_server.md index f18f646f4..9df46991d 100644 --- a/website/docs/en/coro_rpc/coro_rpc_server.md +++ b/website/docs/en/coro_rpc/coro_rpc_server.md @@ -126,7 +126,7 @@ Lazy calculate(int value) { } ``` -Users can also use async_simple::Promise to submit tasks to a custom thread pool: +Users can also use `async_simple::Promise` to submit tasks to a custom thread pool: ```cpp using namespace async_simple::coro; @@ -230,7 +230,7 @@ void echo(coro_rpc::context ctx, std::string_view param) { } ``` -It should be noted that view types in the RPC function parameters, such as std::string_view and std::span, will have their underlying data become invalid after all copies of the coro_rpc::context object for this RPC call are destructed. +It should be noted that view types in the RPC function parameters, such as std::string_view and std::span, will have their underlying data become invalid after all copies of the `coro_rpc::context` object for this RPC call are destructed. ### Calling Model @@ -252,7 +252,7 @@ void echo(coro_rpc::context ctx) { ### Error Handling -In callback functions, one should not and cannot return RPC errors by throwing exceptions, because the error might not occur within the call stack of the RPC function. Instead, we can use the coro_rpc::context::response_error() function to return RPC errors. +In callback functions, one should not and cannot return RPC errors by throwing exceptions, because the error might not occur within the call stack of the RPC function. Instead, we can use the `coro_rpc::context::response_error()` function to return RPC errors. ```cpp void echo(coro_rpc::context ctx) { From 350fbc43524a4ef9f4f503cf4c1145f04b7dc88c Mon Sep 17 00:00:00 2001 From: saipubw Date: Mon, 27 May 2024 14:36:34 +0800 Subject: [PATCH 08/12] [no ci] fix doc (#685) --- website/docs/en/coro_rpc/coro_rpc_server.md | 4 ++-- website/docs/zh/coro_rpc/coro_rpc_server.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/en/coro_rpc/coro_rpc_server.md b/website/docs/en/coro_rpc/coro_rpc_server.md index 9df46991d..2eb8a3742 100644 --- a/website/docs/en/coro_rpc/coro_rpc_server.md +++ b/website/docs/en/coro_rpc/coro_rpc_server.md @@ -427,7 +427,7 @@ using namespace coro_rpc; using namespace async_simple::coro; Lazy rpc_call(coro_rpc_client& cli) { assert(co_await cli.call>(42).value() == 42); - assert(co_await cli.call>("Hello").value() == "Hello"); - assert(co_await cli.call>(std::vector{1,2,3}).value() == std::vector{1,2,3}); + assert(co_await cli.call>("Hello").value() == "Hello"); + assert(co_await cli.call>>(std::vector{1,2,3}).value() == std::vector{1,2,3}); } ``` \ No newline at end of file diff --git a/website/docs/zh/coro_rpc/coro_rpc_server.md b/website/docs/zh/coro_rpc/coro_rpc_server.md index 3400c17c1..0d3b8be46 100644 --- a/website/docs/zh/coro_rpc/coro_rpc_server.md +++ b/website/docs/zh/coro_rpc/coro_rpc_server.md @@ -425,7 +425,7 @@ using namespace coro_rpc; using namespace async_simple::coro; Lazy rpc_call(coro_rpc_client& cli) { assert(co_await cli.call>(42).value() == 42); - assert(co_await cli.call>("Hello").value() == "Hello"); - assert(co_await cli.call>(std::vector{1,2,3}).value() == std::vector{1,2,3}); + assert(co_await cli.call>("Hello").value() == "Hello"); + assert(co_await cli.call>>(std::vector{1,2,3}).value() == std::vector{1,2,3}); } ``` \ No newline at end of file From 476b5842d4e549b390a50dedba8aab9d6610779e Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 29 May 2024 11:43:20 +0800 Subject: [PATCH 09/12] [struct_pb]Refact struct pb (#680) --- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu_clang.yml | 4 +- .github/workflows/ubuntu_gcc.yml | 4 +- .github/workflows/windows.yml | 2 +- CMakeLists.txt | 1 - README.md | 6 +- cmake/struct_pb.cmake | 224 --- cmake/subdir.cmake | 13 +- .../ylt/standalone/iguana/detail/pb_type.hpp | 135 ++ .../iguana/detail/string_resize.hpp | 131 ++ .../ylt/standalone/iguana/detail/traits.hpp | 34 + include/ylt/standalone/iguana/pb_reader.hpp | 257 +++ include/ylt/standalone/iguana/pb_util.hpp | 660 +++++++ include/ylt/standalone/iguana/pb_writer.hpp | 219 +++ include/ylt/standalone/iguana/reflection.hpp | 260 ++- include/ylt/standalone/iguana/util.hpp | 6 - include/ylt/standalone/iguana/version.hpp | 2 +- include/ylt/struct_pb.hpp | 89 +- include/ylt/struct_pb/struct_pb_impl.hpp | 173 +- src/struct_pack/benchmark/BUILD.bazel | 1 + src/struct_pack/benchmark/CMakeLists.txt | 13 - src/struct_pack/benchmark/benchmark.cpp | 12 +- src/struct_pack/benchmark/protobuf_sample.hpp | 3 +- .../benchmark/struct_pack_sample.hpp | 3 +- .../benchmark/struct_pb_sample.hpp | 294 +-- src/struct_pb/CMakeLists.txt | 2 - src/struct_pb/conformance/CMakeLists.txt | 68 - .../conformance/absl/status/status.h | 208 --- .../conformance/absl/status/statusor.h | 20 - .../conformance/absl/strings/str_cat.h | 29 - .../conformance/absl/strings/str_format.h | 92 - .../binary_json_conformance_suite.cc | 1606 ----------------- .../binary_json_conformance_suite.h | 123 -- .../conformance/conformance/conformance.proto | 180 -- src/struct_pb/conformance/conformance_cpp.cc | 304 ---- .../conformance/conformance_struct_pb.cc | 242 --- src/struct_pb/conformance/conformance_test.cc | 526 ------ src/struct_pb/conformance/conformance_test.h | 331 ---- .../conformance/conformance_test_main.cc | 38 - .../conformance/conformance_test_runner.cc | 407 ----- .../conformance/failure_list_cpp.txt | 9 - .../conformance/google/protobuf/any.proto | 161 -- .../google/protobuf/descriptor.proto | 921 ---------- .../google/protobuf/duration.proto | 115 -- .../google/protobuf/field_mask.proto | 245 --- .../google/protobuf/source_context.proto | 48 - .../conformance/google/protobuf/struct.proto | 95 - .../protobuf/test_messages_proto2.proto | 303 ---- .../protobuf/test_messages_proto3.proto | 288 --- .../google/protobuf/timestamp.proto | 144 -- .../conformance/google/protobuf/type.proto | 187 -- .../google/protobuf/wrappers.proto | 123 -- src/struct_pb/examples/CMakeLists.txt | 13 +- src/struct_pb/examples/addressbook.proto | 26 - src/struct_pb/examples/demo.proto | 50 - src/struct_pb/examples/main.cpp | 68 + src/struct_pb/examples/tutorial.cpp | 104 -- src/struct_pb/protoc-plugin/CMakeLists.txt | 18 - .../protoc-plugin/EnumFieldGenerator.cpp | 328 ---- .../protoc-plugin/EnumFieldGenerator.h | 56 - src/struct_pb/protoc-plugin/EnumGenerator.cpp | 37 - src/struct_pb/protoc-plugin/EnumGenerator.h | 20 - .../protoc-plugin/FieldGenerator.cpp | 557 ------ src/struct_pb/protoc-plugin/FieldGenerator.h | 90 - src/struct_pb/protoc-plugin/FileGenerator.cpp | 199 -- src/struct_pb/protoc-plugin/FileGenerator.h | 35 - src/struct_pb/protoc-plugin/GeneratorBase.cpp | 26 - src/struct_pb/protoc-plugin/GeneratorBase.h | 15 - .../protoc-plugin/MapFieldGenerator.cpp | 298 --- .../protoc-plugin/MapFieldGenerator.h | 44 - .../protoc-plugin/MessageFieldGenerator.cpp | 149 -- .../protoc-plugin/MessageFieldGenerator.h | 38 - .../protoc-plugin/MessageGenerator.cpp | 209 --- .../protoc-plugin/MessageGenerator.h | 33 - .../protoc-plugin/OneofFieldGenerator.cpp | 323 ---- .../protoc-plugin/OneofFieldGenerator.h | 64 - src/struct_pb/protoc-plugin/Options.hpp | 10 - .../protoc-plugin/PrimitiveFieldGenerator.cpp | 453 ----- .../protoc-plugin/PrimitiveFieldGenerator.h | 59 - .../protoc-plugin/StringFieldGenerator.cpp | 185 -- .../protoc-plugin/StringFieldGenerator.h | 46 - .../protoc-plugin/StructGenerator.cpp | 71 - src/struct_pb/protoc-plugin/StructGenerator.h | 15 - src/struct_pb/protoc-plugin/helpers.cpp | 67 - src/struct_pb/protoc-plugin/helpers.hpp | 279 --- src/struct_pb/protoc-plugin/main.cpp | 9 - src/struct_pb/tests/CMakeLists.txt | 90 +- src/struct_pb/tests/data_def.proto | 18 +- src/struct_pb/tests/helper.hpp | 78 - src/struct_pb/tests/hex_printer.hpp | 64 - src/struct_pb/tests/main.cpp | 1171 +++++++++++- .../tests/test_bad_identifiers.proto | 191 -- .../tests/test_large_enum_value.proto | 43 - src/struct_pb/tests/test_pb.cpp | 851 --------- src/struct_pb/tests/test_pb.proto | 127 -- .../tests/test_pb_bad_identifiers.cpp | 46 - .../tests/test_pb_benchmark_struct.cpp | 335 ---- src/struct_pb/tests/test_pb_oneof.cpp | 108 -- src/struct_pb/tests/unittest_proto3.h | 688 +++++++ src/struct_pb/tests/unittest_proto3.proto | 108 ++ website/.vitepress/config/en_data.ts | 37 +- website/.vitepress/config/zh_data.ts | 7 +- .../docs/en/guide/what_is_yalantinglibs.md | 6 +- .../struct_pb/images/struct_pb_overview.jpeg | Bin 68961 -> 0 bytes website/docs/en/struct_pb/struct_pb_api.md | 65 - .../struct_pb_generating_your_struct.md | 34 - .../en/struct_pb/struct_pb_guide_proto3.md | 194 -- website/docs/en/struct_pb/struct_pb_intro.md | 277 +-- .../en/struct_pb/struct_pb_quick_start.md | 237 --- .../struct_pb/struct_pb_supported_features.md | 67 - .../docs/zh/guide/what_is_yalantinglibs.md | 6 +- website/docs/zh/struct_pb/struct_pb_api.md | 65 - .../struct_pb_generating_your_struct.md | 34 - .../zh/struct_pb/struct_pb_guide_proto3.md | 194 -- website/docs/zh/struct_pb/struct_pb_intro.md | 269 ++- .../zh/struct_pb/struct_pb_quick_start.md | 237 --- .../struct_pb/struct_pb_supported_features.md | 67 - 117 files changed, 4226 insertions(+), 14845 deletions(-) delete mode 100644 cmake/struct_pb.cmake create mode 100644 include/ylt/standalone/iguana/detail/pb_type.hpp create mode 100644 include/ylt/standalone/iguana/detail/string_resize.hpp create mode 100644 include/ylt/standalone/iguana/pb_reader.hpp create mode 100644 include/ylt/standalone/iguana/pb_util.hpp create mode 100644 include/ylt/standalone/iguana/pb_writer.hpp delete mode 100644 src/struct_pb/CMakeLists.txt delete mode 100644 src/struct_pb/conformance/CMakeLists.txt delete mode 100644 src/struct_pb/conformance/absl/status/status.h delete mode 100644 src/struct_pb/conformance/absl/status/statusor.h delete mode 100644 src/struct_pb/conformance/absl/strings/str_cat.h delete mode 100644 src/struct_pb/conformance/absl/strings/str_format.h delete mode 100644 src/struct_pb/conformance/binary_json_conformance_suite.cc delete mode 100644 src/struct_pb/conformance/binary_json_conformance_suite.h delete mode 100644 src/struct_pb/conformance/conformance/conformance.proto delete mode 100644 src/struct_pb/conformance/conformance_cpp.cc delete mode 100644 src/struct_pb/conformance/conformance_struct_pb.cc delete mode 100644 src/struct_pb/conformance/conformance_test.cc delete mode 100644 src/struct_pb/conformance/conformance_test.h delete mode 100644 src/struct_pb/conformance/conformance_test_main.cc delete mode 100644 src/struct_pb/conformance/conformance_test_runner.cc delete mode 100644 src/struct_pb/conformance/failure_list_cpp.txt delete mode 100644 src/struct_pb/conformance/google/protobuf/any.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/descriptor.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/duration.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/field_mask.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/source_context.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/struct.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/timestamp.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/type.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/wrappers.proto delete mode 100644 src/struct_pb/examples/addressbook.proto delete mode 100644 src/struct_pb/examples/demo.proto create mode 100644 src/struct_pb/examples/main.cpp delete mode 100644 src/struct_pb/examples/tutorial.cpp delete mode 100644 src/struct_pb/protoc-plugin/CMakeLists.txt delete mode 100644 src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/EnumFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/EnumGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/EnumGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/FieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/FieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/FileGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/FileGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/GeneratorBase.cpp delete mode 100644 src/struct_pb/protoc-plugin/GeneratorBase.h delete mode 100644 src/struct_pb/protoc-plugin/MapFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/MapFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/MessageFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/MessageGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/MessageGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/OneofFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/Options.hpp delete mode 100644 src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/StringFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/StringFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/StructGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/StructGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/helpers.cpp delete mode 100644 src/struct_pb/protoc-plugin/helpers.hpp delete mode 100644 src/struct_pb/protoc-plugin/main.cpp delete mode 100644 src/struct_pb/tests/helper.hpp delete mode 100644 src/struct_pb/tests/hex_printer.hpp delete mode 100644 src/struct_pb/tests/test_bad_identifiers.proto delete mode 100644 src/struct_pb/tests/test_large_enum_value.proto delete mode 100644 src/struct_pb/tests/test_pb.cpp delete mode 100644 src/struct_pb/tests/test_pb.proto delete mode 100644 src/struct_pb/tests/test_pb_bad_identifiers.cpp delete mode 100644 src/struct_pb/tests/test_pb_benchmark_struct.cpp delete mode 100644 src/struct_pb/tests/test_pb_oneof.cpp create mode 100644 src/struct_pb/tests/unittest_proto3.h create mode 100644 src/struct_pb/tests/unittest_proto3.proto delete mode 100644 website/docs/en/struct_pb/images/struct_pb_overview.jpeg delete mode 100644 website/docs/en/struct_pb/struct_pb_api.md delete mode 100644 website/docs/en/struct_pb/struct_pb_generating_your_struct.md delete mode 100644 website/docs/en/struct_pb/struct_pb_guide_proto3.md delete mode 100644 website/docs/en/struct_pb/struct_pb_quick_start.md delete mode 100644 website/docs/en/struct_pb/struct_pb_supported_features.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_api.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_generating_your_struct.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_guide_proto3.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_quick_start.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_supported_features.md diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 3edac918d..613aaee9e 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -30,7 +30,7 @@ jobs: CXX=g++ CC=gcc cmake -B ${{github.workspace}}/build \ -DCMAKE_BUILD_TYPE=Debug \ - -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF + -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF cmake --build ${{github.workspace}}/build -j cd ${{github.workspace}}/build/output/tests ./struct_pack_test diff --git a/.github/workflows/ubuntu_clang.yml b/.github/workflows/ubuntu_clang.yml index 4c772f910..d9a7fc58c 100644 --- a/.github/workflows/ubuntu_clang.yml +++ b/.github/workflows/ubuntu_clang.yml @@ -98,7 +98,7 @@ jobs: cmake -B ${{github.workspace}}/build -G Ninja \ -DCMAKE_BUILD_TYPE=${{matrix.mode}} -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} -DYLT_ENABLE_SSL=${{matrix.ssl}} \ -DUSE_CCACHE=${{env.ccache}} -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17\ - -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_STRUCT_PB=ON -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} @@ -146,7 +146,7 @@ jobs: -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} \ -DYLT_ENABLE_IO_URING=${{matrix.io_uring}} \ -DUSE_CCACHE=${{env.ccache}} -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17\ - -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} diff --git a/.github/workflows/ubuntu_gcc.yml b/.github/workflows/ubuntu_gcc.yml index fa02eb7ea..8bd7f014b 100644 --- a/.github/workflows/ubuntu_gcc.yml +++ b/.github/workflows/ubuntu_gcc.yml @@ -80,7 +80,7 @@ jobs: cmake -B ${{github.workspace}}/build -G Ninja \ -DCMAKE_BUILD_TYPE=${{matrix.mode}} -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} -DYLT_ENABLE_SSL=${{matrix.ssl}} \ -DUSE_CCACHE=${{env.ccache}} \ - -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_STRUCT_PB=ON -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} @@ -118,7 +118,7 @@ jobs: -DCMAKE_BUILD_TYPE=${{matrix.mode}} \ -DYLT_ENABLE_IO_URING=${{matrix.io_uring}} \ -DUSE_CCACHE=${{env.ccache}} \ - -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c90e6f117..fe1c645a9 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -72,7 +72,7 @@ jobs: with: key: ${{ github.job }}-${{ matrix.mode}}-arch-${{ matrix.arch}} - name: Configure CMake - run: cmake -B ${{github.workspace}}\build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.mode }} -DYLT_ENABLE_SSL=${{matrix.ssl}} -DUSE_CCACHE=ON -DENABLE_CPP_20=OFF + run: cmake -B ${{github.workspace}}\build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.mode }} -DYLT_ENABLE_SSL=${{matrix.ssl}} -DBUILD_STRUCT_PB=OFF -DUSE_CCACHE=ON -DENABLE_CPP_20=OFF - name: Build run: cmake --build ${{github.workspace}}\build - name: Test diff --git a/CMakeLists.txt b/CMakeLists.txt index b13fec170..0ed3a088a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,6 @@ if(CMAKE_PROJECT_NAME STREQUAL "yaLanTingLibs") # if ylt is top-level project include_directories(src/include) include(cmake/utils.cmake) - include(cmake/struct_pb.cmake) include(cmake/build.cmake) include(cmake/develop.cmake) # add project config, such as enable_ssl. diff --git a/README.md b/README.md index e7a8bdaeb..364c8c734 100644 --- a/README.md +++ b/README.md @@ -504,11 +504,9 @@ No dependency. No dependency. -### struct_pb (optional) +### struct_pb -In default, struct_pb wont be installed. You need install protobuf manually. - -- [protobuf](https://protobuf.dev/) +No dependency. ## Standalone sublibraries diff --git a/cmake/struct_pb.cmake b/cmake/struct_pb.cmake deleted file mode 100644 index decd4e3b0..000000000 --- a/cmake/struct_pb.cmake +++ /dev/null @@ -1,224 +0,0 @@ -function(protobuf_generate_modified) - find_package(Protobuf REQUIRED) - set(_options APPEND_PATH DESCRIPTORS) - set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN PROTOC_OPTION) - if(COMMAND target_sources) - list(APPEND _singleargs TARGET) - endif() - set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS) - - cmake_parse_arguments(protobuf_generate "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}") - - if(NOT protobuf_generate_PROTOS AND NOT protobuf_generate_TARGET) - message(SEND_ERROR "Error: protobuf_generate called without any targets or source files") - return() - endif() - - if(NOT protobuf_generate_OUT_VAR AND NOT protobuf_generate_TARGET) - message(SEND_ERROR "Error: protobuf_generate called without a target or output variable") - return() - endif() - - if(NOT protobuf_generate_LANGUAGE) - set(protobuf_generate_LANGUAGE struct_pb) - endif() - string(TOLOWER ${protobuf_generate_LANGUAGE} protobuf_generate_LANGUAGE) - - if(NOT protobuf_generate_PROTOC_OUT_DIR) - set(protobuf_generate_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) - endif() - - set(_opt) - if(protobuf_generate_PROTOC_OPTION) - set(_opt "${protobuf_generate_PROTOC_OPTION}") - endif() - if(protobuf_generate_EXPORT_MACRO AND protobuf_generate_LANGUAGE STREQUAL cpp) - set(_opt "${opt},dllexport_decl=${protobuf_generate_EXPORT_MACRO}") - endif() - set(_opt "${_opt}:") - if(protobuf_generate_PLUGIN) - set(_plugin "--plugin=${protobuf_generate_PLUGIN}") - endif() - - if(NOT protobuf_generate_GENERATE_EXTENSIONS) - if(protobuf_generate_LANGUAGE STREQUAL cpp) - set(protobuf_generate_GENERATE_EXTENSIONS .pb.h .pb.cc) - elseif(protobuf_generate_LANGUAGE STREQUAL python) - set(protobuf_generate_GENERATE_EXTENSIONS _pb2.py) - elseif(protobuf_generate_LANGUAGE STREQUAL struct_pb) - set(protobuf_generate_GENERATE_EXTENSIONS .struct_pb.h .struct_pb.cc) - else() - message(SEND_ERROR "Error: protobuf_generate given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS") - return() - endif() - endif() - - if(protobuf_generate_TARGET) - get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES) - foreach(_file ${_source_list}) - if(_file MATCHES "proto$") - list(APPEND protobuf_generate_PROTOS ${_file}) - endif() - endforeach() - endif() - - if(NOT protobuf_generate_PROTOS) - message(SEND_ERROR "Error: protobuf_generate could not find any .proto files") - return() - endif() - - if(protobuf_generate_APPEND_PATH) - # Create an include path for each file specified - foreach(_file ${protobuf_generate_PROTOS}) - get_filename_component(_abs_file ${_file} ABSOLUTE) - get_filename_component(_abs_path ${_abs_file} PATH) - list(FIND _protobuf_include_path ${_abs_path} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${_abs_path}) - endif() - endforeach() - else() - set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - - foreach(DIR ${protobuf_generate_IMPORT_DIRS}) - get_filename_component(ABS_PATH ${DIR} ABSOLUTE) - list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${ABS_PATH}) - endif() - endforeach() - - set(_generated_srcs_all) - foreach(_proto ${protobuf_generate_PROTOS}) - get_filename_component(_abs_file ${_proto} ABSOLUTE) - get_filename_component(_abs_dir ${_abs_file} DIRECTORY) - get_filename_component(_basename ${_proto} NAME_WLE) - file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir}) - - set(_possible_rel_dir) - if (NOT protobuf_generate_APPEND_PATH) - set(_possible_rel_dir ${_rel_dir}/) - endif() - - set(_generated_srcs) - foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS}) - list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_possible_rel_dir}${_basename}${_ext}") - endforeach() - - if(protobuf_generate_DESCRIPTORS AND protobuf_generate_LANGUAGE STREQUAL cpp) - set(_descriptor_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.desc") - set(_dll_desc_out "--descriptor_set_out=${_descriptor_file}") - list(APPEND _generated_srcs ${_descriptor_file}) - endif() - list(APPEND _generated_srcs_all ${_generated_srcs}) - - add_custom_command( - OUTPUT ${_generated_srcs} - COMMAND protobuf::protoc - ARGS --${protobuf_generate_LANGUAGE}_out ${_opt}${protobuf_generate_PROTOC_OUT_DIR} ${_plugin} ${_dll_desc_out} ${_protobuf_include_path} ${_abs_file} - DEPENDS ${_abs_file} protobuf::protoc - COMMENT "Running ${protobuf_generate_LANGUAGE} protocol buffer compiler on ${_proto}" - VERBATIM ) - endforeach() - - set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE) - if(protobuf_generate_OUT_VAR) - set(${protobuf_generate_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE) - endif() - if(protobuf_generate_TARGET) - target_sources(${protobuf_generate_TARGET} PRIVATE ${_generated_srcs_all}) - target_include_directories(${protobuf_generate_TARGET} PUBLIC ${protobuf_generate_PROTOC_OUT_DIR}) - endif() -endfunction() - - -function(protobuf_generate_struct_pb SRCS HDRS) - cmake_parse_arguments(protobuf_generate_struct_pb "" "EXPORT_MACRO;DESCRIPTORS;OPTION" "" ${ARGN}) - - set(_proto_files "${protobuf_generate_struct_pb_UNPARSED_ARGUMENTS}") - if(NOT _proto_files) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_STRUCT_PB() called without any proto files") - return() - endif() - - if(PROTOBUF_GENERATE_STRUCT_PB_APPEND_PATH) - set(_append_arg APPEND_PATH) - endif() - - if(protobuf_generate_struct_pb_DESCRIPTORS) - set(_descriptors DESCRIPTORS) - endif() - - if(protobuf_generate_struct_pb_OPTION) - set(_opt ${protobuf_generate_struct_pb_OPTION}) - endif() - - if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) - set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}") - endif() - - if(DEFINED Protobuf_IMPORT_DIRS) - set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS}) - endif() - - set(_outvar) - protobuf_generate_modified(${_append_arg} ${_descriptors} - LANGUAGE struct_pb EXPORT_MACRO ${protobuf_generate_struct_pb_EXPORT_MACRO} - PLUGIN $ - OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files} - PROTOC_OPTION ${_opt} - ) - - set(${SRCS}) - set(${HDRS}) - if(protobuf_generate_struct_pb_DESCRIPTORS) - set(${protobuf_generate_struct_pb_DESCRIPTORS}) - endif() - - foreach(_file ${_outvar}) - if(_file MATCHES "cc$") - list(APPEND ${SRCS} ${_file}) - elseif(_file MATCHES "desc$") - list(APPEND ${protobuf_generate_struct_pb_DESCRIPTORS} ${_file}) - else() - list(APPEND ${HDRS} ${_file}) - endif() - endforeach() - set(${SRCS} ${${SRCS}} PARENT_SCOPE) - set(${HDRS} ${${HDRS}} PARENT_SCOPE) - if(protobuf_generate_struct_pb_DESCRIPTORS) - set(${protobuf_generate_struct_pb_DESCRIPTORS} "${${protobuf_generate_struct_pb_DESCRIPTORS}}" PARENT_SCOPE) - endif() -endfunction() - -function(target_protos_struct_pb target) - set(_options APPEND_PATH DESCRIPTORS) - set(_singleargs LANGUAGE EXPORT_MACRO PROTOC_OUT_DIR PLUGIN OPTION) - set(_multiargs IMPORT_DIRS PRIVATE PUBLIC) - cmake_parse_arguments(target_protos_struct_pb "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}") - set(_proto_files "${target_protos_struct_pb_PRIVATE}" "${target_protos_struct_pb_PUBLIC}") - if (NOT _proto_files) - message(SEND_ERROR "Error: TARGET_PROTOS_STRUCT_PB() called without any proto files") - return() - endif () - - if (DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) - set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}") - endif () - - if (DEFINED Protobuf_IMPORT_DIRS) - set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS}) - endif () - - if (target_protos_struct_pb_OPTION) - set(_opt ${target_protos_struct_pb_OPTION}) - endif () - protobuf_generate_modified( - TARGET ${target} - LANGUAGE struct_pb EXPORT_MACRO ${target_protos_struct_pb_EXPORT_MACRO} - PLUGIN $ - ${_import_arg} PROTOS ${_proto_files} - PROTOC_OPTION ${_opt} - ) -endfunction() diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 90f1a08cc..02013f980 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -22,13 +22,13 @@ endif() foreach(child ${children}) get_filename_component(subdir_name ${child} NAME) string(TOUPPER ${subdir_name} subdir_name) - message(STATUS "BUILD_${subdir_name}: ${BUILD_${subdir_name}}") -endforeach() + if((${subdir_name} STREQUAL "STRUCT_PACK" OR ${subdir_name} STREQUAL "STRUCT_PB") AND (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")) + message(STATUS "skip ${subdir_name}") + continue() + endif() -foreach(child ${children}) - get_filename_component(subdir_name ${child} NAME) - string(TOUPPER ${subdir_name} subdir_name) if (BUILD_${subdir_name}) + message(STATUS "BUILD_${subdir_name}: ${BUILD_${subdir_name}}") if(BUILD_EXAMPLES AND EXISTS ${child}/examples) add_subdirectory(${child}/examples) endif() @@ -40,7 +40,4 @@ foreach(child ${children}) endif() endif() endforeach() -if (BUILD_STRUCT_PB) - add_subdirectory(src/struct_pb) -endif() message(STATUS "--------------------------------------------") \ No newline at end of file diff --git a/include/ylt/standalone/iguana/detail/pb_type.hpp b/include/ylt/standalone/iguana/detail/pb_type.hpp new file mode 100644 index 000000000..2ce5f60b1 --- /dev/null +++ b/include/ylt/standalone/iguana/detail/pb_type.hpp @@ -0,0 +1,135 @@ +#pragma once + +namespace iguana { + +struct sint32_t { + using value_type = int32_t; + int32_t val; + bool operator==(const sint32_t& other) const { return val == other.val; } +}; + +inline bool operator==(sint32_t value1, int32_t value2) { + return value1.val == value2; +} + +// for key in std::map +inline bool operator<(const sint32_t& lhs, const sint32_t& rhs) { + return lhs.val < rhs.val; +} + +struct sint64_t { + using value_type = int64_t; + int64_t val; + bool operator==(const sint64_t& other) const { return val == other.val; } +}; + +inline bool operator==(sint64_t value1, int64_t value2) { + return value1.val == value2; +} + +inline bool operator<(const sint64_t& lhs, const sint64_t& rhs) { + return lhs.val < rhs.val; +} + +struct fixed32_t { + using value_type = uint32_t; + uint32_t val; + bool operator==(const fixed32_t& other) const { return val == other.val; } +}; + +inline bool operator==(fixed32_t value1, uint32_t value2) { + return value1.val == value2; +} + +inline bool operator<(const fixed32_t& lhs, const fixed32_t& rhs) { + return lhs.val < rhs.val; +} + +struct fixed64_t { + using value_type = uint64_t; + uint64_t val; + bool operator==(const fixed64_t& other) const { return val == other.val; } +}; + +inline bool operator==(fixed64_t value1, uint64_t value2) { + return value1.val == value2; +} + +inline bool operator<(const fixed64_t& lhs, const fixed64_t& rhs) { + return lhs.val < rhs.val; +} + +struct sfixed32_t { + using value_type = int32_t; + int32_t val; + bool operator==(const sfixed32_t& other) const { return val == other.val; } +}; + +inline bool operator==(sfixed32_t value1, int32_t value2) { + return value1.val == value2; +} + +inline bool operator<(const sfixed32_t& lhs, const sfixed32_t& rhs) { + return lhs.val < rhs.val; +} + +struct sfixed64_t { + using value_type = int64_t; + int64_t val; + bool operator==(const sfixed64_t& other) const { return val == other.val; } +}; + +inline bool operator==(sfixed64_t value1, int64_t value2) { + return value1.val == value2; +} + +inline bool operator<(const sfixed64_t& lhs, const sfixed64_t& rhs) { + return lhs.val < rhs.val; +} + +} // namespace iguana + +// for key in std::unordered_map +namespace std { +template <> +struct hash { + size_t operator()(const iguana::sint32_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::sint64_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::fixed32_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::fixed64_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::sfixed32_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::sfixed64_t& x) const noexcept { + return std::hash()(x.val); + } +}; +} // namespace std diff --git a/include/ylt/standalone/iguana/detail/string_resize.hpp b/include/ylt/standalone/iguana/detail/string_resize.hpp new file mode 100644 index 000000000..81d4605e5 --- /dev/null +++ b/include/ylt/standalone/iguana/detail/string_resize.hpp @@ -0,0 +1,131 @@ +#pragma once +#include +#include +#include +#include + +namespace iguana::detail { + +#if __cpp_lib_string_resize_and_overwrite >= 202110L +template +inline void resize(std::basic_string &str, std::size_t sz) { + str.resize_and_overwrite(sz, [sz](ch *, std::size_t) { + return sz; + }); +} +#elif (defined(_MSC_VER) && _MSC_VER <= 1920) +// old msvc don't support visit private, discard it. + +#else + +template +class string_thief { + public: + friend void string_set_length_hacker(std::string &self, std::size_t sz) { +#if defined(_MSVC_STL_VERSION) + (self.*func_ptr)._Myval2._Mysize = sz; +#else +#if defined(_LIBCPP_VERSION) + (self.*func_ptr)(sz); +#else +#if (_GLIBCXX_USE_CXX11_ABI == 0) && defined(__GLIBCXX__) + (self.*func_ptr)()->_M_set_length_and_sharable(sz); +#else +#if defined(__GLIBCXX__) + (self.*func_ptr)(sz); +#endif +#endif +#endif +#endif + } +}; + +#if defined(__GLIBCXX__) // libstdc++ +#if (_GLIBCXX_USE_CXX11_ABI == 0) +template class string_thief; +#else +template class string_thief; +#endif +#elif defined(_LIBCPP_VERSION) +template class string_thief; +#elif defined(_MSVC_STL_VERSION) +template class string_thief; +#endif + +void string_set_length_hacker(std::string &, std::size_t); + +template +inline void resize(std::basic_string &raw_str, std::size_t sz) { + std::string &str = *reinterpret_cast(&raw_str); +#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \ + defined(_MSVC_STL_VERSION) + if (sz > str.capacity()) { + str.reserve(sz); + } + string_set_length_hacker(str, sz); + str[sz] = '\0'; +#else + raw_str.resize(sz); +#endif +} + +#endif + +#if (defined(_MSC_VER) && _MSC_VER <= 1920) +#else +void vector_set_length_hacker(std::vector &self, std::size_t sz); + +template +class vector_thief { + public: + friend void vector_set_length_hacker(std::vector &self, + std::size_t sz) { +#if defined(_MSVC_STL_VERSION) + (self.*func_ptr)._Myval2._Mylast = self.data() + sz; +#else +#if defined(_LIBCPP_VERSION) +#if _LIBCPP_VERSION < 14000 + ((*(std::__vector_base > *)(&self)).*func_ptr) = + self.data() + sz; +#else + (self.*func_ptr) = self.data() + sz; +#endif +#else +#if defined(__GLIBCXX__) + ((*(std::_Vector_base > *)(&self)).*func_ptr) + ._M_finish = self.data() + sz; +#endif +#endif +#endif + } +}; + +#if defined(__GLIBCXX__) // libstdc++ +template class vector_thief::_M_impl), + &std::vector::_M_impl>; +#elif defined(_LIBCPP_VERSION) +template class vector_thief::__end_), + &std::vector::__end_>; +#elif defined(_MSVC_STL_VERSION) +template class vector_thief::_Mypair), + &std::vector::_Mypair>; +#endif + +template +inline void resize(std::vector &raw_vec, std::size_t sz) { +#if defined(__GLIBCXX__) || \ + (defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_ASAN)) || \ + defined(_MSVC_STL_VERSION) + std::vector &vec = *reinterpret_cast *>(&raw_vec); + vec.reserve(sz); + vector_set_length_hacker(vec, sz); +#else + raw_vec.resize(sz); +#endif +} +#endif +}; // namespace iguana::detail \ No newline at end of file diff --git a/include/ylt/standalone/iguana/detail/traits.hpp b/include/ylt/standalone/iguana/detail/traits.hpp index 64f082e03..57a9fa45d 100644 --- a/include/ylt/standalone/iguana/detail/traits.hpp +++ b/include/ylt/standalone/iguana/detail/traits.hpp @@ -79,5 +79,39 @@ struct member_tratis { template inline constexpr bool is_int64_v = std::is_same_v || std::is_same_v; + +template +struct is_variant : std::false_type {}; + +template +struct is_variant> : std::true_type {}; + +template +struct member_traits { + using value_type = T; +}; + +template +struct member_traits { + using owner_type = Owner; + using value_type = T; +}; + +template +using member_value_type_t = typename member_traits::value_type; + +template +struct variant_type_at { + using type = T; +}; + +template +struct variant_type_at::value>> { + using type = std::variant_alternative_t; +}; +template +using variant_type_at_t = + typename variant_type_at::value_type, I>::type; + } // namespace iguana #endif // SERIALIZE_TRAITS_HPP diff --git a/include/ylt/standalone/iguana/pb_reader.hpp b/include/ylt/standalone/iguana/pb_reader.hpp new file mode 100644 index 000000000..6a0a92d9a --- /dev/null +++ b/include/ylt/standalone/iguana/pb_reader.hpp @@ -0,0 +1,257 @@ +#pragma once +#include "detail/string_resize.hpp" +#include "pb_util.hpp" + +namespace iguana { + +namespace detail { + +template +IGUANA_INLINE void from_pb_impl(T& val, std::string_view& pb_str, + uint32_t field_no = 0); + +template +IGUANA_INLINE void decode_pair_value(T& val, std::string_view& pb_str) { + size_t pos; + uint32_t key = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + WireType wire_type = static_cast(key & 0b0111); + if (wire_type != detail::get_wire_type>()) { + return; + } + from_pb_impl(val, pb_str); +} + +template +IGUANA_INLINE void from_pb_impl(T& val, std::string_view& pb_str, + uint32_t field_no) { + size_t pos = 0; + if constexpr (is_reflection_v) { + size_t pos; + uint32_t size = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid fixed int value: too few bytes."); + } + if (size == 0) { + return; + } + from_pb(val, pb_str.substr(0, size)); + pb_str = pb_str.substr(size); + } + else if constexpr (is_sequence_container::value) { + using item_type = typename T::value_type; + if constexpr (is_lenprefix_v) { + // item_type non-packed + while (!pb_str.empty()) { + item_type item{}; + from_pb_impl(item, pb_str); + val.push_back(std::move(item)); + if (pb_str.empty()) { + break; + } + uint32_t key = detail::decode_varint(pb_str, pos); + uint32_t field_number = key >> 3; + if (field_number != field_no) { + break; + } + else { + pb_str = pb_str.substr(pos); + } + } + } + else { + // item_type packed + size_t pos; + uint32_t size = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument( + "Invalid fixed int value: too few bytes."); + } + using item_type = typename T::value_type; + size_t start = pb_str.size(); + + while (!pb_str.empty()) { + item_type item; + from_pb_impl(item, pb_str); + val.push_back(std::move(item)); + if (start - pb_str.size() == size) { + break; + } + } + } + } + else if constexpr (is_map_container::value) { + using item_type = std::pair; + while (!pb_str.empty()) { + size_t pos; + uint32_t size = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument( + "Invalid fixed int value: too few bytes."); + } + item_type item = {}; + decode_pair_value(item.first, pb_str); + decode_pair_value(item.second, pb_str); + val.emplace(std::move(item)); + + if (pb_str.empty()) { + break; + } + uint32_t key = detail::decode_varint(pb_str, pos); + uint32_t field_number = key >> 3; + if (field_number != field_no) { + break; + } + pb_str = pb_str.substr(pos); + } + } + else if constexpr (std::is_integral_v) { + val = static_cast(detail::decode_varint(pb_str, pos)); + pb_str = pb_str.substr(pos); + } + else if constexpr (detail::is_signed_varint_v) { + constexpr size_t len = sizeof(typename T::value_type); + uint64_t temp = detail::decode_varint(pb_str, pos); + if constexpr (len == 8) { + val.val = detail::decode_zigzag(temp); + } + else { + val.val = detail::decode_zigzag(static_cast(temp)); + } + pb_str = pb_str.substr(pos); + } + else if constexpr (detail::is_fixed_v) { + constexpr size_t size = sizeof(typename T::value_type); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid fixed int value: too few bytes."); + } + memcpy(&(val.val), pb_str.data(), size); + pb_str = pb_str.substr(size); + } + else if constexpr (std::is_same_v || std::is_same_v) { + constexpr size_t size = sizeof(T); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid fixed int value: too few bytes."); + } + memcpy(&(val), pb_str.data(), size); + pb_str = pb_str.substr(size); + } + else if constexpr (std::is_same_v || + std::is_same_v) { + size_t size = detail::decode_varint(pb_str, pos); + if (pb_str.size() < pos + size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid string value: too few bytes."); + } + if constexpr (std::is_same_v) { + val = std::string_view(pb_str.data() + pos, size); + } + else { + detail::resize(val, size); + memcpy(val.data(), pb_str.data() + pos, size); + } + pb_str = pb_str.substr(size + pos); + } + else if constexpr (std::is_enum_v) { + using U = std::underlying_type_t; + U value{}; + from_pb_impl(value, pb_str); + val = static_cast(value); + } + else if constexpr (optional_v) { + from_pb_impl(val.emplace(), pb_str); + } + else { + static_assert(!sizeof(T), "err"); + } +} + +template +IGUANA_INLINE void parse_oneof(T& t, const Field& f, std::string_view& pb_str) { + using item_type = typename std::decay_t::sub_type; + from_pb_impl(t.template emplace(), pb_str, f.field_no); +} +} // namespace detail + +template +IGUANA_INLINE void from_pb(T& t, std::string_view pb_str) { + if (pb_str.empty()) + IGUANA_UNLIKELY { return; } + size_t pos = 0; + uint32_t key = detail::decode_varint(pb_str, pos); + WireType wire_type = static_cast(key & 0b0111); + uint32_t field_number = key >> 3; +#ifdef SEQUENTIAL_PARSE + constexpr static auto tp = get_members_tuple(); + constexpr size_t SIZE = std::tuple_size_v>; + bool parse_done = false; + detail::for_each_n( + [&](auto i) IGUANA__INLINE_LAMBDA { + constexpr auto val = std::get(tp); + using sub_type = typename std::decay_t::sub_type; + using value_type = typename std::decay_t::value_type; + // sub_type is the element type when value_type is the variant type; + // otherwise, they are the same. + if (parse_done || field_number != val.field_no) { + return; + } + pb_str = pb_str.substr(pos); + if (wire_type != detail::get_wire_type()) + IGUANA_UNLIKELY { throw std::runtime_error("unmatched wire_type"); } + if constexpr (variant_v) { + detail::parse_oneof(val.value(t), val, pb_str); + } + else { + detail::from_pb_impl(val.value(t), pb_str, val.field_no); + } + if (pb_str.empty()) { + parse_done = true; + return; + } + key = detail::decode_varint(pb_str, pos); + wire_type = static_cast(key & 0b0111); + field_number = key >> 3; + }, + std::make_index_sequence{}); + if (parse_done) + IGUANA_LIKELY { return; } +#endif + while (true) { + pb_str = pb_str.substr(pos); + constexpr static auto map = get_members(); + auto& member = map.at(field_number); + std::visit( + [&t, &pb_str, wire_type](auto& val) { + using sub_type = typename std::decay_t::sub_type; + using value_type = typename std::decay_t::value_type; + if (wire_type != detail::get_wire_type()) { + throw std::runtime_error("unmatched wire_type"); + } + if constexpr (variant_v) { + detail::parse_oneof(val.value(t), val, pb_str); + } + else { + detail::from_pb_impl(val.value(t), pb_str, val.field_no); + } + }, + member); + if (!pb_str.empty()) + IGUANA_LIKELY { + key = detail::decode_varint(pb_str, pos); + wire_type = static_cast(key & 0b0111); + field_number = key >> 3; + } + else { + return; + } + } +} +} // namespace iguana diff --git a/include/ylt/standalone/iguana/pb_util.hpp b/include/ylt/standalone/iguana/pb_util.hpp new file mode 100644 index 000000000..b2e467721 --- /dev/null +++ b/include/ylt/standalone/iguana/pb_util.hpp @@ -0,0 +1,660 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "detail/pb_type.hpp" +#include "reflection.hpp" +#include "util.hpp" + +namespace iguana { + +enum class WireType : uint32_t { + Varint = 0, + Fixed64 = 1, + LengthDelimeted = 2, + StartGroup = 3, + EndGroup = 4, + Fixed32 = 5, + Unknown +}; + +template +IGUANA_INLINE void to_pb(T& t, Stream& out); + +template +IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); + +using base = detail::base; + +template +IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { + return (char*)&(t->*member) - (char*)t; +} + +template +struct base_impl : public base { + void to_pb(std::string& str) override { + iguana::to_pb(*(static_cast(this)), str); + } + + void from_pb(std::string_view str) override { + iguana::from_pb(*(static_cast(this)), str); + } + + iguana::detail::field_info get_field_info(std::string_view name) override { + static constexpr auto map = iguana::get_members(); + 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(); +#endif + } + }, + field); + } + + return info; + } + + std::vector get_fields_name() override { + static constexpr auto map = iguana::get_members(); + std::vector 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 +constexpr bool inherits_from_base_v = std::is_base_of_v; + +IGUANA_INLINE std::shared_ptr 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 detail { +template +constexpr bool is_fixed_v = + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v; + +template +constexpr bool is_signed_varint_v = + std::is_same_v || std::is_same_v; + +template +constexpr inline WireType get_wire_type() { + if constexpr (std::is_integral_v || is_signed_varint_v || + std::is_enum_v || std::is_same_v) { + return WireType::Varint; + } + else if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v) { + return WireType::Fixed32; + } + else if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v) { + return WireType::Fixed64; + } + else if constexpr (std::is_same_v || + std::is_same_v || + is_reflection_v || is_sequence_container::value || + is_map_container::value) { + return WireType::LengthDelimeted; + } + else if constexpr (optional_v) { + return get_wire_type(); + } + else { + throw std::runtime_error("unknown type"); + } +} + +template +constexpr bool is_lenprefix_v = (get_wire_type() == + WireType::LengthDelimeted); + +[[nodiscard]] IGUANA_INLINE uint32_t encode_zigzag(int32_t v) { + return (static_cast(v) << 1U) ^ + static_cast( + -static_cast(static_cast(v) >> 31U)); +} +[[nodiscard]] IGUANA_INLINE uint64_t encode_zigzag(int64_t v) { + return (static_cast(v) << 1U) ^ + static_cast( + -static_cast(static_cast(v) >> 63U)); +} + +[[nodiscard]] IGUANA_INLINE int64_t decode_zigzag(uint64_t u) { + return static_cast((u >> 1U)) ^ + static_cast(-static_cast(u & 1U)); +} +[[nodiscard]] IGUANA_INLINE int64_t decode_zigzag(uint32_t u) { + return static_cast((u >> 1U)) ^ + static_cast(-static_cast(u & 1U)); +} + +template +IGUANA_INLINE uint64_t decode_varint(T& data, size_t& pos) { + const int8_t* begin = reinterpret_cast(data.data()); + const int8_t* end = begin + data.size(); + const int8_t* p = begin; + uint64_t val = 0; + + if ((static_cast(*p) & 0x80) == 0) { + pos = 1; + return static_cast(*p); + } + + // end is always greater than or equal to begin, so this subtraction is safe + if (size_t(end - begin) >= 10) + IGUANA_LIKELY { // fast path + int64_t b; + do { + b = *p++; + val = (b & 0x7f); + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 7; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 14; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 21; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 28; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 35; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 42; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 49; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 56; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x01) << 63; + if (b >= 0) { + break; + } + throw std::invalid_argument("Invalid varint value: too many bytes."); + } while (false); + } + else { + int shift = 0; + while (p != end && *p < 0) { + val |= static_cast(*p++ & 0x7f) << shift; + shift += 7; + } + if (p == end) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid varint value: too few bytes."); + } + val |= static_cast(*p++) << shift; + } + + pos = (p - begin); + return val; +} + +// value == 0 ? 1 : floor(log2(value)) / 7 + 1 +constexpr size_t variant_uint32_size_constexpr(uint32_t value) { + if (value == 0) { + return 1; + } + int log = 0; + while (value >>= 1) ++log; + return log / 7 + 1; +} + +template +IGUANA_INLINE void append_varint_u32_constexpr_help(It&& it) { + *(it++) = static_cast((v >> (7 * I)) | 0x80); +} + +template +IGUANA_INLINE void append_varint_u32_constexpr(It&& it, + std::index_sequence) { + (append_varint_u32_constexpr_help(it), ...); +} + +template +IGUANA_INLINE void serialize_varint_u32_constexpr(It&& it) { + constexpr auto size = variant_uint32_size_constexpr(v); + append_varint_u32_constexpr(it, std::make_index_sequence{}); + *(it++) = static_cast(v >> (7 * (size - 1))); +} + +template +IGUANA_INLINE void serialize_varint(uint64_t v, It&& it) { + if (v < 0x80) { + *(it++) = static_cast(v); + return; + } + *(it++) = static_cast(v | 0x80); + v >>= 7; + if (v < 0x80) { + *(it++) = static_cast(v); + return; + } + do { + *(it++) = static_cast(v | 0x80); + v >>= 7; + } while (v >= 0x80); + *(it++) = static_cast(v); +} + +IGUANA_INLINE uint32_t log2_floor_uint32(uint32_t n) { +#if defined(__GNUC__) + return 31 ^ static_cast(__builtin_clz(n)); +#else + unsigned long where; + _BitScanReverse(&where, n); + return where; +#endif +} + +IGUANA_INLINE size_t variant_uint32_size(uint32_t value) { + // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1 + // Use an explicit multiplication to implement the divide of + // a number in the 1..31 range. + // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is + // undefined. + uint32_t log2value = log2_floor_uint32(value | 0x1); + return static_cast((log2value * 9 + 73) / 64); +} + +IGUANA_INLINE int Log2FloorNonZero_Portable(uint32_t n) { + if (n == 0) + return -1; + int log = 0; + uint32_t value = n; + for (int i = 4; i >= 0; --i) { + int shift = (1 << i); + uint32_t x = value >> shift; + if (x != 0) { + value = x; + log += shift; + } + } + assert(value == 1); + return log; +} + +IGUANA_INLINE uint32_t Log2FloorNonZero(uint32_t n) { +#if defined(__GNUC__) + return 31 ^ static_cast(__builtin_clz(n)); +#elif defined(_MSC_VER) + unsigned long where; + _BitScanReverse(&where, n); + return where; +#else + return Log2FloorNonZero_Portable(n); +#endif +} + +IGUANA_INLINE int Log2FloorNonZero64_Portable(uint64_t n) { + const uint32_t topbits = static_cast(n >> 32); + if (topbits == 0) { + // Top bits are zero, so scan in bottom bits + return static_cast(Log2FloorNonZero(static_cast(n))); + } + else { + return 32 + static_cast(Log2FloorNonZero(topbits)); + } +} + +IGUANA_INLINE uint32_t log2_floor_uint64(uint64_t n) { +#if defined(__GNUC__) + return 63 ^ static_cast(__builtin_clzll(n)); +#elif defined(_MSC_VER) && defined(_M_X64) + unsigned long where; + _BitScanReverse64(&where, n); + return where; +#else + return Log2FloorNonZero64_Portable(n); +#endif +} + +IGUANA_INLINE size_t variant_uint64_size(uint64_t value) { + // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1 + // Use an explicit multiplication to implement the divide of + // a number in the 1..63 range. + // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is + // undefined. + uint32_t log2value = log2_floor_uint64(value | 0x1); + return static_cast((log2value * 9 + 73) / 64); +} + +template +constexpr IGUANA_INLINE size_t variant_intergal_size(U value) { + using T = std::remove_reference_t; + if constexpr (sizeof(T) == 8) { + return variant_uint64_size(static_cast(value)); + } + else if constexpr (sizeof(T) <= 4) { + if constexpr (std::is_signed_v) { + if (value < 0) { + return 10; + } + } + return variant_uint32_size(static_cast(value)); + } + else { + static_assert(!sizeof(T), "intergal in not supported"); + } +} + +template +IGUANA_INLINE constexpr void for_each_n(F&& f, std::index_sequence) { + (std::forward(f)(std::integral_constant{}), ...); +} + +template +IGUANA_INLINE size_t str_numeric_size(Type&& t) { + using T = std::remove_const_t>; + if constexpr (std::is_same_v || + std::is_same_v) { + // string + if constexpr (omit_default_val) { + if (t.size() == 0) + IGUANA_UNLIKELY { return 0; } + } + if constexpr (key_size == 0) { + return t.size(); + } + else { + return key_size + variant_uint32_size(static_cast(t.size())) + + t.size(); + } + } + else { + // numeric + if constexpr (omit_default_val) { + if constexpr (is_fixed_v || is_signed_varint_v) { + if (t.val == 0) + IGUANA_UNLIKELY { return 0; } + } + else { + if (t == static_cast(0)) + IGUANA_UNLIKELY { return 0; } + } + } + if constexpr (std::is_integral_v) { + if constexpr (std::is_same_v) { + return 1 + key_size; + } + else { + return key_size + variant_intergal_size(t); + } + } + else if constexpr (detail::is_signed_varint_v) { + return key_size + variant_intergal_size(encode_zigzag(t.val)); + } + else if constexpr (detail::is_fixed_v) { + return key_size + sizeof(typename T::value_type); + } + else if constexpr (std::is_same_v || std::is_same_v) { + return key_size + sizeof(T); + } + else if constexpr (std::is_enum_v) { + using U = std::underlying_type_t; + return key_size + variant_intergal_size(static_cast(t)); + } + else { + static_assert(!sizeof(T), "err"); + } + } +} + +template +IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr); + +template +constexpr inline size_t get_variant_index() { + if constexpr (I == 0) { + static_assert(std::is_same_v, T>, + "Type T is not found in Variant"); + return 0; + } + else if constexpr (std::is_same_v, + T>) { + return I; + } + else { + return get_variant_index(); + } +} + +template +IGUANA_INLINE size_t pb_oneof_size(Type&& t, Arr& size_arr) { + using T = std::decay_t; + int len = 0; + std::visit( + [&len, &size_arr](auto&& value) IGUANA__INLINE_LAMBDA { + using value_type = + std::remove_const_t>; + constexpr auto offset = + get_variant_index - 1>(); + constexpr uint32_t key = + ((field_no + offset) << 3) | + static_cast(get_wire_type()); + len = pb_key_value_size( + std::forward(value), size_arr); + }, + std::forward(t)); + return len; +} + +// returns size = key_size + optional(len_size) + len +// when key_size == 0, return len +template +IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr) { + using T = std::remove_const_t>; + if constexpr (is_reflection_v || is_custom_reflection_v) { + size_t len = 0; + static constexpr auto tuple = get_members_tuple(); + constexpr size_t SIZE = std::tuple_size_v>; + size_t pre_index = -1; + if constexpr (!inherits_from_base_v && key_size != 0) { + pre_index = size_arr.size(); + size_arr.push_back(0); // placeholder + } + for_each_n( + [&len, &t, &size_arr](auto i) IGUANA__INLINE_LAMBDA { + using field_type = + std::tuple_element_t>; + constexpr auto value = std::get(tuple); + using U = typename field_type::value_type; + auto& val = value.value(t); + if constexpr (variant_v) { + constexpr auto offset = + get_variant_index - 1>(); + if constexpr (offset == 0) { + len += pb_oneof_size(val, size_arr); + } + } + else { + constexpr uint32_t sub_key = + (value.field_no << 3) | + static_cast(get_wire_type()); + constexpr auto sub_keysize = variant_uint32_size_constexpr(sub_key); + len += pb_key_value_size(val, size_arr); + } + }, + std::make_index_sequence{}); + if constexpr (inherits_from_base_v) { + t.cache_size = len; + } + else if constexpr (key_size != 0) { + size_arr[pre_index] = len; + } + if constexpr (key_size == 0) { + // for top level + return len; + } + else { + if (len == 0) { + // equals key_size + variant_uint32_size(len) + return key_size + 1; + } + else { + return key_size + variant_uint32_size(static_cast(len)) + len; + } + } + } + else if constexpr (is_sequence_container::value) { + using item_type = typename T::value_type; + size_t len = 0; + if constexpr (is_lenprefix_v) { + for (auto& item : t) { + len += pb_key_value_size(item, size_arr); + } + return len; + } + else { + for (auto& item : t) { + // here 0 to get pakced size, and item must be numeric + len += str_numeric_size<0, false>(item); + } + if (len == 0) { + return 0; + } + else { + return key_size + variant_uint32_size(static_cast(len)) + len; + } + } + } + else if constexpr (is_map_container::value) { + size_t len = 0; + for (auto& [k, v] : t) { + // the key_size of k and v is constant 1 + auto kv_len = pb_key_value_size<1, false>(k, size_arr) + + pb_key_value_size<1, false>(v, size_arr); + len += key_size + variant_uint32_size(static_cast(kv_len)) + + kv_len; + } + return len; + } + else if constexpr (optional_v) { + if (!t.has_value()) { + return 0; + } + return pb_key_value_size(*t, size_arr); + } + else { + return str_numeric_size(t); + } +} + +// return the payload size +template +IGUANA_INLINE size_t pb_value_size(Type&& t, uint32_t*& sz_ptr) { + using T = std::remove_const_t>; + if constexpr (is_reflection_v || is_custom_reflection_v) { + if constexpr (inherits_from_base_v) { + return t.cache_size; + } + else { + // *sz_ptr is secure and logically guaranteed + if constexpr (skip_next) { + return *(sz_ptr++); + } + else { + return *sz_ptr; + } + } + } + else if constexpr (is_sequence_container::value) { + using item_type = typename T::value_type; + size_t len = 0; + if constexpr (!is_lenprefix_v) { + for (auto& item : t) { + len += str_numeric_size<0, false>(item); + } + return len; + } + else { + static_assert(!sizeof(item_type), "the size of this type is meaningless"); + } + } + else if constexpr (is_map_container::value) { + static_assert(!sizeof(T), "the size of this type is meaningless"); + } + else if constexpr (optional_v) { + if (!t.has_value()) { + return 0; + } + return pb_value_size(*t, sz_ptr); + } + else { + return str_numeric_size<0, false>(t); + } +} + +} // namespace detail +} // namespace iguana \ No newline at end of file diff --git a/include/ylt/standalone/iguana/pb_writer.hpp b/include/ylt/standalone/iguana/pb_writer.hpp new file mode 100644 index 000000000..db2662ab5 --- /dev/null +++ b/include/ylt/standalone/iguana/pb_writer.hpp @@ -0,0 +1,219 @@ +#pragma once +#include "detail/string_resize.hpp" +#include "pb_util.hpp" + +namespace iguana { +namespace detail { + +template +IGUANA_INLINE void encode_varint_field(V val, It&& it) { + static_assert(std::is_integral_v, "must be integral"); + if constexpr (key != 0) { + serialize_varint_u32_constexpr(it); + } + serialize_varint(val, it); +} + +template +IGUANA_INLINE void encode_fixed_field(V val, It&& it) { + if constexpr (key != 0) { + serialize_varint_u32_constexpr(it); + } + constexpr size_t size = sizeof(V); + // TODO: check Stream continuous + memcpy(it, &val, size); + it += size; +} + +template +IGUANA_INLINE void to_pb_impl(Type&& t, It&& it, uint32_t*& sz_ptr); + +template +IGUANA_INLINE void encode_pair_value(V&& val, It&& it, size_t size, + uint32_t*& sz_ptr) { + if (size == 0) + IGUANA_UNLIKELY { + // map keys can't be omitted even if values are empty + // TODO: repeated ? + serialize_varint_u32_constexpr(it); + serialize_varint(0, it); + } + else { + to_pb_impl(val, it, sz_ptr); + } +} + +template +IGUANA_INLINE void encode_numeric_field(T t, It&& it) { + if constexpr (omit_default_val) { + if constexpr (is_fixed_v || is_signed_varint_v) { + if (t.val == 0) { + return; + } + } + else { + if (t == static_cast(0)) + IGUANA_UNLIKELY { return; } + } + } + if constexpr (std::is_integral_v) { + detail::encode_varint_field(t, it); + } + else if constexpr (detail::is_signed_varint_v) { + detail::encode_varint_field(encode_zigzag(t.val), it); + } + else if constexpr (detail::is_fixed_v) { + detail::encode_fixed_field(t.val, it); + } + else if constexpr (std::is_same_v || std::is_same_v) { + detail::encode_fixed_field(t, it); + } + else if constexpr (std::is_enum_v) { + using U = std::underlying_type_t; + detail::encode_varint_field(static_cast(t), it); + } + else { + static_assert(!sizeof(T), "unsupported type"); + } +} + +template +IGUANA_INLINE void to_pb_oneof(Type&& t, It&& it, uint32_t*& sz_ptr) { + using T = std::decay_t; + std::visit( + [&it, &sz_ptr](auto&& value) IGUANA__INLINE_LAMBDA { + using value_type = + std::remove_const_t>; + constexpr auto offset = + get_variant_index - 1>(); + constexpr uint32_t key = + ((field_no + offset) << 3) | + static_cast(get_wire_type()); + to_pb_impl(std::forward(value), it, sz_ptr); + }, + std::forward(t)); +} + +// omit_default_val = true indicates to omit the default value in searlization +template +IGUANA_INLINE void to_pb_impl(Type&& t, It&& it, uint32_t*& sz_ptr) { + using T = std::remove_const_t>; + if constexpr (is_reflection_v || is_custom_reflection_v) { + // can't be omitted even if values are empty + if constexpr (key != 0) { + auto len = pb_value_size(t, sz_ptr); + serialize_varint_u32_constexpr(it); + serialize_varint(len, it); + if (len == 0) + IGUANA_UNLIKELY { return; } + } + static constexpr auto tuple = get_members_tuple(); + constexpr size_t SIZE = std::tuple_size_v>; + for_each_n( + [&t, &it, &sz_ptr](auto i) IGUANA__INLINE_LAMBDA { + using field_type = + std::tuple_element_t>; + constexpr auto value = std::get(tuple); + auto& val = value.value(t); + + using U = typename field_type::value_type; + if constexpr (variant_v) { + constexpr auto offset = + get_variant_index - 1>(); + if constexpr (offset == 0) { + to_pb_oneof(val, it, sz_ptr); + } + } + else { + constexpr uint32_t sub_key = + (value.field_no << 3) | + static_cast(get_wire_type()); + to_pb_impl(val, it, sz_ptr); + } + }, + std::make_index_sequence{}); + } + else if constexpr (is_sequence_container::value) { + // TODO support std::array + // repeated values can't be omitted even if values are empty + using item_type = typename T::value_type; + if constexpr (is_lenprefix_v) { + // non-packed + for (auto& item : t) { + to_pb_impl(item, it, sz_ptr); + } + } + else { + if (t.empty()) + IGUANA_UNLIKELY { return; } + serialize_varint_u32_constexpr(it); + serialize_varint(pb_value_size(t, sz_ptr), it); + for (auto& item : t) { + encode_numeric_field(item, it); + } + } + } + else if constexpr (is_map_container::value) { + using first_type = typename T::key_type; + using second_type = typename T::mapped_type; + constexpr uint32_t key1 = + (1 << 3) | static_cast(get_wire_type()); + constexpr auto key1_size = variant_uint32_size_constexpr(key1); + constexpr uint32_t key2 = + (2 << 3) | static_cast(get_wire_type()); + constexpr auto key2_size = variant_uint32_size_constexpr(key2); + + for (auto& [k, v] : t) { + serialize_varint_u32_constexpr(it); + // k must be string or numeric + auto k_val_len = str_numeric_size<0, false>(k); + auto v_val_len = pb_value_size(v, sz_ptr); + auto pair_len = key1_size + key2_size + k_val_len + v_val_len; + if constexpr (is_lenprefix_v) { + pair_len += variant_uint32_size(k_val_len); + } + if constexpr (is_lenprefix_v) { + pair_len += variant_uint32_size(v_val_len); + } + serialize_varint(pair_len, it); + // map k and v can't be omitted even if values are empty + encode_pair_value(k, it, k_val_len, sz_ptr); + encode_pair_value(v, it, v_val_len, sz_ptr); + } + } + else if constexpr (optional_v) { + if (!t.has_value()) { + return; + } + to_pb_impl(*t, it, sz_ptr); + } + else if constexpr (std::is_same_v || + std::is_same_v) { + if constexpr (omit_default_val) { + if (t.size() == 0) + IGUANA_UNLIKELY { return; } + } + serialize_varint_u32_constexpr(it); + serialize_varint(t.size(), it); + memcpy(it, t.data(), t.size()); + it += t.size(); + } + else { + encode_numeric_field(t, it); + } +} +} // namespace detail + +template +IGUANA_INLINE void to_pb(T& t, Stream& out) { + std::vector size_arr; + auto byte_len = detail::pb_key_value_size<0>(t, size_arr); + detail::resize(out, byte_len); + auto sz_ptr = size_arr.empty() ? nullptr : &size_arr[0]; + detail::to_pb_impl<0>(t, &out[0], sz_ptr); +} + +} // namespace iguana diff --git a/include/ylt/standalone/iguana/reflection.hpp b/include/ylt/standalone/iguana/reflection.hpp index 234da95d6..cb0ff86a8 100644 --- a/include/ylt/standalone/iguana/reflection.hpp +++ b/include/ylt/standalone/iguana/reflection.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include "detail/string_stream.hpp" #include "detail/traits.hpp" +#include "enum_reflection.hpp" #include "frozen/string.h" #include "frozen/unordered_map.h" @@ -550,9 +552,88 @@ namespace iguana::detail { #define MAKE_STR_LIST(...) \ MACRO_CONCAT(CON_STR, GET_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__) +template +struct identity {}; + +struct field_info { + size_t offset; + std::string_view type_name; +}; + +struct base { + virtual void to_pb(std::string &str) {} + virtual void from_pb(std::string_view str) {} + virtual std::vector get_fields_name() { return {}; } + virtual iguana::detail::field_info get_field_info(std::string_view name) { + return {}; + } + + template + T &get_field_value(std::string_view name) { + auto info = get_field_info(name); + check_field(name, info); + auto ptr = (((char *)this) + info.offset); + return *((T *)ptr); + } + + template + void set_field_value(std::string_view name, T val) { + auto info = get_field_info(name); + check_field(name, info); + + auto ptr = (((char *)this) + info.offset); + + *((T *)ptr) = std::move(val); + } + virtual ~base() {} + + private: + template + void check_field(std::string_view name, const field_info &info) { + if (info.offset == 0) { + throw std::invalid_argument(std::string(name) + " field not exist "); + } + +#if defined(__clang__) || defined(_MSC_VER) || \ + (defined(__GNUC__) && __GNUC__ > 8) + if (info.type_name != iguana::type_string()) { + std::string str = "type is not match: can not assign "; + str.append(iguana::type_string()); + str.append(" to ").append(info.type_name); + + throw std::invalid_argument(str); + } +#endif + } +}; + +inline std::unordered_map()>> + g_pb_map; + +template +inline bool register_type() { +#if defined(__clang__) || defined(_MSC_VER) || \ + (defined(__GNUC__) && __GNUC__ > 8) + if constexpr (std::is_base_of_v) { + auto it = g_pb_map.emplace(type_string(), [] { + return std::make_shared(); + }); + return it.second; + } + else { + return true; + } +#else + return true; +#endif +} + #define MAKE_META_DATA_IMPL(STRUCT_NAME, ...) \ + static inline bool IGUANA_UNIQUE_VARIABLE(reg_var) = \ + iguana::detail::register_type(); \ [[maybe_unused]] inline static auto iguana_reflect_members( \ - STRUCT_NAME const &) { \ + const iguana::detail::identity &) { \ struct reflect_members { \ constexpr decltype(auto) static apply_impl() { \ return std::make_tuple(__VA_ARGS__); \ @@ -602,7 +683,7 @@ constexpr std::array get_alias_arr(Args... pairs) { #define MAKE_META_DATA_IMPL_ALIAS(STRUCT_NAME, ALIAS, ...) \ [[maybe_unused]] inline static auto iguana_reflect_members( \ - STRUCT_NAME const &) { \ + const iguana::detail::identity &) { \ struct reflect_members { \ constexpr decltype(auto) static apply_impl() { \ return iguana::detail::get_mem_ptr_tp(__VA_ARGS__); \ @@ -622,7 +703,8 @@ constexpr std::array get_alias_arr(Args... pairs) { } #define MAKE_META_DATA_IMPL_EMPTY(STRUCT_NAME) \ - inline auto iguana_reflect_members(STRUCT_NAME const &) { \ + inline auto iguana_reflect_members( \ + const iguana::detail::identity &) { \ struct reflect_members { \ constexpr decltype(auto) static apply_impl() { \ return std::make_tuple(); \ @@ -692,6 +774,143 @@ inline constexpr auto get_iguana_struct_map() { } } +template ::value_type> +struct field_t { + using member_type = T; + using owner_type = typename member_traits::owner_type; + using value_type = typename member_traits::value_type; + using sub_type = ElementType; + constexpr field_t() = default; + constexpr field_t(T member, uint32_t number, frozen::string name = "") + : member_ptr(member), field_name(name), field_no(number) {} + + T member_ptr; + frozen::string field_name; + uint32_t field_no; + + auto &value(owner_type &value) const { return value.*member_ptr; } +}; + +template +struct field_type_t; + +template +struct field_type_t> { + using value_type = std::variant; +}; + +template +struct is_custom_reflection : std::false_type {}; + +template +struct is_custom_reflection< + T, std::void_t()))>> + : std::true_type {}; + +template +struct is_reflection : std::false_type {}; + +template +inline constexpr bool is_reflection_v = is_reflection::value; + +template +inline constexpr bool is_custom_reflection_v = is_custom_reflection::value; + +template +constexpr inline auto build_variant_fields(T t, S &s, uint32_t base_idx, + std::index_sequence) { + using value_type = typename member_traits::value_type; + return std::tuple(field_t>{ + t, (base_idx + uint32_t(I)), s}...); +} + +template +constexpr inline auto build_fields(T t, S &s, uint32_t &index) { + using value_type = typename member_traits::value_type; + if constexpr (is_variant::value) { + constexpr uint32_t Size = std::variant_size_v; + index += (Size - 1); + return build_variant_fields(t, s, I + 1, std::make_index_sequence{}); + } + else { + uint32_t field_no = (I == index) ? (I + 1) : (I + index); + index++; + return std::tuple(field_t{t, field_no, s}); + } +} + +template +constexpr inline auto get_members_tuple_impl(T &&tp, U &&arr, + std::index_sequence &&) { + uint32_t index = 0; + return std::tuple_cat(build_fields(std::get(tp), arr[I], index)...); +} + +template +constexpr inline auto get_members_tuple() { + if constexpr (is_reflection::value) { + using reflect_members = decltype(iguana_reflect_type(std::declval())); + using Tuple = decltype(reflect_members::apply_impl()); + constexpr size_t Size = std::tuple_size_v; + return get_members_tuple_impl(reflect_members::apply_impl(), + reflect_members::arr(), + std::make_index_sequence{}); + } + else if constexpr (is_custom_reflection_v) { + using U = std::remove_const_t>; + return get_members_impl((U *)nullptr); + } + else { + static_assert(!sizeof(T), "expected reflection or custom reflection"); + } +} + +template +constexpr auto inline get_members_impl(Tuple &&tp, std::index_sequence) { + return frozen::unordered_map{ + {std::get(tp).field_no, + T{std::in_place_index, std::move(std::get(tp))}}...}; +} + +template +constexpr size_t count_variant_size() { + if constexpr (is_variant::value) { + return std::variant_size_v; + } + else { + return 1; + } +} + +template +constexpr size_t tuple_type_count_impl(std::index_sequence) { + return ( + (count_variant_size>>() + + ...)); +} + +template +constexpr size_t tuple_type_count() { + return tuple_type_count_impl( + std::make_index_sequence>{}); +} + +template +constexpr inline auto get_members() { + if constexpr (is_reflection_v || is_custom_reflection_v) { + constexpr auto tp = get_members_tuple(); + using Tuple = std::decay_t; + using value_type = typename field_type_t::value_type; + constexpr auto Size = tuple_type_count(); + return get_members_impl(tp, + std::make_index_sequence{}); + } + else { + static_assert(!sizeof(T), "expected reflection or custom reflection"); + } +} + #define REFLECTION(STRUCT_NAME, ...) \ MAKE_META_DATA(STRUCT_NAME, #STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), \ __VA_ARGS__) @@ -703,11 +922,7 @@ inline constexpr auto get_iguana_struct_map() { STRUCT_NAME, ALIAS, \ std::tuple_size_v, __VA_ARGS__) -#ifdef _MSC_VER #define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __COUNTER__) -#else -#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __LINE__) -#endif template struct iguana_required_struct; #define REQUIRED_IMPL(STRUCT_NAME, N, ...) \ @@ -762,12 +977,6 @@ inline int add_custom_fields(std::string_view key, return 0; } -#ifdef _MSC_VER -#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __COUNTER__) -#else -#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __LINE__) -#endif - #define CUSTOM_FIELDS_IMPL(STRUCT_NAME, N, ...) \ inline auto IGUANA_UNIQUE_VARIABLE(STRUCT_NAME) = iguana::add_custom_fields( \ #STRUCT_NAME, {MARCO_EXPAND(MACRO_CONCAT(CON_STR, N)(__VA_ARGS__))}); @@ -776,14 +985,16 @@ inline int add_custom_fields(std::string_view key, CUSTOM_FIELDS_IMPL(STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__) template -using Reflect_members = decltype(iguana_reflect_members(std::declval())); +using Reflect_members = decltype(iguana_reflect_members( + std::declval>())); template struct is_public_reflection : std::false_type {}; template -struct is_public_reflection< - T, std::void_t()))>> +struct is_public_reflection>()))>> : std::true_type {}; template @@ -795,14 +1006,11 @@ struct is_private_reflection : std::false_type {}; template struct is_private_reflection< T, std::void_t().iguana_reflect_members( - std::declval()))>> : std::true_type {}; + std::declval>()))>> : std::true_type {}; template constexpr bool is_private_reflection_v = is_private_reflection::value; -template -struct is_reflection : std::false_type {}; - template struct is_reflection>> : std::true_type {}; @@ -813,17 +1021,14 @@ struct is_reflection>> template inline auto iguana_reflect_type(const T &t) { - if constexpr (is_public_reflection_v) { - return iguana_reflect_members(t); + if constexpr (is_public_reflection_v>) { + return iguana_reflect_members(iguana::detail::identity{}); } else { - return t.iguana_reflect_members(t); + return t.iguana_reflect_members(iguana::detail::identity{}); } } -template -inline constexpr bool is_reflection_v = is_reflection::value; - template typename Condition, typename Tuple, typename Owner> constexpr int element_index_helper() { @@ -1112,7 +1317,8 @@ constexpr void for_each(const std::tuple &t, F &&f, } template -constexpr std::enable_if_t::value> for_each(T &&t, F &&f) { +constexpr std::enable_if_t>::value> for_each( + T &&t, F &&f) { using M = decltype(iguana_reflect_type(std::forward(t))); for_each(M::apply_impl(), std::forward(f), std::make_index_sequence{}); diff --git a/include/ylt/standalone/iguana/util.hpp b/include/ylt/standalone/iguana/util.hpp index 47959618a..3f6768a91 100644 --- a/include/ylt/standalone/iguana/util.hpp +++ b/include/ylt/standalone/iguana/util.hpp @@ -130,12 +130,6 @@ constexpr inline bool shared_ptr_v = template constexpr inline bool smart_ptr_v = shared_ptr_v || unique_ptr_v; -template -struct is_variant : std::false_type {}; - -template -struct is_variant> : std::true_type {}; - template constexpr inline bool variant_v = is_variant>::value; diff --git a/include/ylt/standalone/iguana/version.hpp b/include/ylt/standalone/iguana/version.hpp index 202ea4a3a..bdb1121b5 100644 --- a/include/ylt/standalone/iguana/version.hpp +++ b/include/ylt/standalone/iguana/version.hpp @@ -5,4 +5,4 @@ // IGUANA_VERSION % 100 is the sub-minor version // IGUANA_VERSION / 100 % 1000 is the minor version // IGUANA_VERSION / 100000 is the major version -#define IGUANA_VERSION 100004 // 1.0.4 \ No newline at end of file +#define IGUANA_VERSION 100005 // 1.0.5 \ No newline at end of file diff --git a/include/ylt/struct_pb.hpp b/include/ylt/struct_pb.hpp index a57ea241d..b49a220eb 100644 --- a/include/ylt/struct_pb.hpp +++ b/include/ylt/struct_pb.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Alibaba Group Holding Limited; + * Copyright (c) 2024, Alibaba Group Holding Limited; * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,89 +14,4 @@ * limitations under the License. */ #pragma once -#include -#include -#include -#include -#if defined __clang__ -#define STRUCT_PB_INLINE __attribute__((always_inline)) inline -#elif defined _MSC_VER -#define STRUCT_PB_INLINE __forceinline -#else -#define STRUCT_PB_INLINE __attribute__((always_inline)) inline -#endif -#define STRUCT_PB_NODISCARD [[nodiscard]] -namespace struct_pb { - -struct UnknownFields { - STRUCT_PB_NODISCARD std::size_t total_size() const { - std::size_t total = 0; - for (const auto& f : fields) { - total += f.len; - } - return total; - } - void serialize_to(char* data, std::size_t& pos, std::size_t size) const { - for (const auto& f : fields) { - assert(pos + f.len <= size); - std::memcpy(data + pos, f.data, f.len); - pos += f.len; - } - } - void add_field(const char* data, std::size_t start, std::size_t end) { - fields.push_back(Field{data + start, end - start}); - } - struct Field { - const char* data; - std::size_t len; - }; - std::vector fields; -}; -/* - * Low-Level API for struct_pb user - * the following internal API will be generated by struct_pb protoc plugin - */ -namespace internal { -template -STRUCT_PB_NODISCARD std::size_t get_needed_size( - const T& t, const UnknownFields& unknown_fields = {}); -template -void serialize_to(char* data, std::size_t size, const T& t, - const UnknownFields& unknown_fields = {}); -template -STRUCT_PB_NODISCARD bool deserialize_to(T& t, const char* data, - std::size_t size, - UnknownFields& unknown_fields); -template -STRUCT_PB_NODISCARD bool deserialize_to(T& t, const char* data, - std::size_t size); -} // namespace internal - -/* - * High-Level API for struct_pb user - * If you need more fine-grained operations, encapsulate the internal API - * yourself. - */ -template , typename T> -STRUCT_PB_NODISCARD Buffer serialize(const T& t, - const UnknownFields& unknown_fields = {}) { - Buffer buffer; - auto size = struct_pb::internal::get_needed_size(t, unknown_fields); - buffer.resize(size); - struct_pb::internal::serialize_to(buffer.data(), buffer.size(), t, - unknown_fields); - return buffer; -} -template -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_to( - T& t, UnknownFields& unknown_fields, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size(), - unknown_fields); -} -template -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_to(T& t, - const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size()); -} - -} // namespace struct_pb +#include "struct_pb/struct_pb_impl.hpp" diff --git a/include/ylt/struct_pb/struct_pb_impl.hpp b/include/ylt/struct_pb/struct_pb_impl.hpp index 12a2a76c2..909995d8c 100644 --- a/include/ylt/struct_pb/struct_pb_impl.hpp +++ b/include/ylt/struct_pb/struct_pb_impl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Alibaba Group Holding Limited; + * Copyright (c) 2024, Alibaba Group Holding Limited; * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,171 +14,6 @@ * limitations under the License. */ #pragma once -#include -#include -#include -#include -#include - -#include "ylt/struct_pb.hpp" - -namespace struct_pb { - -namespace internal { -STRUCT_PB_NODISCARD STRUCT_PB_INLINE uint32_t encode_zigzag(int32_t v) { - return (static_cast(v) << 1U) ^ - static_cast( - -static_cast(static_cast(v) >> 31U)); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE uint64_t encode_zigzag(int64_t v) { - return (static_cast(v) << 1U) ^ - static_cast( - -static_cast(static_cast(v) >> 63U)); -} - -STRUCT_PB_NODISCARD STRUCT_PB_INLINE int64_t decode_zigzag(uint64_t u) { - return static_cast((u >> 1U)) ^ - static_cast(-static_cast(u & 1U)); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE int64_t decode_zigzag(uint32_t u) { - return static_cast((u >> 1U)) ^ - static_cast(-static_cast(u & 1U)); -} - -STRUCT_PB_NODISCARD STRUCT_PB_INLINE std::size_t calculate_varint_size( - uint64_t v) { - std::size_t ret = 0; - do { - ret++; - v >>= 7; - } while (v != 0); - return ret; -} - -[[nodiscard]] STRUCT_PB_INLINE bool decode_varint(const char* data, - std::size_t& pos_, - std::size_t size_, - uint64_t& v) { - // fix test failed on arm due to different char definition - const signed char* data_ = reinterpret_cast(data); - // from https://github.com/facebook/folly/blob/main/folly/Varint.h - if (pos_ < size_ && (static_cast(data_[pos_]) & 0x80U) == 0) { - v = static_cast(data_[pos_]); - pos_++; - return true; - } - constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1; - uint64_t val = 0; - if (size_ - pos_ >= max_varint_length) [[likely]] { - do { - // clang-format off - int64_t b = data_[pos_++]; - val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; } - // clang-format on - return false; - } while (false); - } - else { - unsigned int shift = 0; - while (pos_ != size_ && int64_t(data_[pos_]) < 0) { - val |= (uint64_t(data_[pos_++]) & 0x7fU) << shift; - shift += 7; - } - if (pos_ == size_) { - return false; - } - val |= uint64_t(data_[pos_++]) << shift; - } - v = val; - return true; -} -STRUCT_PB_INLINE void serialize_varint(char* const data, std::size_t& pos, - std::size_t size, uint64_t v) { - while (v >= 0x80) { - assert(pos < size); - data[pos++] = static_cast(v | 0x80); - v >>= 7; - } - data[pos++] = static_cast(v); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_varint(const char* data, - std::size_t& pos, - std::size_t size, - uint64_t& v) { - return decode_varint(data, pos, size, v); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool read_tag(const char* data, - std::size_t& pos, - std::size_t size, - uint64_t& tag) { - return deserialize_varint(data, pos, size, tag); -} -inline bool deserialize_unknown(const char* data, std::size_t& pos, - std::size_t size, uint32_t tag, - UnknownFields& unknown_fields) { - uint32_t field_number = tag >> 3; - if (field_number == 0) { - return false; - } - auto offset = internal::calculate_varint_size(tag); - auto start = pos - offset; - uint32_t wire_type = tag & 0b0000'0111; - switch (wire_type) { - case 0: { - uint64_t t; - auto ok = internal::deserialize_varint(data, pos, size, t); - if (!ok) [[unlikely]] { - return false; - } - unknown_fields.add_field(data, start, pos); - break; - } - case 1: { - static_assert(sizeof(double) == 8); - if (pos + 8 > size) [[unlikely]] { - return false; - } - pos += 8; - unknown_fields.add_field(data, start, pos); - break; - } - case 2: { - uint64_t sz; - auto ok = internal::deserialize_varint(data, pos, size, sz); - if (!ok) [[unlikely]] { - return false; - } - if (pos + sz > size) [[unlikely]] { - return false; - } - pos += sz; - unknown_fields.add_field(data, start, pos); - break; - } - case 5: { - static_assert(sizeof(float) == 4); - if (pos + 4 > size) [[unlikely]] { - return false; - } - pos += 4; - unknown_fields.add_field(data, start, pos); - break; - } - default: { - assert(false && "error path"); - } - } - return true; -} -} // namespace internal - -} // namespace struct_pb \ No newline at end of file +#include +#include +namespace struct_pb = iguana; diff --git a/src/struct_pack/benchmark/BUILD.bazel b/src/struct_pack/benchmark/BUILD.bazel index e9947217b..0ec3b71fc 100644 --- a/src/struct_pack/benchmark/BUILD.bazel +++ b/src/struct_pack/benchmark/BUILD.bazel @@ -10,6 +10,7 @@ cc_binary( "no_op.cpp", "no_op.h", "sample.hpp", + "struct_pb_sample.hpp", "struct_pack_sample.hpp", "msgpack_sample.hpp" ], diff --git a/src/struct_pack/benchmark/CMakeLists.txt b/src/struct_pack/benchmark/CMakeLists.txt index 450428fd9..3054843e3 100644 --- a/src/struct_pack/benchmark/CMakeLists.txt +++ b/src/struct_pack/benchmark/CMakeLists.txt @@ -15,19 +15,6 @@ if (Protobuf_FOUND) target_link_libraries(struct_pack_benchmark PRIVATE protobuf::libprotobuf) target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_PROTOBUF) - if (BUILD_STRUCT_PB) - protobuf_generate_struct_pb(STRUCT_PACK_BENCHMARK_PROTO_SRCS2 - STRUCT_PACK_BENCHMARK_PROTO_HDRS2 - data_def.proto - OPTION "namespace=struct_pb_sample" - ) - target_sources(struct_pack_benchmark PRIVATE - ${STRUCT_PACK_BENCHMARK_PROTO_SRCS2} - ${STRUCT_PACK_BENCHMARK_PROTO_HDRS2} - ) - target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_STRUCT_PB) - endif() - target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_PROTOBUF) endif () target_compile_definitions(struct_pack_benchmark PRIVATE MSGPACK_NO_BOOST) diff --git a/src/struct_pack/benchmark/benchmark.cpp b/src/struct_pack/benchmark/benchmark.cpp index f32e2e160..7a5128799 100644 --- a/src/struct_pack/benchmark/benchmark.cpp +++ b/src/struct_pack/benchmark/benchmark.cpp @@ -1,7 +1,7 @@ #include #include #include - +#define SEQUENTIAL_PARSE #include "struct_pack_sample.hpp" #if __has_include() @@ -14,10 +14,8 @@ #ifdef HAVE_PROTOBUF #include "protobuf_sample.hpp" -#ifdef HAVE_STRUCT_PB -#include "struct_pb_sample.hpp" -#endif #endif +#include "struct_pb_sample.hpp" #ifdef HAVE_FLATBUFFER #include "flatbuffer_sample.hpp" #endif @@ -120,11 +118,9 @@ int main(int argc, char** argv) { map.emplace(LibType::MSGPACK, new message_pack_sample()); #endif #ifdef HAVE_PROTOBUF -#ifdef HAVE_STRUCT_PB - map.emplace(LibType::STRUCT_PB, new struct_pb_sample::struct_pb_sample_t()); -#endif map.emplace(LibType::PROTOBUF, new protobuf_sample_t()); #endif + map.emplace(LibType::STRUCT_PB, new struct_pb_sample()); #ifdef HAVE_FLATBUFFER map.emplace(LibType::FLATBUFFER, new flatbuffer_sample_t()); #endif @@ -143,9 +139,7 @@ int main(int argc, char** argv) { run_benchmark(map, LibType::STRUCT_PACK); -#ifdef HAVE_STRUCT_PB run_benchmark(map, LibType::STRUCT_PB); -#endif return 0; } diff --git a/src/struct_pack/benchmark/protobuf_sample.hpp b/src/struct_pack/benchmark/protobuf_sample.hpp index 72f98b356..b9238e5b6 100644 --- a/src/struct_pack/benchmark/protobuf_sample.hpp +++ b/src/struct_pack/benchmark/protobuf_sample.hpp @@ -211,8 +211,6 @@ struct protobuf_sample_t : public base_sample { buffer_.clear(); sample.SerializeToString(&buffer_); - T obj; - uint64_t ns = 0; std::string bench_name = name() + " deserialize " + get_sample_name(sample_type); @@ -220,6 +218,7 @@ struct protobuf_sample_t : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { + T obj; obj.ParseFromString(buffer_); no_op((char *)&obj); no_op(buffer_); diff --git a/src/struct_pack/benchmark/struct_pack_sample.hpp b/src/struct_pack/benchmark/struct_pack_sample.hpp index 1b19bd746..7a798642b 100644 --- a/src/struct_pack/benchmark/struct_pack_sample.hpp +++ b/src/struct_pack/benchmark/struct_pack_sample.hpp @@ -148,8 +148,6 @@ struct struct_pack_sample : public base_sample { buffer_.clear(); struct_pack::serialize_to(buffer_, sample); - U obj; - uint64_t ns = 0; std::string bench_name = name() + " deserialize " + get_sample_name(sample_type); @@ -157,6 +155,7 @@ struct struct_pack_sample : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { + U obj; [[maybe_unused]] auto ec = struct_pack::deserialize_to(obj, buffer_); no_op((char *)&obj); no_op(buffer_); diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index bfec902d0..53ca2fae2 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -1,162 +1,208 @@ #pragma once -#include -#include -#include -#include +#include #include "ScopedTimer.hpp" #include "no_op.h" #include "sample.hpp" -#ifdef HAVE_PROTOBUF -#include "data_def.struct_pb.h" -#endif +namespace pb_sample { +struct person : public iguana::base_impl { + person() = default; + person(int32_t a, std::string b, int c, double d) + : id(a), name(std::move(b)), age(c), salary(d) {} + int32_t id; + std::string name; + int age; + double salary; +}; +REFLECTION(person, id, name, age, salary); + +struct persons : public iguana::base_impl { + persons() = default; + explicit persons(std::vector l) : list(std::move(l)) {} + std::vector list; +}; +REFLECTION(persons, list); + +struct rect : public iguana::base_impl { + rect() = default; + rect(int32_t a, int32_t b, int32_t c, int32_t d) + : x(a), y(b), width(c), height(d) {} + int32_t x = 1; + int32_t y = 0; + int32_t width = 11; + int32_t height = 1; +}; +REFLECTION(rect, x, y, width, height); + +struct rects : public iguana::base_impl { + rects() = default; + explicit rects(std::vector l) : list(std::move(l)) {} + std::vector list; +}; +REFLECTION(rects, list); + +struct Vec3 : public iguana::base_impl { + Vec3() = default; + Vec3(float a, float b, float c) : x(a), y(b), z(c) {} + float x; + float y; + float z; + + REFLECTION(Vec3, x, y, z); +}; -namespace struct_pb_sample { +struct Weapon : public iguana::base_impl { + Weapon() = default; + Weapon(std::string s, int32_t d) : name(std::move(s)), damage(d) {} + std::string name; + int32_t damage; +}; +REFLECTION(Weapon, name, damage); + +enum Color : uint8_t { Red, Green, Blue }; + +struct Monster : public iguana::base_impl { + Monster() = default; + Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, Color f, + std::vector g, Weapon h, std::vector i) {} + Vec3 pos; + int32_t mana; + int32_t hp; + std::string name; + std::string inventory; + Color color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, + path); -inline auto create_rects(std::size_t object_count) { - rect32s rcs; - for (int i = 0; i < object_count; ++i) { - rect32 rc{1, 0, 11, 1}; - rcs.rect32_list.emplace_back(rc); +struct Monsters : public iguana::base_impl { + Monsters() = default; + explicit Monsters(std::vector l) : list(std::move(l)) {} + std::vector list; +}; +REFLECTION(Monsters, list); + +inline auto create_rects(size_t object_count) { + rect rc{1, 0, 11, 1}; + std::vector v{}; + for (std::size_t i = 0; i < object_count; i++) { + v.push_back(rc); } - return rcs; + return v; } -inline auto create_persons(std::size_t object_count) { - persons ps; - for (int i = 0; i < object_count; ++i) { - person p{.id = 432798, - .name = std::string(1024, 'A'), - .age = 24, - .salary = 65536.42}; - ps.person_list.emplace_back(p); + +inline auto create_persons(size_t object_count) { + std::vector v{}; + person p{432798, std::string(1024, 'A'), 24, 65536.42}; + + for (std::size_t i = 0; i < object_count; i++) { + v.push_back(p); } - return ps; + return v; } -inline auto create_monsters(std::size_t object_count) { - Monsters monsters; - for (int i = 0; i < object_count / 2; ++i) { - { - Monster m{}; - m.pos = std::make_unique(); - *m.pos = struct_pb_sample::Vec3{1, 2, 3}; - // m.pos = {1, 2, 3}; - m.mana = 16; - m.hp = 24; - m.name = "it is a test"; - m.inventory = "\1\2\3\4"; - m.color = Monster::Color::Red; - m.weapons = {{"gun", 42}, {"shotgun", 56}}; - m.equipped = std::make_unique(); - *m.equipped = struct_pb_sample::Weapon{"air craft", 67}; - // m.equipped = {"air craft", 67}; - m.path = {{7, 8, 9}, {71, 81, 91}}; - monsters.monsters.push_back(std::move(m)); - } - { - Monster m; - m.pos = std::make_unique(); - *m.pos = struct_pb_sample::Vec3{11, 22, 33}; - m.mana = 161; - m.hp = 241; - m.name = "it is a test, ok"; - m.inventory = "\24\25\26\24"; - m.color = Monster::Color::Red; - m.weapons = {{"gun", 421}, {"shotgun", 561}}; - m.equipped = std::make_unique(); - *m.equipped = struct_pb_sample::Weapon{"air craft", 671}; - // m.equipped = {"air craft", 671}; - m.path = {{71, 82, 93}, {711, 821, 931}}; - monsters.monsters.push_back(std::move(m)); - } + +inline std::vector create_monsters(size_t object_count) { + std::vector v{}; + Monster m = { + Vec3{1, 2, 3}, + 16, + 24, + "it is a test", + "\1\2\3\4", + Color::Red, + {{"gun", 42}, {"shotgun", 56}}, + {"air craft", 67}, + {{7, 8, 9}, {71, 81, 91}}, + }; + + Monster m1 = { + {11, 22, 33}, + 161, + 241, + "it is a test, ok", + "\24\25\26\24", + Color::Red, + {{"gun", 421}, {"shotgun", 561}}, + {"air craft", 671}, + {{71, 82, 93}, {711, 821, 931}}, + }; + + for (std::size_t i = 0; i < object_count / 2; i++) { + v.push_back(m); + v.push_back(m1); } + if (object_count % 2 == 1) { - Monster m{}; - m.pos = std::make_unique(); - *m.pos = struct_pb_sample::Vec3{1, 2, 3}; - // m.pos = {1, 2, 3}; - m.mana = 16; - m.hp = 24; - m.name = "it is a test"; - m.inventory = "\1\2\3\4"; - m.color = Monster::Color::Red; - m.weapons = {{"gun", 42}, {"shotgun", 56}}; - m.equipped = std::make_unique(); - *m.equipped = struct_pb_sample::Weapon{"air craft", 67}; - // m.equipped = {"air craft", 67}; - m.path = {{7, 8, 9}, {71, 81, 91}}; - monsters.monsters.push_back(std::move(m)); + v.push_back(m); } - return monsters; + + return v; } +} // namespace pb_sample -struct struct_pb_sample_t : public base_sample { +struct struct_pb_sample : public base_sample { static inline constexpr LibType lib_type = LibType::STRUCT_PB; std::string name() const override { return get_lib_name(lib_type); } void create_samples() override { - rects_ = struct_pb_sample::create_rects(OBJECT_COUNT); - persons_ = struct_pb_sample::create_persons(OBJECT_COUNT); - monsters_ = struct_pb_sample::create_monsters(OBJECT_COUNT); + rects_.list = {pb_sample::create_rects(OBJECT_COUNT)}; + persons_.list = {pb_sample::create_persons(OBJECT_COUNT)}; + monsters_.list = {pb_sample::create_monsters(OBJECT_COUNT)}; } void do_serialization() override { - serialize(SampleType::RECT, rects_.rect32_list[0]); + serialize(SampleType::RECT, rects_.list[0]); + struct_pb::to_pb(rects_, buffer_); + struct_pb::to_pb(rects_, buffer_); + struct_pb::to_pb(rects_, buffer_); + std::cout << rects_.list.size() << "\n"; serialize(SampleType::RECTS, rects_); - serialize(SampleType::PERSON, persons_.person_list[0]); + serialize(SampleType::PERSON, persons_.list[0]); serialize(SampleType::PERSONS, persons_); - serialize(SampleType::MONSTER, monsters_.monsters[0]); + serialize(SampleType::MONSTER, monsters_.list[0]); serialize(SampleType::MONSTERS, monsters_); } void do_deserialization() override { - deserialize(SampleType::RECT, rects_.rect32_list[0]); + deserialize(SampleType::RECT, rects_.list[0]); deserialize(SampleType::RECTS, rects_); - deserialize(SampleType::PERSON, persons_.person_list[0]); + deserialize(SampleType::PERSON, persons_.list[0]); deserialize(SampleType::PERSONS, persons_); - deserialize(SampleType::MONSTER, monsters_.monsters[0]); + deserialize(SampleType::MONSTER, monsters_.list[0]); deserialize(SampleType::MONSTERS, monsters_); } private: template - void serialize(SampleType sample_type, T& sample) { - auto sz = struct_pb::internal::get_needed_size(sample); - buffer_.resize(sz); - struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample); - buffer_.clear(); - buffer_.resize(sz); - - uint64_t ns = 0; - std::string bench_name = - name() + " serialize " + get_sample_name(sample_type); - + void serialize(SampleType sample_type, T &sample) { { - ScopedTimer timer(bench_name.data(), ns); - for (int i = 0; i < ITERATIONS; ++i) { - buffer_.clear(); - auto sz = struct_pb::internal::get_needed_size(sample); - buffer_.resize(sz); - struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), - sample); - no_op(buffer_); - no_op((char*)&sample); + struct_pb::to_pb(sample, buffer_); + buffer_.clear(); + + uint64_t ns = 0; + std::string bench_name = + name() + " serialize " + get_sample_name(sample_type); + + { + ScopedTimer timer(bench_name.data(), ns); + for (int i = 0; i < ITERATIONS; ++i) { + struct_pb::to_pb(sample, buffer_); + no_op(buffer_); + no_op((char *)&sample); + } } + ser_time_elapsed_map_.emplace(sample_type, ns); } - - ser_time_elapsed_map_.emplace(sample_type, ns); buf_size_map_.emplace(sample_type, buffer_.size()); } - - template - void deserialize(SampleType sample_type, T& sample) { + template + void deserialize(SampleType sample_type, T &sample) { buffer_.clear(); - auto sz = struct_pb::internal::get_needed_size(sample); - buffer_.resize(sz); - struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample); - - T obj; - // vec.resize(ITERATIONS); + struct_pb::to_pb(sample, buffer_); uint64_t ns = 0; std::string bench_name = @@ -165,21 +211,17 @@ struct struct_pb_sample_t : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { - [[maybe_unused]] auto ok = struct_pb::internal::deserialize_to( - obj, buffer_.data(), buffer_.size()); - assert(ok); - no_op((char*)&obj); + U obj; + struct_pb::from_pb(obj, buffer_); + no_op((char *)&obj); no_op(buffer_); } } deser_time_elapsed_map_.emplace(sample_type, ns); - - buf_size_map_.emplace(sample_type, buffer_.size()); } - struct_pb_sample::rect32s rects_; - struct_pb_sample::persons persons_; - struct_pb_sample::Monsters monsters_; + pb_sample::rects rects_; + pb_sample::persons persons_; + pb_sample::Monsters monsters_; std::string buffer_; }; -} // namespace struct_pb_sample \ No newline at end of file diff --git a/src/struct_pb/CMakeLists.txt b/src/struct_pb/CMakeLists.txt deleted file mode 100644 index 0dc65fab8..000000000 --- a/src/struct_pb/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(protoc-plugin) -add_subdirectory(conformance) diff --git a/src/struct_pb/conformance/CMakeLists.txt b/src/struct_pb/conformance/CMakeLists.txt deleted file mode 100644 index 20c962de6..000000000 --- a/src/struct_pb/conformance/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests/struct_pb) -find_package(Protobuf QUIET) -if (NOT Protobuf_FOUND) - message(INFO "to build struct_pb conformance test, you must install libprotoc first") - return() -endif () -set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(conformance_test_runner - binary_json_conformance_suite.cc - binary_json_conformance_suite.h - conformance_test_runner.cc - conformance_test_main.cc - conformance_test.cc - conformance_test.h - ) -target_sources(conformance_test_runner PRIVATE - conformance/conformance.proto - google/protobuf/test_messages_proto2.proto - google/protobuf/test_messages_proto3.proto - ) -protobuf_generate(TARGET conformance_test_runner) -target_include_directories(conformance_test_runner PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(conformance_test_runner PRIVATE protobuf::libprotobuf) -add_executable(conformance_cpp conformance_cpp.cc) -target_link_libraries(conformance_cpp PRIVATE protobuf::libprotobuf) -target_sources(conformance_cpp PRIVATE - conformance/conformance.proto - google/protobuf/test_messages_proto2.proto - google/protobuf/test_messages_proto3.proto - ) -protobuf_generate(TARGET conformance_cpp) -target_include_directories(conformance_cpp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - -add_test(NAME conformance_cpp_test - COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_test_runner - --failure_list ${CMAKE_CURRENT_SOURCE_DIR}/failure_list_cpp.txt - --output_dir ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_cpp - DEPENDS conformance_test_runner conformance_cpp) - -add_executable(conformance_struct_pb - conformance_struct_pb.cc - ) -protobuf_generate_struct_pb(SRCS HDRS - conformance/conformance.proto - google/protobuf/test_messages_proto2.proto - google/protobuf/test_messages_proto3.proto - google/protobuf/any.proto - google/protobuf/descriptor.proto - google/protobuf/duration.proto - google/protobuf/field_mask.proto - google/protobuf/struct.proto - google/protobuf/timestamp.proto - google/protobuf/type.proto - google/protobuf/wrappers.proto - google/protobuf/source_context.proto - TARGET conformance_struct_pb - ) -target_sources(conformance_struct_pb PRIVATE ${SRCS} ${HDRS}) -target_include_directories(conformance_struct_pb PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - - -add_test(NAME conformance_struct_pb_test - COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_test_runner - --failure_list ${CMAKE_CURRENT_SOURCE_DIR}/failure_list_cpp.txt - --output_dir ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_struct_pb - DEPENDS conformance_test_runner conformance_struct_pb) diff --git a/src/struct_pb/conformance/absl/status/status.h b/src/struct_pb/conformance/absl/status/status.h deleted file mode 100644 index 94ebfc9cf..000000000 --- a/src/struct_pb/conformance/absl/status/status.h +++ /dev/null @@ -1,208 +0,0 @@ -#pragma once -// absl compat -#include -#include - -#include "absl/strings/str_cat.h" -// #include "google/protobuf/stubs/status.h" -namespace absl { -// using namespace google::protobuf::util; -enum class StatusCode : int { - kOk = 0, - kCancelled = 1, - kUnknown = 2, - kInvalidArgument = 3, - kDeadlineExceeded = 4, - kNotFound = 5, - kAlreadyExists = 6, - kPermissionDenied = 7, - kResourceExhausted = 8, - kFailedPrecondition = 9, - kAborted = 10, - kOutOfRange = 11, - kUnimplemented = 12, - kInternal = 13, - kUnavailable = 14, - kDataLoss = 15, - kUnauthenticated = 16, -}; -class Status { - public: - Status(StatusCode code = StatusCode::kOk, std::string_view message = {}) - : code_(code), msg_(message) {} - bool ok() const { return code_ == StatusCode::kOk; } - std::string message() const { - // fix gcc 10 - return std::string(msg_); - } - - private: - StatusCode code_; - std::string_view msg_; - friend std::ostream& operator<<(std::ostream& os, const Status& x); -}; -inline std::ostream& operator<<(std::ostream& os, const Status& x) { - os << static_cast(x.code_) << " " << x.msg_; - return os; -} -Status DataLossError(std::string_view message) { - return Status(absl::StatusCode::kDataLoss, message); -} - -StatusCode ErrnoToStatusCode(int error_number) { - switch (error_number) { - case 0: - return StatusCode::kOk; - case EINVAL: // Invalid argument - case ENAMETOOLONG: // Filename too long - case E2BIG: // Argument list too long - case EDESTADDRREQ: // Destination address required - case EDOM: // Mathematics argument out of domain of function - case EFAULT: // Bad address - case EILSEQ: // Illegal byte sequence - case ENOPROTOOPT: // Protocol not available - case ENOSTR: // Not a STREAM - case ENOTSOCK: // Not a socket - case ENOTTY: // Inappropriate I/O control operation - case EPROTOTYPE: // Protocol wrong type for socket - case ESPIPE: // Invalid seek - return StatusCode::kInvalidArgument; - case ETIMEDOUT: // Connection timed out - case ETIME: // Timer expired - return StatusCode::kDeadlineExceeded; - case ENODEV: // No such device - case ENOENT: // No such file or directory -#ifdef ENOMEDIUM - case ENOMEDIUM: // No medium found -#endif - case ENXIO: // No such device or address - case ESRCH: // No such process - return StatusCode::kNotFound; - case EEXIST: // File exists - case EADDRNOTAVAIL: // Address not available - case EALREADY: // Connection already in progress -#ifdef ENOTUNIQ - case ENOTUNIQ: // Name not unique on network -#endif - return StatusCode::kAlreadyExists; - case EPERM: // Operation not permitted - case EACCES: // Permission denied -#ifdef ENOKEY - case ENOKEY: // Required key not available -#endif - case EROFS: // Read only file system - return StatusCode::kPermissionDenied; - case ENOTEMPTY: // Directory not empty - case EISDIR: // Is a directory - case ENOTDIR: // Not a directory - case EADDRINUSE: // Address already in use - case EBADF: // Invalid file descriptor -#ifdef EBADFD - case EBADFD: // File descriptor in bad state -#endif - case EBUSY: // Device or resource busy - case ECHILD: // No child processes - case EISCONN: // Socket is connected -#ifdef EISNAM - case EISNAM: // Is a named type file -#endif -#ifdef ENOTBLK - case ENOTBLK: // Block device required -#endif - case ENOTCONN: // The socket is not connected - case EPIPE: // Broken pipe -#ifdef ESHUTDOWN - case ESHUTDOWN: // Cannot send after transport endpoint shutdown -#endif - case ETXTBSY: // Text file busy -#ifdef EUNATCH - case EUNATCH: // Protocol driver not attached -#endif - return StatusCode::kFailedPrecondition; - case ENOSPC: // No space left on device -#ifdef EDQUOT - case EDQUOT: // Disk quota exceeded -#endif - case EMFILE: // Too many open files - case EMLINK: // Too many links - case ENFILE: // Too many open files in system - case ENOBUFS: // No buffer space available - case ENODATA: // No message is available on the STREAM read queue - case ENOMEM: // Not enough space - case ENOSR: // No STREAM resources -#ifdef EUSERS - case EUSERS: // Too many users -#endif - return StatusCode::kResourceExhausted; -#ifdef ECHRNG - case ECHRNG: // Channel number out of range -#endif - case EFBIG: // File too large - case EOVERFLOW: // Value too large to be stored in data type - case ERANGE: // Result too large - return StatusCode::kOutOfRange; -#ifdef ENOPKG - case ENOPKG: // Package not installed -#endif - case ENOSYS: // Function not implemented - case ENOTSUP: // Operation not supported - case EAFNOSUPPORT: // Address family not supported -#ifdef EPFNOSUPPORT - case EPFNOSUPPORT: // Protocol family not supported -#endif - case EPROTONOSUPPORT: // Protocol not supported -#ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: // Socket type not supported -#endif - case EXDEV: // Improper link - return StatusCode::kUnimplemented; - case EAGAIN: // Resource temporarily unavailable -#ifdef ECOMM - case ECOMM: // Communication error on send -#endif - case ECONNREFUSED: // Connection refused - case ECONNABORTED: // Connection aborted - case ECONNRESET: // Connection reset - case EINTR: // Interrupted function call -#ifdef EHOSTDOWN - case EHOSTDOWN: // Host is down -#endif - case EHOSTUNREACH: // Host is unreachable - case ENETDOWN: // Network is down - case ENETRESET: // Connection aborted by network - case ENETUNREACH: // Network unreachable - case ENOLCK: // No locks available - case ENOLINK: // Link has been severed -#ifdef ENONET - case ENONET: // Machine is not on the network -#endif - return StatusCode::kUnavailable; - case EDEADLK: // Resource deadlock avoided -#ifdef ESTALE - case ESTALE: // Stale file handle -#endif - return StatusCode::kAborted; - case ECANCELED: // Operation cancelled - return StatusCode::kCancelled; - default: - return StatusCode::kUnknown; - } -} -std::string MessageForErrnoToStatus(int error_number, std::string message) { - return message + ": " + std::to_string(error_number); -} -Status ErrnoToStatus(int error_number, std::string message) { - return Status(ErrnoToStatusCode(error_number), - MessageForErrnoToStatus(error_number, message)); -} -inline Status OkStatus() { return Status(); } -Status NotFoundError(std::string_view message) { - return Status(absl::StatusCode::kNotFound, message); -} -Status InvalidArgumentError(std::string_view message) { - return Status(absl::StatusCode::kInvalidArgument, message); -} -Status UnimplementedError(std::string_view message) { - return Status(absl::StatusCode::kUnimplemented, message); -} -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/absl/status/statusor.h b/src/struct_pb/conformance/absl/status/statusor.h deleted file mode 100644 index 22d1e78a0..000000000 --- a/src/struct_pb/conformance/absl/status/statusor.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -// absl compat -#include "status.h" - -namespace absl { -template -class StatusOr { - public: - StatusOr(Status status) : status_(status) {} - StatusOr(const T& data) : data_(data) {} - Status status() const { return status_; } - T* operator->() { return &data_; } - bool ok() const { return status_.ok(); } - const T& operator*() const& { return data_; } - - private: - Status status_; - T data_; -}; -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/absl/strings/str_cat.h b/src/struct_pb/conformance/absl/strings/str_cat.h deleted file mode 100644 index fedc56cfc..000000000 --- a/src/struct_pb/conformance/absl/strings/str_cat.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma -#include - -// #include "google/protobuf/stubs/strutil.h" -// compat for absl::StrCat -namespace absl { -// using google::protobuf::StrCat; -template -std::string StrCat(const T& t) { - if constexpr (std::same_as) { - return t; - } - else if constexpr (std::integral) { - return std::to_string(t); - } - else if constexpr (std::is_enum_v) { - int n = static_cast(t); - return std::to_string(n); - } - else { - return std::string(t); - } -} - -template -std::string StrCat(const T& t, const Args&... args) { - return StrCat(t) + StrCat(args...); -} -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/absl/strings/str_format.h b/src/struct_pb/conformance/absl/strings/str_format.h deleted file mode 100644 index 2160d2e0c..000000000 --- a/src/struct_pb/conformance/absl/strings/str_format.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -#include -// compat only -namespace absl { -template -auto to(const T& t) { - if constexpr (std::same_as) { - return t.c_str(); - } - else { - return t; - } -} -class SimpleAppender { - public: - SimpleAppender(std::string& buffer, std::string_view format) - : buffer(buffer), format_(format) {} - void format() { - buffer += format_.substr(index); - index = format_.size(); - } - template - void format(const T& t, const Args&... args) { - while (index < format_.size()) { - if (format_[index] != '%') { - buffer += format_[index]; - index++; - continue; - } - if (index + 1 < format_.size()) { - if (format_[index + 1] == 's') { - if constexpr (std::same_as) { - buffer += t; - } - else if constexpr (std::same_as) { - buffer += t; - } - else if constexpr (std::same_as>) { - buffer += std::string(t); - } - else { - buffer += "'ERROR FORMAT'"; - } - index++; - index++; - format(args...); - } - else if (format_[index + 1] == 'd') { - if constexpr (std::integral) { - buffer += std::to_string(t); - } - else { - buffer += "'ERROR FORMAT'"; - } - index++; - index++; - format(args...); - } - else if (format_[index + 1] == 'z') { - if (index + 2 < format_.size() && format_[index + 2] == 'u') { - if constexpr (std::integral) { - buffer += std::to_string(t); - } - else { - buffer += "'ERROR FORMAT'"; - } - index++; - index++; - index++; - format(args...); - } - } - } - else { - buffer += "'maybe ERROR FORMAT'"; - break; - } - } - } - - private: - std::string& buffer; - std::string_view format_; - int index = 0; -}; -template -void StrAppendFormat(std::string* output, const char* format, - const Args&... args) { - SimpleAppender(*output, format).format(args...); - // std::cout << "result: " << *output << std::endl; -} -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/binary_json_conformance_suite.cc b/src/struct_pb/conformance/binary_json_conformance_suite.cc deleted file mode 100644 index 858bbc2db..000000000 --- a/src/struct_pb/conformance/binary_json_conformance_suite.cc +++ /dev/null @@ -1,1606 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "binary_json_conformance_suite.h" - -#include "google/protobuf/text_format.h" -#include "google/protobuf/util/json_util.h" -#include "google/protobuf/util/type_resolver_util.h" -// #include "absl/status/status.h" -#include "absl/strings/str_cat.h" -// #include "json/json.h" -#include "conformance/conformance.pb.h" -#include "conformance_test.h" -#include "google/protobuf/test_messages_proto2.pb.h" -#include "google/protobuf/test_messages_proto3.pb.h" -#include "google/protobuf/wire_format_lite.h" - -namespace proto2_messages = protobuf_test_messages::proto2; - -using conformance::ConformanceRequest; -using conformance::ConformanceResponse; -using conformance::WireFormat; -using google::protobuf::Descriptor; -using google::protobuf::FieldDescriptor; -using google::protobuf::Message; -using google::protobuf::TextFormat; -using google::protobuf::internal::WireFormatLite; -using google::protobuf::util::NewTypeResolverForDescriptorPool; -using proto2_messages::TestAllTypesProto2; -using protobuf_test_messages::proto3::TestAllTypesProto3; -using std::string; - -namespace { - -static const char kTypeUrlPrefix[] = "type.googleapis.com"; - -// The number of repetitions to use for performance tests. -// Corresponds approx to 500KB wireformat bytes. -static const size_t kPerformanceRepeatCount = 50000; - -static string GetTypeUrl(const Descriptor* message) { - return string(kTypeUrlPrefix) + "/" + message->full_name(); -} - -/* Routines for building arbitrary protos *************************************/ - -// We would use CodedOutputStream except that we want more freedom to build -// arbitrary protos (even invalid ones). - -const string empty; - -string cat(const string& a, const string& b, const string& c = empty, - const string& d = empty, const string& e = empty, - const string& f = empty, const string& g = empty, - const string& h = empty, const string& i = empty, - const string& j = empty, const string& k = empty, - const string& l = empty) { - string ret; - ret.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() + - g.size() + h.size() + i.size() + j.size() + k.size() + l.size()); - ret.append(a); - ret.append(b); - ret.append(c); - ret.append(d); - ret.append(e); - ret.append(f); - ret.append(g); - ret.append(h); - ret.append(i); - ret.append(j); - ret.append(k); - ret.append(l); - return ret; -} - -// The maximum number of bytes that it takes to encode a 64-bit varint. -#define VARINT_MAX_LEN 10 - -size_t vencode64(uint64_t val, int over_encoded_bytes, char* buf) { - if (val == 0) { - buf[0] = 0; - return 1; - } - size_t i = 0; - while (val) { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val || over_encoded_bytes) - byte |= 0x80U; - buf[i++] = byte; - } - while (over_encoded_bytes--) { - assert(i < 10); - uint8_t byte = over_encoded_bytes ? 0x80 : 0; - buf[i++] = byte; - } - return i; -} - -string varint(uint64_t x) { - char buf[VARINT_MAX_LEN]; - size_t len = vencode64(x, 0, buf); - return string(buf, len); -} - -// Encodes a varint that is |extra| bytes longer than it needs to be, but still -// valid. -string longvarint(uint64_t x, int extra) { - char buf[VARINT_MAX_LEN]; - size_t len = vencode64(x, extra, buf); - return string(buf, len); -} - -// TODO: proper byte-swapping for big-endian machines. -string fixed32(void* data) { return string(static_cast(data), 4); } -string fixed64(void* data) { return string(static_cast(data), 8); } - -string delim(const string& buf) { return cat(varint(buf.size()), buf); } -string u32(uint32_t u32) { return fixed32(&u32); } -string u64(uint64_t u64) { return fixed64(&u64); } -string flt(float f) { return fixed32(&f); } -string dbl(double d) { return fixed64(&d); } -string zz32(int32_t x) { return varint(WireFormatLite::ZigZagEncode32(x)); } -string zz64(int64_t x) { return varint(WireFormatLite::ZigZagEncode64(x)); } - -string tag(uint32_t fieldnum, char wire_type) { - return varint((fieldnum << 3) | wire_type); -} - -string GetDefaultValue(FieldDescriptor::Type type) { - switch (type) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_BOOL: - return varint(0); - case FieldDescriptor::TYPE_SINT32: - return zz32(0); - case FieldDescriptor::TYPE_SINT64: - return zz64(0); - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - return u32(0); - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - return u64(0); - case FieldDescriptor::TYPE_FLOAT: - return flt(0); - case FieldDescriptor::TYPE_DOUBLE: - return dbl(0); - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - case FieldDescriptor::TYPE_MESSAGE: - return delim(""); - default: - return ""; - } - return ""; -} - -string GetNonDefaultValue(FieldDescriptor::Type type) { - switch (type) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_BOOL: - return varint(1); - case FieldDescriptor::TYPE_SINT32: - return zz32(1); - case FieldDescriptor::TYPE_SINT64: - return zz64(1); - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - return u32(1); - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - return u64(1); - case FieldDescriptor::TYPE_FLOAT: - return flt(1); - case FieldDescriptor::TYPE_DOUBLE: - return dbl(1); - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - return delim("a"); - case FieldDescriptor::TYPE_MESSAGE: - return delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))); - default: - return ""; - } - return ""; -} - -#define UNKNOWN_FIELD 666 - -enum class Packed { - kUnspecified = 0, - kTrue = 1, - kFalse = 2, -}; - -const FieldDescriptor* GetFieldForType(FieldDescriptor::Type type, - bool repeated, bool is_proto3, - Packed packed = Packed::kUnspecified) { - const Descriptor* d = is_proto3 ? TestAllTypesProto3().GetDescriptor() - : TestAllTypesProto2().GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { - const FieldDescriptor* f = d->field(i); - if (f->type() == type && f->is_repeated() == repeated) { - if ((packed == Packed::kTrue && !f->is_packed()) || - (packed == Packed::kFalse && f->is_packed())) { - continue; - } - return f; - } - } - - string packed_string = ""; - const string repeated_string = repeated ? "Repeated " : "Singular "; - const string proto_string = is_proto3 ? "Proto3" : "Proto2"; - if (packed == Packed::kTrue) { - packed_string = "Packed "; - } - if (packed == Packed::kFalse) { - packed_string = "Unpacked "; - } - GOOGLE_LOG(FATAL) << "Couldn't find field with type: " - << repeated_string.c_str() << packed_string.c_str() - << FieldDescriptor::TypeName(type) << " for " - << proto_string.c_str(); - return nullptr; -} - -const FieldDescriptor* GetFieldForMapType(FieldDescriptor::Type key_type, - FieldDescriptor::Type value_type, - bool is_proto3) { - const Descriptor* d = is_proto3 ? TestAllTypesProto3().GetDescriptor() - : TestAllTypesProto2().GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { - const FieldDescriptor* f = d->field(i); - if (f->is_map()) { - const Descriptor* map_entry = f->message_type(); - const FieldDescriptor* key = map_entry->field(0); - const FieldDescriptor* value = map_entry->field(1); - if (key->type() == key_type && value->type() == value_type) { - return f; - } - } - } - - const string proto_string = is_proto3 ? "Proto3" : "Proto2"; - GOOGLE_LOG(FATAL) << "Couldn't find map field with type: " - << FieldDescriptor::TypeName(key_type) << " and " - << FieldDescriptor::TypeName(key_type) << " for " - << proto_string.c_str(); - return nullptr; -} - -const FieldDescriptor* GetFieldForOneofType(FieldDescriptor::Type type, - bool is_proto3, - bool exclusive = false) { - const Descriptor* d = is_proto3 ? TestAllTypesProto3().GetDescriptor() - : TestAllTypesProto2().GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { - const FieldDescriptor* f = d->field(i); - if (f->containing_oneof() && ((f->type() == type) ^ exclusive)) { - return f; - } - } - - const string proto_string = is_proto3 ? "Proto3" : "Proto2"; - GOOGLE_LOG(FATAL) << "Couldn't find oneof field with type: " - << FieldDescriptor::TypeName(type) << " for " - << proto_string.c_str(); - return nullptr; -} - -string UpperCase(string str) { - for (size_t i = 0; i < str.size(); i++) { - str[i] = toupper(str[i]); - } - return str; -} - -std::unique_ptr NewTestMessage(bool is_proto3) { - std::unique_ptr prototype; - if (is_proto3) { - prototype.reset(new TestAllTypesProto3()); - } - else { - prototype.reset(new TestAllTypesProto2()); - } - return prototype; -} - -bool IsProto3Default(FieldDescriptor::Type type, const string& binary_data) { - switch (type) { - case FieldDescriptor::TYPE_DOUBLE: - return binary_data == dbl(0); - case FieldDescriptor::TYPE_FLOAT: - return binary_data == flt(0); - case FieldDescriptor::TYPE_BOOL: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_ENUM: - return binary_data == varint(0); - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - return binary_data == u64(0); - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - return binary_data == u32(0); - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - return binary_data == delim(""); - default: - return false; - } -} - -} // anonymous namespace - -namespace google { -namespace protobuf { - -bool BinaryAndJsonConformanceSuite::ParseResponse( - const ConformanceResponse& response, - const ConformanceRequestSetting& setting, Message* test_message) { - const ConformanceRequest& request = setting.GetRequest(); - WireFormat requested_output = request.requested_output_format(); - const string& test_name = setting.GetTestName(); - ConformanceLevel level = setting.GetLevel(); - - switch (response.result_case()) { - case ConformanceResponse::kProtobufPayload: { - if (requested_output != conformance::PROTOBUF) { - ReportFailure(test_name, level, request, response, - absl::StrCat("Test was asked for ", - WireFormatToString(requested_output), - " output but provided PROTOBUF instead.") - .c_str()); - return false; - } - - if (!test_message->ParseFromString(response.protobuf_payload())) { - ReportFailure(test_name, level, request, response, - "Protobuf output we received from test was unparseable."); - return false; - } - - break; - } - - case ConformanceResponse::kJsonPayload: { - GOOGLE_LOG(FATAL) << "json not support: " << response.DebugString(); - break; - } - - default: - GOOGLE_LOG(FATAL) << test_name - << ": unknown payload type: " << response.result_case(); - } - - return true; -} - -void BinaryAndJsonConformanceSuite::ExpectParseFailureForProtoWithProtoVersion( - const string& proto, const string& test_name, ConformanceLevel level, - bool is_proto3) { - std::unique_ptr prototype = NewTestMessage(is_proto3); - // We don't expect output, but if the program erroneously accepts the protobuf - // we let it send its response as this. We must not leave it unspecified. - ConformanceRequestSetting setting( - level, conformance::PROTOBUF, conformance::PROTOBUF, - conformance::BINARY_TEST, *prototype, test_name, proto); - - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - string effective_test_name = absl::StrCat( - setting.ConformanceLevelToString(level), - (is_proto3 ? ".Proto3" : ".Proto2"), ".ProtobufInput.", test_name); - - RunTest(effective_test_name, request, &response); - if (response.result_case() == ConformanceResponse::kParseError) { - ReportSuccess(effective_test_name); - } - else if (response.result_case() == ConformanceResponse::kSkipped) { - ReportSkip(effective_test_name, request, response); - } - else { - ReportFailure(effective_test_name, level, request, response, - "Should have failed to parse, but didn't."); - } -} - -// Expect that this precise protobuf will cause a parse error. -void BinaryAndJsonConformanceSuite::ExpectParseFailureForProto( - const string& proto, const string& test_name, ConformanceLevel level) { - ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, true); - ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, false); -} - -// Expect that this protobuf will cause a parse error, even if it is followed -// by valid protobuf data. We can try running this twice: once with this -// data verbatim and once with this data followed by some valid data. -// -// TODO(haberman): implement the second of these. -void BinaryAndJsonConformanceSuite::ExpectHardParseFailureForProto( - const string& proto, const string& test_name, ConformanceLevel level) { - return ExpectParseFailureForProto(proto, test_name, level); -} - -void BinaryAndJsonConformanceSuite::RunValidJsonTest( - const string& test_name, ConformanceLevel level, const string& input_json, - const string& equivalent_text_format, bool is_proto3) { - // if (is_proto3) { - // RunValidJsonTest(test_name, level, input_json, equivalent_text_format); - // } else { - // TestAllTypesProto2 prototype; - // RunValidJsonTestWithMessage(test_name, level, input_json, - // equivalent_text_format, prototype); - // } -} - -void BinaryAndJsonConformanceSuite::RunValidProtobufTest( - const string& test_name, ConformanceLevel level, - const string& input_protobuf, const string& equivalent_text_format, - bool is_proto3) { - std::unique_ptr prototype = NewTestMessage(is_proto3); - - ConformanceRequestSetting setting1( - level, conformance::PROTOBUF, conformance::PROTOBUF, - conformance::BINARY_TEST, *prototype, test_name, input_protobuf); - RunValidInputTest(setting1, equivalent_text_format); - - if (is_proto3) { - ConformanceRequestSetting setting2( - level, conformance::PROTOBUF, conformance::JSON, - conformance::BINARY_TEST, *prototype, test_name, input_protobuf); - // RunValidInputTest(setting2, equivalent_text_format); - } -} - -void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest( - const string& test_name, ConformanceLevel level, - const string& input_protobuf, bool is_proto3) { - RunValidBinaryProtobufTest(test_name, level, input_protobuf, input_protobuf, - is_proto3); -} - -void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest( - const string& test_name, ConformanceLevel level, - const string& input_protobuf, const string& expected_protobuf, - bool is_proto3) { - std::unique_ptr prototype = NewTestMessage(is_proto3); - ConformanceRequestSetting setting( - level, conformance::PROTOBUF, conformance::PROTOBUF, - conformance::BINARY_TEST, *prototype, test_name, input_protobuf); - RunValidBinaryInputTest(setting, expected_protobuf, true); -} - -void BinaryAndJsonConformanceSuite::RunBinaryPerformanceMergeMessageWithField( - const string& test_name, const string& field_proto, bool is_proto3) { - string message_tag = tag(27, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); - string message_proto = cat(message_tag, delim(field_proto)); - - string proto; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - proto.append(message_proto); - } - - string multiple_repeated_field_proto; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - multiple_repeated_field_proto.append(field_proto); - } - string expected_proto = - cat(message_tag, delim(multiple_repeated_field_proto)); - - RunValidBinaryProtobufTest(test_name, RECOMMENDED, proto, expected_proto, - is_proto3); -} - -void BinaryAndJsonConformanceSuite::RunValidProtobufTestWithMessage( - const string& test_name, ConformanceLevel level, const Message* input, - const string& equivalent_text_format, bool is_proto3) { - RunValidProtobufTest(test_name, level, input->SerializeAsString(), - equivalent_text_format, is_proto3); -} - -void BinaryAndJsonConformanceSuite::ExpectParseFailureForJson( - const string& test_name, ConformanceLevel level, const string& input_json) { - TestAllTypesProto3 prototype; - // We don't expect output, but if the program erroneously accepts the protobuf - // we let it send its response as this. We must not leave it unspecified. - ConformanceRequestSetting setting(level, conformance::JSON, conformance::JSON, - conformance::JSON_TEST, prototype, - test_name, input_json); - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - string effective_test_name = absl::StrCat( - setting.ConformanceLevelToString(level), ".Proto3.JsonInput.", test_name); - - RunTest(effective_test_name, request, &response); - if (response.result_case() == ConformanceResponse::kParseError) { - ReportSuccess(effective_test_name); - } - else if (response.result_case() == ConformanceResponse::kSkipped) { - ReportSkip(effective_test_name, request, response); - } - else { - ReportFailure(effective_test_name, level, request, response, - "Should have failed to parse, but didn't."); - } -} - -void BinaryAndJsonConformanceSuite::ExpectSerializeFailureForJson( - const string& test_name, ConformanceLevel level, - const string& text_format) { - TestAllTypesProto3 payload_message; - GOOGLE_CHECK(TextFormat::ParseFromString(text_format, &payload_message)) - << "Failed to parse: " << text_format; - - TestAllTypesProto3 prototype; - ConformanceRequestSetting setting( - level, conformance::PROTOBUF, conformance::JSON, conformance::JSON_TEST, - prototype, test_name, payload_message.SerializeAsString()); - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - string effective_test_name = absl::StrCat( - setting.ConformanceLevelToString(level), ".", test_name, ".JsonOutput"); - - RunTest(effective_test_name, request, &response); - if (response.result_case() == ConformanceResponse::kSerializeError) { - ReportSuccess(effective_test_name); - } - else if (response.result_case() == ConformanceResponse::kSkipped) { - ReportSkip(effective_test_name, request, response); - } - else { - ReportFailure(effective_test_name, level, request, response, - "Should have failed to serialize, but didn't."); - } -} - -void BinaryAndJsonConformanceSuite::TestPrematureEOFForType( - FieldDescriptor::Type type) { - // Incomplete values for each wire type. - static const string incompletes[6] = { - string("\x80"), // VARINT - string("abcdefg"), // 64BIT - string("\x80"), // DELIMITED (partial length) - string(), // START_GROUP (no value required) - string(), // END_GROUP (no value required) - string("abc") // 32BIT - }; - - const FieldDescriptor* field = GetFieldForType(type, false, true); - const FieldDescriptor* rep_field = GetFieldForType(type, true, true); - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(type)); - const string& incomplete = incompletes[wire_type]; - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - - ExpectParseFailureForProto( - tag(field->number(), wire_type), - "PrematureEofBeforeKnownNonRepeatedValue" + type_name, REQUIRED); - - ExpectParseFailureForProto(tag(rep_field->number(), wire_type), - "PrematureEofBeforeKnownRepeatedValue" + type_name, - REQUIRED); - - ExpectParseFailureForProto(tag(UNKNOWN_FIELD, wire_type), - "PrematureEofBeforeUnknownValue" + type_name, - REQUIRED); - - ExpectParseFailureForProto( - cat(tag(field->number(), wire_type), incomplete), - "PrematureEofInsideKnownNonRepeatedValue" + type_name, REQUIRED); - - ExpectParseFailureForProto( - cat(tag(rep_field->number(), wire_type), incomplete), - "PrematureEofInsideKnownRepeatedValue" + type_name, REQUIRED); - - ExpectParseFailureForProto(cat(tag(UNKNOWN_FIELD, wire_type), incomplete), - "PrematureEofInsideUnknownValue" + type_name, - REQUIRED); - - if (wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - ExpectParseFailureForProto( - cat(tag(field->number(), wire_type), varint(1)), - "PrematureEofInDelimitedDataForKnownNonRepeatedValue" + type_name, - REQUIRED); - - ExpectParseFailureForProto( - cat(tag(rep_field->number(), wire_type), varint(1)), - "PrematureEofInDelimitedDataForKnownRepeatedValue" + type_name, - REQUIRED); - - // EOF in the middle of delimited data for unknown value. - ExpectParseFailureForProto( - cat(tag(UNKNOWN_FIELD, wire_type), varint(1)), - "PrematureEofInDelimitedDataForUnknownValue" + type_name, REQUIRED); - - if (type == FieldDescriptor::TYPE_MESSAGE) { - // Submessage ends in the middle of a value. - string incomplete_submsg = - cat(tag(WireFormatLite::TYPE_INT32, WireFormatLite::WIRETYPE_VARINT), - incompletes[WireFormatLite::WIRETYPE_VARINT]); - ExpectHardParseFailureForProto( - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - varint(incomplete_submsg.size()), incomplete_submsg), - "PrematureEofInSubmessageValue" + type_name, REQUIRED); - } - } - else if (type != FieldDescriptor::TYPE_GROUP) { - // Non-delimited, non-group: eligible for packing. - - // Packed region ends in the middle of a value. - ExpectHardParseFailureForProto( - cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - varint(incomplete.size()), incomplete), - "PrematureEofInPackedFieldValue" + type_name, REQUIRED); - - // EOF in the middle of packed region. - ExpectParseFailureForProto( - cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - varint(1)), - "PrematureEofInPackedField" + type_name, REQUIRED); - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForType( - FieldDescriptor::Type type, - std::vector> values) { - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(type)); - const FieldDescriptor* field = GetFieldForType(type, false, is_proto3); - const FieldDescriptor* rep_field = GetFieldForType(type, true, is_proto3); - - // Test singular data for singular fields. - for (size_t i = 0; i < values.size(); i++) { - string proto = cat(tag(field->number(), wire_type), values[i].first); - // In proto3, default primitive fields should not be encoded. - string expected_proto = - is_proto3 && IsProto3Default(field->type(), values[i].second) - ? "" - : cat(tag(field->number(), wire_type), values[i].second); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest( - absl::StrCat("ValidDataScalar", type_name, "[", i, "]"), REQUIRED, - proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataScalarBinary", type_name, "[", i, "]"), - RECOMMENDED, proto, expected_proto, is_proto3); - } - - // Test repeated data for singular fields. - // For scalar message fields, repeated values are merged, which is tested - // separately. - if (type != FieldDescriptor::TYPE_MESSAGE) { - string proto; - for (size_t i = 0; i < values.size(); i++) { - proto += cat(tag(field->number(), wire_type), values[i].first); - } - string expected_proto = - cat(tag(field->number(), wire_type), values.back().second); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest("RepeatedScalarSelectsLast" + type_name, REQUIRED, - proto, text, is_proto3); - } - - // Test repeated fields. - if (FieldDescriptor::IsTypePackable(type)) { - const FieldDescriptor* packed_field = - GetFieldForType(type, true, is_proto3, Packed::kTrue); - const FieldDescriptor* unpacked_field = - GetFieldForType(type, true, is_proto3, Packed::kFalse); - - string default_proto_packed; - string default_proto_unpacked; - string default_proto_packed_expected; - string default_proto_unpacked_expected; - string packed_proto_packed; - string packed_proto_unpacked; - string packed_proto_expected; - string unpacked_proto_packed; - string unpacked_proto_unpacked; - string unpacked_proto_expected; - - for (size_t i = 0; i < values.size(); i++) { - default_proto_unpacked += - cat(tag(rep_field->number(), wire_type), values[i].first); - default_proto_unpacked_expected += - cat(tag(rep_field->number(), wire_type), values[i].second); - default_proto_packed += values[i].first; - default_proto_packed_expected += values[i].second; - packed_proto_unpacked += - cat(tag(packed_field->number(), wire_type), values[i].first); - packed_proto_packed += values[i].first; - packed_proto_expected += values[i].second; - unpacked_proto_unpacked += - cat(tag(unpacked_field->number(), wire_type), values[i].first); - unpacked_proto_packed += values[i].first; - unpacked_proto_expected += - cat(tag(unpacked_field->number(), wire_type), values[i].second); - } - default_proto_packed = cat( - tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(default_proto_packed)); - default_proto_packed_expected = cat( - tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(default_proto_packed_expected)); - packed_proto_packed = cat(tag(packed_field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(packed_proto_packed)); - packed_proto_expected = - cat(tag(packed_field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(packed_proto_expected)); - unpacked_proto_packed = - cat(tag(unpacked_field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(unpacked_proto_packed)); - - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(default_proto_packed_expected); - string text; - TextFormat::PrintToString(*test_message, &text); - - // Ensures both packed and unpacked data can be parsed. - RunValidProtobufTest( - absl::StrCat("ValidDataRepeated", type_name, ".UnpackedInput"), - REQUIRED, default_proto_unpacked, text, is_proto3); - RunValidProtobufTest( - absl::StrCat("ValidDataRepeated", type_name, ".PackedInput"), - REQUIRED, default_proto_packed, text, is_proto3); - - // proto2 should encode as unpacked by default and proto3 should encode as - // packed by default. - string expected_proto = rep_field->is_packed() - ? default_proto_packed_expected - : default_proto_unpacked_expected; - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".UnpackedInput.DefaultOutput"), - RECOMMENDED, default_proto_unpacked, - expected_proto, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".PackedInput.DefaultOutput"), - RECOMMENDED, default_proto_packed, - expected_proto, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".UnpackedInput.PackedOutput"), - RECOMMENDED, packed_proto_unpacked, - packed_proto_expected, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".PackedInput.PackedOutput"), - RECOMMENDED, packed_proto_packed, - packed_proto_expected, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".UnpackedInput.UnpackedOutput"), - RECOMMENDED, unpacked_proto_unpacked, - unpacked_proto_expected, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".PackedInput.UnpackedOutput"), - RECOMMENDED, unpacked_proto_packed, - unpacked_proto_expected, is_proto3); - } - else { - string proto; - string expected_proto; - for (size_t i = 0; i < values.size(); i++) { - proto += cat(tag(rep_field->number(), wire_type), values[i].first); - expected_proto += - cat(tag(rep_field->number(), wire_type), values[i].second); - } - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest(absl::StrCat("ValidDataRepeated", type_name), - REQUIRED, proto, text, is_proto3); - } - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForRepeatedScalarMessage() { - std::vector values = { - delim(cat( - tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234), - tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1234), - tag(31, WireFormatLite::WIRETYPE_VARINT), varint(1234))))), - delim(cat( - tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(4321), - tag(3, WireFormatLite::WIRETYPE_VARINT), varint(4321), - tag(31, WireFormatLite::WIRETYPE_VARINT), varint(4321))))), - }; - - const std::string expected = - R"({ - corecursive: { - optional_int32: 4321, - optional_int64: 1234, - optional_uint32: 4321, - repeated_int32: [1234, 4321], - } - })"; - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - string proto; - const FieldDescriptor* field = - GetFieldForType(FieldDescriptor::TYPE_MESSAGE, false, is_proto3); - for (size_t i = 0; i < values.size(); i++) { - proto += - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - values[i]); - } - - RunValidProtobufTest("RepeatedScalarMessageMerge", REQUIRED, proto, - field->name() + ": " + expected, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForMapType( - FieldDescriptor::Type key_type, FieldDescriptor::Type value_type) { - const string key_type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(key_type)); - const string value_type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(value_type)); - WireFormatLite::WireType key_wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(key_type)); - WireFormatLite::WireType value_wire_type = - WireFormatLite::WireTypeForFieldType( - static_cast(value_type)); - - string key1_data = cat(tag(1, key_wire_type), GetDefaultValue(key_type)); - string value1_data = - cat(tag(2, value_wire_type), GetDefaultValue(value_type)); - string key2_data = cat(tag(1, key_wire_type), GetNonDefaultValue(key_type)); - string value2_data = - cat(tag(2, value_wire_type), GetNonDefaultValue(value_type)); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = - GetFieldForMapType(key_type, value_type, is_proto3); - - { - // Tests map with default key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key1_data, value1_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".Default"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with missing default key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim("")); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".MissingDefault"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with non-default key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".NonDefault"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with unordered key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(value2_data, key2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".Unordered"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with duplicate key. - string proto1 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value1_data))); - string proto2 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value2_data))); - string proto = cat(proto1, proto2); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto2); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".DuplicateKey"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with duplicate key in map entry. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key1_data, key2_data, value2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest( - absl::StrCat("ValidDataMap", key_type_name, value_type_name, - ".DuplicateKeyInMapEntry"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with duplicate value in map entry. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value1_data, value2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest( - absl::StrCat("ValidDataMap", key_type_name, value_type_name, - ".DuplicateValueInMapEntry"), - REQUIRED, proto, text, is_proto3); - } - } -} - -void BinaryAndJsonConformanceSuite::TestOverwriteMessageValueMap() { - string key_data = - cat(tag(1, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), delim("")); - string field1_data = cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field2_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field31_data = - cat(tag(31, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string submsg1_data = delim(cat(field1_data, field31_data)); - string submsg2_data = delim(cat(field2_data, field31_data)); - string value1_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - submsg1_data))); - string value2_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - submsg2_data))); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = GetFieldForMapType( - FieldDescriptor::TYPE_STRING, FieldDescriptor::TYPE_MESSAGE, is_proto3); - - string proto1 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key_data, value1_data))); - string proto2 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key_data, value2_data))); - string proto = cat(proto1, proto2); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto2); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest("ValidDataMap.STRING.MESSAGE.MergeValue", REQUIRED, - proto, text, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForOneofType( - FieldDescriptor::Type type) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(type)); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = GetFieldForOneofType(type, is_proto3); - const string default_value = - cat(tag(field->number(), wire_type), GetDefaultValue(type)); - const string non_default_value = - cat(tag(field->number(), wire_type), GetNonDefaultValue(type)); - - { - // Tests oneof with default value. - const string proto = default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest( - absl::StrCat("ValidDataOneof", type_name, ".DefaultValue"), REQUIRED, - proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataOneofBinary", type_name, ".DefaultValue"), - RECOMMENDED, proto, proto, is_proto3); - } - - { - // Tests oneof with non-default value. - const string proto = non_default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest( - absl::StrCat("ValidDataOneof", type_name, ".NonDefaultValue"), - REQUIRED, proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataOneofBinary", type_name, ".NonDefaultValue"), - RECOMMENDED, proto, proto, is_proto3); - } - - { - // Tests oneof with multiple values of the same field. - const string proto = absl::StrCat(default_value, non_default_value); - const string expected_proto = non_default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest(absl::StrCat("ValidDataOneof", type_name, - ".MultipleValuesForSameField"), - REQUIRED, proto, text, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataOneofBinary", type_name, - ".MultipleValuesForSameField"), - RECOMMENDED, proto, expected_proto, is_proto3); - } - - { - // Tests oneof with multiple values of the different fields. - const FieldDescriptor* other_field = - GetFieldForOneofType(type, is_proto3, true); - FieldDescriptor::Type other_type = other_field->type(); - WireFormatLite::WireType other_wire_type = - WireFormatLite::WireTypeForFieldType( - static_cast(other_type)); - const string other_value = - cat(tag(other_field->number(), other_wire_type), - GetDefaultValue(other_type)); - - const string proto = absl::StrCat(other_value, non_default_value); - const string expected_proto = non_default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest(absl::StrCat("ValidDataOneof", type_name, - ".MultipleValuesForDifferentField"), - REQUIRED, proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataOneofBinary", type_name, - ".MultipleValuesForDifferentField"), - RECOMMENDED, proto, expected_proto, is_proto3); - } - } -} - -void BinaryAndJsonConformanceSuite::TestMergeOneofMessage() { - string field1_data = cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field2a_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field2b_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field89_data = - cat(tag(89, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string submsg1_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(field1_data, field2a_data, field89_data))); - string submsg2_data = cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(field2b_data, field89_data))); - string merged_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(field1_data, field2b_data, field89_data, field89_data))); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = - GetFieldForOneofType(FieldDescriptor::TYPE_MESSAGE, is_proto3); - - string proto1 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(submsg1_data)); - string proto2 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(submsg2_data)); - string proto = cat(proto1, proto2); - string expected_proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(merged_data)); - - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest("ValidDataOneof.MESSAGE.Merge", REQUIRED, proto, text, - is_proto3); - RunValidBinaryProtobufTest("ValidDataOneofBinary.MESSAGE.Merge", - RECOMMENDED, proto, expected_proto, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::TestIllegalTags() { - // field num 0 is illegal - string nullfield[] = {"\1DEADBEEF", "\2\1\1", "\3\4", "\5DEAD"}; - for (int i = 0; i < 4; i++) { - string name = "IllegalZeroFieldNum_Case_0"; - name.back() += i; - ExpectParseFailureForProto(nullfield[i], name, REQUIRED); - } -} -template -void BinaryAndJsonConformanceSuite::TestOneofMessage(MessageType& message, - bool is_proto3) { - message.set_oneof_uint32(0); - RunValidProtobufTestWithMessage("OneofZeroUint32", RECOMMENDED, &message, - "oneof_uint32: 0", is_proto3); - message.mutable_oneof_nested_message()->set_a(0); - RunValidProtobufTestWithMessage( - "OneofZeroMessage", RECOMMENDED, &message, - is_proto3 ? "oneof_nested_message: {}" : "oneof_nested_message: {a: 0}", - is_proto3); - message.mutable_oneof_nested_message()->set_a(1); - RunValidProtobufTestWithMessage("OneofZeroMessageSetTwice", RECOMMENDED, - &message, "oneof_nested_message: {a: 1}", - is_proto3); - message.set_oneof_string(""); - RunValidProtobufTestWithMessage("OneofZeroString", RECOMMENDED, &message, - "oneof_string: \"\"", is_proto3); - message.set_oneof_bytes(""); - RunValidProtobufTestWithMessage("OneofZeroBytes", RECOMMENDED, &message, - "oneof_bytes: \"\"", is_proto3); - message.set_oneof_bool(false); - RunValidProtobufTestWithMessage("OneofZeroBool", RECOMMENDED, &message, - "oneof_bool: false", is_proto3); - message.set_oneof_uint64(0); - RunValidProtobufTestWithMessage("OneofZeroUint64", RECOMMENDED, &message, - "oneof_uint64: 0", is_proto3); - message.set_oneof_float(0.0f); - RunValidProtobufTestWithMessage("OneofZeroFloat", RECOMMENDED, &message, - "oneof_float: 0", is_proto3); - message.set_oneof_double(0.0); - RunValidProtobufTestWithMessage("OneofZeroDouble", RECOMMENDED, &message, - "oneof_double: 0", is_proto3); - message.set_oneof_enum(MessageType::FOO); - RunValidProtobufTestWithMessage("OneofZeroEnum", RECOMMENDED, &message, - "oneof_enum: FOO", is_proto3); -} - -template -void BinaryAndJsonConformanceSuite::TestUnknownMessage(MessageType& message, - bool is_proto3) { - message.ParseFromString("\xA8\x1F\x01"); - RunValidBinaryProtobufTest("UnknownVarint", REQUIRED, - message.SerializeAsString(), is_proto3); -} - -void BinaryAndJsonConformanceSuite:: - TestBinaryPerformanceForAlternatingUnknownFields() { - string unknown_field_1 = - cat(tag(UNKNOWN_FIELD, WireFormatLite::WIRETYPE_VARINT), varint(1234)); - string unknown_field_2 = cat( - tag(UNKNOWN_FIELD + 1, WireFormatLite::WIRETYPE_VARINT), varint(5678)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - string proto; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - proto.append(unknown_field_1); - proto.append(unknown_field_2); - } - - RunValidBinaryProtobufTest( - "TestBinaryPerformanceForAlternatingUnknownFields", RECOMMENDED, proto, - is_proto3); - } -} - -void BinaryAndJsonConformanceSuite:: - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::Type type) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - int field_number = - GetFieldForType(type, true, is_proto3, Packed::kFalse)->number(); - string rep_field_proto = cat( - tag(field_number, WireFormatLite::WireTypeForFieldType( - static_cast(type))), - GetNonDefaultValue(type)); - - RunBinaryPerformanceMergeMessageWithField( - "TestBinaryPerformanceMergeMessageWithRepeatedFieldForType" + type_name, - rep_field_proto, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite:: - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::Type type) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - string unknown_field_proto = - cat(tag(UNKNOWN_FIELD, WireFormatLite::WireTypeForFieldType( - static_cast(type))), - GetNonDefaultValue(type)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - RunBinaryPerformanceMergeMessageWithField( - "TestBinaryPerformanceMergeMessageWithUnknownFieldForType" + type_name, - unknown_field_proto, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::RunSuiteImpl() { - // Hack to get the list of test failures based on whether - // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER is enabled or not. - conformance::FailureSet failure_set; - ConformanceRequest req; - ConformanceResponse res; - req.set_message_type(failure_set.GetTypeName()); - req.set_protobuf_payload(""); - req.set_requested_output_format(conformance::WireFormat::PROTOBUF); - RunTest("FindFailures", req, &res); - GOOGLE_CHECK(failure_set.MergeFromString(res.protobuf_payload())); - for (const string& failure : failure_set.failure()) { - AddExpectedFailedTest(failure); - } - - type_resolver_.reset(NewTypeResolverForDescriptorPool( - kTypeUrlPrefix, DescriptorPool::generated_pool())); - type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor()); - - if (!performance_) { - for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) { - if (i == FieldDescriptor::TYPE_GROUP) - continue; - TestPrematureEOFForType(static_cast(i)); - } - - TestIllegalTags(); - - int64 kInt64Min = -9223372036854775808ULL; - int64 kInt64Max = 9223372036854775807ULL; - uint64 kUint64Max = 18446744073709551615ULL; - int32 kInt32Max = 2147483647; - int32 kInt32Min = -2147483648; - uint32 kUint32Max = 4294967295UL; - - TestValidDataForType( - FieldDescriptor::TYPE_DOUBLE, - { - {dbl(0), dbl(0)}, - {dbl(0.1), dbl(0.1)}, - {dbl(1.7976931348623157e+308), dbl(1.7976931348623157e+308)}, - {dbl(2.22507385850720138309e-308), - dbl(2.22507385850720138309e-308)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_FLOAT, - { - {flt(0), flt(0)}, - {flt(0.1), flt(0.1)}, - {flt(1.00000075e-36), flt(1.00000075e-36)}, - {flt(3.402823e+38), flt(3.402823e+38)}, // 3.40282347e+38 - {flt(1.17549435e-38f), flt(1.17549435e-38)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_INT64, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {varint(kInt64Max), varint(kInt64Max)}, - {varint(kInt64Min), varint(kInt64Min)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_UINT64, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {varint(kUint64Max), varint(kUint64Max)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_INT32, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {longvarint(12345, 2), varint(12345)}, - {longvarint(12345, 7), varint(12345)}, - {varint(kInt32Max), varint(kInt32Max)}, - {varint(kInt32Min), varint(kInt32Min)}, - {varint(1LL << 33), varint(0)}, - {varint((1LL << 33) - 1), varint(-1)}, - {varint(kInt64Max), varint(-1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_UINT32, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {longvarint(12345, 2), varint(12345)}, - {longvarint(12345, 7), varint(12345)}, - {varint(kUint32Max), varint(kUint32Max)}, // UINT32_MAX - {varint(1LL << 33), varint(0)}, - {varint((1LL << 33) + 1), varint(1)}, - {varint((1LL << 33) - 1), varint((1LL << 32) - 1)}, - {varint(kInt64Max), varint((1LL << 32) - 1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_FIXED64, - { - {u64(0), u64(0)}, - {u64(12345), u64(12345)}, - {u64(kUint64Max), u64(kUint64Max)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_FIXED32, - { - {u32(0), u32(0)}, - {u32(12345), u32(12345)}, - {u32(kUint32Max), u32(kUint32Max)}, // UINT32_MAX - }); - TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, - { - {u64(0), u64(0)}, - {u64(12345), u64(12345)}, - {u64(kInt64Max), u64(kInt64Max)}, - {u64(kInt64Min), u64(kInt64Min)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, - { - {u32(0), u32(0)}, - {u32(12345), u32(12345)}, - {u32(kInt32Max), u32(kInt32Max)}, - {u32(kInt32Min), u32(kInt32Min)}, - }); - // Bools should be serialized as 0 for false and 1 for true. Parsers should - // also interpret any nonzero value as true. - TestValidDataForType(FieldDescriptor::TYPE_BOOL, - { - {varint(0), varint(0)}, - {varint(1), varint(1)}, - {varint(-1), varint(1)}, - {varint(12345678), varint(1)}, - {varint(1LL << 33), varint(1)}, - {varint(kInt64Max), varint(1)}, - {varint(kInt64Min), varint(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SINT32, - { - {zz32(0), zz32(0)}, - {zz32(12345), zz32(12345)}, - {zz32(kInt32Max), zz32(kInt32Max)}, - {zz32(kInt32Min), zz32(kInt32Min)}, - {zz64(kInt32Max + 2LL), zz32(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SINT64, - { - {zz64(0), zz64(0)}, - {zz64(12345), zz64(12345)}, - {zz64(kInt64Max), zz64(kInt64Max)}, - {zz64(kInt64Min), zz64(kInt64Min)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_STRING, - { - {delim(""), delim("")}, - {delim("Hello world!"), delim("Hello world!")}, - {delim("\'\"\?\\\a\b\f\n\r\t\v"), - delim("\'\"\?\\\a\b\f\n\r\t\v")}, // escape - {delim("谷歌"), delim("谷歌")}, // Google in Chinese - {delim("\u8C37\u6B4C"), delim("谷歌")}, // unicode escape - {delim("\u8c37\u6b4c"), delim("谷歌")}, // lowercase unicode - {delim("\xF0\x9F\x98\x81"), delim("\xF0\x9F\x98\x81")}, // emoji: 😁 - }); - TestValidDataForType(FieldDescriptor::TYPE_BYTES, - { - {delim(""), delim("")}, - {delim("Hello world!"), delim("Hello world!")}, - {delim("\x01\x02"), delim("\x01\x02")}, - {delim("\xfb"), delim("\xfb")}, - }); - TestValidDataForType(FieldDescriptor::TYPE_ENUM, - { - {varint(0), varint(0)}, - {varint(1), varint(1)}, - {varint(2), varint(2)}, - {varint(-1), varint(-1)}, - {varint(kInt64Max), varint(-1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForRepeatedScalarMessage(); - TestValidDataForType( - FieldDescriptor::TYPE_MESSAGE, - { - {delim(""), delim("")}, - {delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))), - delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234)))}, - }); - - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_INT32); - TestValidDataForMapType(FieldDescriptor::TYPE_INT64, - FieldDescriptor::TYPE_INT64); - TestValidDataForMapType(FieldDescriptor::TYPE_UINT32, - FieldDescriptor::TYPE_UINT32); - TestValidDataForMapType(FieldDescriptor::TYPE_UINT64, - FieldDescriptor::TYPE_UINT64); - TestValidDataForMapType(FieldDescriptor::TYPE_SINT32, - FieldDescriptor::TYPE_SINT32); - TestValidDataForMapType(FieldDescriptor::TYPE_SINT64, - FieldDescriptor::TYPE_SINT64); - TestValidDataForMapType(FieldDescriptor::TYPE_FIXED32, - FieldDescriptor::TYPE_FIXED32); - TestValidDataForMapType(FieldDescriptor::TYPE_FIXED64, - FieldDescriptor::TYPE_FIXED64); - TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED32, - FieldDescriptor::TYPE_SFIXED32); - TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED64, - FieldDescriptor::TYPE_SFIXED64); - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_FLOAT); - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_DOUBLE); - TestValidDataForMapType(FieldDescriptor::TYPE_BOOL, - FieldDescriptor::TYPE_BOOL); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_STRING); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_BYTES); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_ENUM); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_MESSAGE); - // Additional test to check overwriting message value map. - TestOverwriteMessageValueMap(); - - TestValidDataForOneofType(FieldDescriptor::TYPE_UINT32); - TestValidDataForOneofType(FieldDescriptor::TYPE_BOOL); - TestValidDataForOneofType(FieldDescriptor::TYPE_UINT64); - TestValidDataForOneofType(FieldDescriptor::TYPE_FLOAT); - TestValidDataForOneofType(FieldDescriptor::TYPE_DOUBLE); - TestValidDataForOneofType(FieldDescriptor::TYPE_STRING); - TestValidDataForOneofType(FieldDescriptor::TYPE_BYTES); - TestValidDataForOneofType(FieldDescriptor::TYPE_ENUM); - TestValidDataForOneofType(FieldDescriptor::TYPE_MESSAGE); - // Additional test to check merging oneof message. - TestMergeOneofMessage(); - - // TODO(haberman): - // TestValidDataForType(FieldDescriptor::TYPE_GROUP - - // Unknown fields. - { - TestAllTypesProto3 messageProto3; - TestAllTypesProto2 messageProto2; - // TODO(yilunchong): update this behavior when unknown field's behavior - // changed in open source. Also delete - // Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput - // from failure list of python_cpp python java - TestUnknownMessage(messageProto3, true); - TestUnknownMessage(messageProto2, false); - } - - // RunJsonTests(); - } - // Flag control performance tests to keep them internal and opt-in only - if (performance_) { - RunBinaryPerformanceTests(); - // RunJsonPerformanceTests(); - } -} - -void BinaryAndJsonConformanceSuite::RunBinaryPerformanceTests() { - TestBinaryPerformanceForAlternatingUnknownFields(); - - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_BOOL); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_DOUBLE); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_FLOAT); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_UINT32); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_UINT64); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_STRING); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_BYTES); - - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_BOOL); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_DOUBLE); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_FLOAT); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_UINT32); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_UINT64); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_STRING); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_BYTES); -} - -// This is currently considered valid input by some languages but not others -void BinaryAndJsonConformanceSuite:: - TestJsonPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::Type type, string field_value) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = - GetFieldForType(type, true, is_proto3, Packed::kFalse); - string field_name = field->name(); - - string message_field = "\"" + field_name + "\": [" + field_value + "]"; - string recursive_message = - "\"recursive_message\": { " + message_field + "}"; - string input = "{"; - input.append(recursive_message); - for (size_t i = 1; i < kPerformanceRepeatCount; i++) { - input.append("," + recursive_message); - } - input.append("}"); - - string textproto_message_field = field_name + ": " + field_value; - string expected_textproto = "recursive_message { "; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - expected_textproto.append(textproto_message_field + " "); - } - expected_textproto.append("}"); - RunValidJsonTest( - "TestJsonPerformanceMergeMessageWithRepeatedFieldForType" + type_name, - RECOMMENDED, input, expected_textproto, is_proto3); - } -} - -} // namespace protobuf -} // namespace google diff --git a/src/struct_pb/conformance/binary_json_conformance_suite.h b/src/struct_pb/conformance/binary_json_conformance_suite.h deleted file mode 100644 index 23670551c..000000000 --- a/src/struct_pb/conformance/binary_json_conformance_suite.h +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H -#define CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H - -#include "conformance_test.h" -#include "google/protobuf/descriptor.h" - -namespace google { -namespace protobuf { - -class BinaryAndJsonConformanceSuite : public ConformanceTestSuite { - public: - BinaryAndJsonConformanceSuite() {} - - private: - void RunSuiteImpl() override; - void RunBinaryPerformanceTests(); - void RunValidJsonTest(const std::string& test_name, ConformanceLevel level, - const std::string& input_json, - const std::string& equivalent_text_format, - bool is_proto3); - void RunValidProtobufTest(const std::string& test_name, - ConformanceLevel level, - const std::string& input_protobuf, - const std::string& equivalent_text_format, - bool is_proto3); - void RunValidBinaryProtobufTest(const std::string& test_name, - ConformanceLevel level, - const std::string& input_protobuf, - bool is_proto3); - void RunValidBinaryProtobufTest(const std::string& test_name, - ConformanceLevel level, - const std::string& input_protobuf, - const std::string& expected_protobuf, - bool is_proto3); - void RunBinaryPerformanceMergeMessageWithField(const std::string& test_name, - const std::string& field_proto, - bool is_proto3); - - void RunValidProtobufTestWithMessage( - const std::string& test_name, ConformanceLevel level, - const Message* input, const std::string& equivalent_text_format, - bool is_proto3); - - bool ParseResponse(const conformance::ConformanceResponse& response, - const ConformanceRequestSetting& setting, - Message* test_message) override; - void ExpectParseFailureForJson(const std::string& test_name, - ConformanceLevel level, - const std::string& input_json); - void ExpectSerializeFailureForJson(const std::string& test_name, - ConformanceLevel level, - const std::string& text_format); - void ExpectParseFailureForProtoWithProtoVersion(const std::string& proto, - const std::string& test_name, - ConformanceLevel level, - bool is_proto3); - void ExpectParseFailureForProto(const std::string& proto, - const std::string& test_name, - ConformanceLevel level); - void ExpectHardParseFailureForProto(const std::string& proto, - const std::string& test_name, - ConformanceLevel level); - void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type); - void TestIllegalTags(); - template - void TestOneofMessage(MessageType& message, bool is_proto3); - template - void TestUnknownMessage(MessageType& message, bool is_proto3); - void TestValidDataForType( - google::protobuf::FieldDescriptor::Type, - std::vector> values); - void TestValidDataForRepeatedScalarMessage(); - void TestValidDataForMapType(google::protobuf::FieldDescriptor::Type, - google::protobuf::FieldDescriptor::Type); - void TestValidDataForOneofType(google::protobuf::FieldDescriptor::Type); - void TestMergeOneofMessage(); - void TestOverwriteMessageValueMap(); - void TestBinaryPerformanceForAlternatingUnknownFields(); - void TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - google::protobuf::FieldDescriptor::Type); - void TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - google::protobuf::FieldDescriptor::Type); - void TestJsonPerformanceMergeMessageWithRepeatedFieldForType( - google::protobuf::FieldDescriptor::Type, std::string field_value); - - std::unique_ptr type_resolver_; - std::string type_url_; -}; - -} // namespace protobuf -} // namespace google - -#endif // CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H diff --git a/src/struct_pb/conformance/conformance/conformance.proto b/src/struct_pb/conformance/conformance/conformance.proto deleted file mode 100644 index bee04d160..000000000 --- a/src/struct_pb/conformance/conformance/conformance.proto +++ /dev/null @@ -1,180 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package conformance; - -option java_package = "com.google.protobuf.conformance"; -option objc_class_prefix = "Conformance"; - -// This defines the conformance testing protocol. This protocol exists between -// the conformance test suite itself and the code being tested. For each test, -// the suite will send a ConformanceRequest message and expect a -// ConformanceResponse message. -// -// You can either run the tests in two different ways: -// -// 1. in-process (using the interface in conformance_test.h). -// -// 2. as a sub-process communicating over a pipe. Information about how to -// do this is in conformance_test_runner.cc. -// -// Pros/cons of the two approaches: -// -// - running as a sub-process is much simpler for languages other than C/C++. -// -// - running as a sub-process may be more tricky in unusual environments like -// iOS apps, where fork/stdin/stdout are not available. - -enum WireFormat { - UNSPECIFIED = 0; - PROTOBUF = 1; - JSON = 2; - JSPB = 3; // Only used inside Google. Opensource testees just skip it. - TEXT_FORMAT = 4; -} - -enum TestCategory { - UNSPECIFIED_TEST = 0; - BINARY_TEST = 1; // Test binary wire format. - JSON_TEST = 2; // Test json wire format. - // Similar to JSON_TEST. However, during parsing json, testee should ignore - // unknown fields. This feature is optional. Each implementation can decide - // whether to support it. See - // https://developers.google.com/protocol-buffers/docs/proto3#json_options - // for more detail. - JSON_IGNORE_UNKNOWN_PARSING_TEST = 3; - // Test jspb wire format. Only used inside Google. Opensource testees just - // skip it. - JSPB_TEST = 4; - // Test text format. For cpp, java and python, testees can already deal with - // this type. Testees of other languages can simply skip it. - TEXT_FORMAT_TEST = 5; -} - -// The conformance runner will request a list of failures as the first request. -// This will be known by message_type == "conformance.FailureSet", a conformance -// test should return a serialized FailureSet in protobuf_payload. -message FailureSet { - repeated string failure = 1; -} - -// Represents a single test case's input. The testee should: -// -// 1. parse this proto (which should always succeed) -// 2. parse the protobuf or JSON payload in "payload" (which may fail) -// 3. if the parse succeeded, serialize the message in the requested format. -message ConformanceRequest { - // The payload (whether protobuf of JSON) is always for a - // protobuf_test_messages.proto3.TestAllTypes proto (as defined in - // src/google/protobuf/proto3_test_messages.proto). - oneof payload { - bytes protobuf_payload = 1; - string json_payload = 2; - // Only used inside Google. Opensource testees just skip it. - string jspb_payload = 7; - string text_payload = 8; - } - - // Which format should the testee serialize its message to? - WireFormat requested_output_format = 3; - - // The full name for the test message to use; for the moment, either: - // protobuf_test_messages.proto3.TestAllTypesProto3 or - // protobuf_test_messages.google.protobuf.TestAllTypesProto2. - string message_type = 4; - - // Each test is given a specific test category. Some category may need - // specific support in testee programs. Refer to the definition of - // TestCategory for more information. - TestCategory test_category = 5; - - // Specify details for how to encode jspb. - JspbEncodingConfig jspb_encoding_options = 6; - - // This can be used in json and text format. If true, testee should print - // unknown fields instead of ignore. This feature is optional. - bool print_unknown_fields = 9; -} - -// Represents a single test case's output. -message ConformanceResponse { - oneof result { - // This string should be set to indicate parsing failed. The string can - // provide more information about the parse error if it is available. - // - // Setting this string does not necessarily mean the testee failed the - // test. Some of the test cases are intentionally invalid input. - string parse_error = 1; - - // If the input was successfully parsed but errors occurred when - // serializing it to the requested output format, set the error message in - // this field. - string serialize_error = 6; - - // This should be set if the test program timed out. The string should - // provide more information about what the child process was doing when it - // was killed. - string timeout_error = 9; - - // This should be set if some other error occurred. This will always - // indicate that the test failed. The string can provide more information - // about the failure. - string runtime_error = 2; - - // If the input was successfully parsed and the requested output was - // protobuf, serialize it to protobuf and set it in this field. - bytes protobuf_payload = 3; - - // If the input was successfully parsed and the requested output was JSON, - // serialize to JSON and set it in this field. - string json_payload = 4; - - // For when the testee skipped the test, likely because a certain feature - // wasn't supported, like JSON input/output. - string skipped = 5; - - // If the input was successfully parsed and the requested output was JSPB, - // serialize to JSPB and set it in this field. JSPB is only used inside - // Google. Opensource testees can just skip it. - string jspb_payload = 7; - - // If the input was successfully parsed and the requested output was - // TEXT_FORMAT, serialize to TEXT_FORMAT and set it in this field. - string text_payload = 8; - } -} - -// Encoding options for jspb format. -message JspbEncodingConfig { - // Encode the value field of Any as jspb array if true, otherwise binary. - bool use_jspb_array_any_format = 1; -} diff --git a/src/struct_pb/conformance/conformance_cpp.cc b/src/struct_pb/conformance/conformance_cpp.cc deleted file mode 100644 index 09c3a3e8e..000000000 --- a/src/struct_pb/conformance/conformance_cpp.cc +++ /dev/null @@ -1,304 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "conformance/conformance.pb.h" -#include "google/protobuf/message.h" -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/test_messages_proto2.pb.h" -#include "google/protobuf/test_messages_proto3.pb.h" -#include "google/protobuf/text_format.h" -#include "google/protobuf/util/json_util.h" -#include "google/protobuf/util/type_resolver.h" -#include "google/protobuf/util/type_resolver_util.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -#define RETURN_IF_ERROR(expr) \ - do { \ - /* Using _status below to avoid capture problems if expr is "status". */ \ - const absl::Status _status = (expr); \ - if (PROTOBUF_PREDICT_FALSE(!_status.ok())) \ - return _status; \ - } while (0) - -namespace google { -namespace protobuf { -namespace { -using ::conformance::ConformanceRequest; -using ::conformance::ConformanceResponse; -using ::google::protobuf::util::BinaryToJsonString; -using ::google::protobuf::util::JsonParseOptions; -using ::google::protobuf::util::JsonToBinaryString; -using ::google::protobuf::util::NewTypeResolverForDescriptorPool; -using ::google::protobuf::util::TypeResolver; -using ::protobuf_test_messages::proto2::TestAllTypesProto2; -using ::protobuf_test_messages::proto3::TestAllTypesProto3; - -absl::Status ReadFd(int fd, char* buf, size_t len) { - while (len > 0) { - ssize_t bytes_read = read(fd, buf, len); - - if (bytes_read == 0) { - return absl::DataLossError("unexpected EOF"); - } - - if (bytes_read < 0) { - return absl::ErrnoToStatus(errno, "error reading from test runner"); - } - - len -= bytes_read; - buf += bytes_read; - } - return absl::OkStatus(); -} - -absl::Status WriteFd(int fd, const void* buf, size_t len) { - if (static_cast(write(fd, buf, len)) != len) { - return absl::ErrnoToStatus(errno, "error reading to test runner"); - } - return absl::OkStatus(); -} -// define this macro when you want to debug struct_pb conformance test -// -#ifdef CONFORMANCE_CPP_DUMP_DATA -static int index = 0; -void write_to_file(const std::string& buffer, const std::string& tag, - const std::string& suffix) { - std::string filename = tag + "/" + std::to_string(index) + "." + suffix; - std::ofstream ofs; - ofs.open(filename, std::ios::out | std::ios::binary); - ofs.write(buffer.data(), buffer.size()); -} -#endif -class Harness { - public: - Harness() { - google::protobuf::LinkMessageReflection(); - google::protobuf::LinkMessageReflection(); - - resolver_.reset(NewTypeResolverForDescriptorPool( - "type.googleapis.com", DescriptorPool::generated_pool())); - type_url_ = absl::StrCat("type.googleapis.com/", - TestAllTypesProto3::GetDescriptor()->full_name()); - } - - absl::StatusOr RunTest( - const ConformanceRequest& request); - - // Returns Ok(true) if we're done processing requests. - absl::StatusOr ServeConformanceRequest(); - - private: - bool verbose_ = false; - std::unique_ptr resolver_; - std::string type_url_; -}; - -absl::StatusOr Harness::RunTest( - const ConformanceRequest& request) { - const Descriptor* descriptor = - DescriptorPool::generated_pool()->FindMessageTypeByName( - request.message_type()); - if (descriptor == nullptr) { - return absl::NotFoundError( - absl::StrCat("No such message type: ", request.message_type())); - } - - std::unique_ptr test_message( - MessageFactory::generated_factory()->GetPrototype(descriptor)->New()); - ConformanceResponse response; - - switch (request.payload_case()) { - case ConformanceRequest::kProtobufPayload: { - if (!test_message->ParseFromString(request.protobuf_payload())) { - response.set_parse_error("parse error (no more details available)"); - return response; - } - break; - } - - case ConformanceRequest::kJsonPayload: { - JsonParseOptions options; - options.ignore_unknown_fields = - (request.test_category() == - conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST); - - std::string proto_binary; - auto status = - JsonToBinaryString(resolver_.get(), type_url_, request.json_payload(), - &proto_binary, options); - if (!status.ok()) { - response.set_parse_error( - absl::StrCat("parse error: ", status.message())); - return response; - } - - if (!test_message->ParseFromString(proto_binary)) { - response.set_runtime_error( - "parsing JSON generated invalid proto output"); - return response; - } - - break; - } - - case ConformanceRequest::kTextPayload: { - if (!TextFormat::ParseFromString(request.text_payload(), - test_message.get())) { - response.set_parse_error("parse error (no more details available)"); - return response; - } - break; - } - - case ConformanceRequest::PAYLOAD_NOT_SET: - return absl::InvalidArgumentError("request didn't have payload"); - - default: - return absl::InvalidArgumentError( - absl::StrCat("unknown payload type", request.payload_case())); - } -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file(test_message->DebugString(), "in", "msg.txt"); -#endif - switch (request.requested_output_format()) { - case conformance::UNSPECIFIED: - return absl::InvalidArgumentError("unspecified output format"); - - case conformance::PROTOBUF: { - GOOGLE_CHECK( - test_message->SerializeToString(response.mutable_protobuf_payload())); - break; - } - - case conformance::JSON: { - std::string proto_binary; - GOOGLE_CHECK(test_message->SerializeToString(&proto_binary)); - auto status = BinaryToJsonString(resolver_.get(), type_url_, proto_binary, - response.mutable_json_payload()); - if (!status.ok()) { - response.set_serialize_error(absl::StrCat( - "failed to serialize JSON output: ", status.message())); - } - break; - } - - case conformance::TEXT_FORMAT: { - TextFormat::Printer printer; - printer.SetHideUnknownFields(!request.print_unknown_fields()); - GOOGLE_CHECK(printer.PrintToString(*test_message, - response.mutable_text_payload())); - break; - } - - default: - return absl::InvalidArgumentError(absl::StrCat( - "unknown output format", request.requested_output_format())); - } - - return response; -} - -absl::StatusOr Harness::ServeConformanceRequest() { - uint32_t in_len; - if (!ReadFd(STDIN_FILENO, reinterpret_cast(&in_len), sizeof(in_len)) - .ok()) { - // EOF means we're done. - return true; - } - - std::string serialized_input; - serialized_input.resize(in_len); - RETURN_IF_ERROR(ReadFd(STDIN_FILENO, &serialized_input[0], in_len)); -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file(serialized_input, "in", "bin"); -#endif - ConformanceRequest request; - GOOGLE_CHECK(request.ParseFromString(serialized_input)); -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file( - std::to_string(serialized_input.size()) + "\n" + request.DebugString(), - "in", "txt"); -#endif - absl::StatusOr response = RunTest(request); - RETURN_IF_ERROR(response.status()); - - std::string serialized_output; - response->SerializeToString(&serialized_output); -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file(serialized_output, "out", "bin"); - write_to_file(response->DebugString(), "out", "txt"); - index++; -#endif - - uint32_t out_len = static_cast(serialized_output.size()); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, &out_len, sizeof(out_len))); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, serialized_output.data(), out_len)); - - if (verbose_) { - GOOGLE_LOG(INFO) << "conformance-cpp: request=" - << request.ShortDebugString() - << ", response=" << response->ShortDebugString(); - } - return false; -} -} // namespace -} // namespace protobuf -} // namespace google - -int main() { - google::protobuf::Harness harness; - int total_runs = 0; - while (true) { - auto is_done = harness.ServeConformanceRequest(); - if (!is_done.ok()) { - GOOGLE_LOG(FATAL) << is_done.status().message(); - } - if (*is_done) { - break; - } - total_runs++; - } - GOOGLE_LOG(INFO) << "conformance-cpp: received EOF from test runner after " - << total_runs << " tests"; -} diff --git a/src/struct_pb/conformance/conformance_struct_pb.cc b/src/struct_pb/conformance/conformance_struct_pb.cc deleted file mode 100644 index 5d7f2667c..000000000 --- a/src/struct_pb/conformance/conformance_struct_pb.cc +++ /dev/null @@ -1,242 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -namespace fs = std::filesystem; - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "conformance/conformance.struct_pb.h" -#include "google/protobuf/test_messages_proto2.struct_pb.h" -#include "google/protobuf/test_messages_proto3.struct_pb.h" - -#define RETURN_IF_ERROR(expr) \ - do { \ - /* Using _status below to avoid capture problems if expr is "status". */ \ - const absl::Status _status = (expr); \ - if (!_status.ok()) \ - return _status; \ - } while (0) - -using ::conformance::ConformanceRequest; -using ::conformance::ConformanceResponse; -using ::protobuf_test_messages::proto2::TestAllTypesProto2; -using ::protobuf_test_messages::proto3::TestAllTypesProto3; - -absl::Status ReadFd(int fd, char* buf, size_t len) { - while (len > 0) { - ssize_t bytes_read = read(fd, buf, len); - - if (bytes_read == 0) { - return absl::DataLossError("unexpected EOF"); - } - - if (bytes_read < 0) { - return absl::ErrnoToStatus(errno, "error reading from test runner"); - } - - len -= bytes_read; - buf += bytes_read; - } - return absl::OkStatus(); -} - -absl::Status WriteFd(int fd, const void* buf, size_t len) { - if (static_cast(write(fd, buf, len)) != len) { - return absl::ErrnoToStatus(errno, "error reading to test runner"); - } - return absl::OkStatus(); -} - -class Harness { - public: - Harness() {} - - absl::StatusOr RunTest( - const ConformanceRequest& request); - - // Returns Ok(true) if we're done processing requests. - absl::StatusOr ServeConformanceRequest(); - - private: - bool verbose_ = false; - std::string type_url_; -}; - -template -absl::StatusOr run_test( - const ConformanceRequest& request) { - ConformanceResponse response{}; - T data{}; - struct_pb::UnknownFields unknown_fields{}; - switch (request.payload_case()) { - case ConformanceRequest::PayloadCase::protobuf_payload: { - const auto& buffer = request.protobuf_payload(); - bool ok = struct_pb::internal::deserialize_to( - data, buffer.data(), buffer.size(), unknown_fields); - if (!ok) { - response.set_parse_error("parse error (no more details available)"); - return response; - } - break; - } - case ConformanceRequest::PayloadCase::none: - return absl::UnimplementedError("payload none"); - case ConformanceRequest::PayloadCase::json_payload: - return absl::UnimplementedError("payload json"); - case ConformanceRequest::PayloadCase::jspb_payload: - return absl::UnimplementedError("payload jspb"); - case ConformanceRequest::PayloadCase::text_payload: - return absl::UnimplementedError("payload text"); - default: { - int num = static_cast(request.payload_case()); - return absl::UnimplementedError("unknown payload type: " + - std::to_string(num)); - } - } - switch (request.requested_output_format) { - case conformance::WireFormat::PROTOBUF: { - response.set_protobuf_payload( - struct_pb::serialize(data, unknown_fields)); - break; - } - case conformance::WireFormat::UNSPECIFIED: - return absl::InvalidArgumentError("unspecified output format"); - case conformance::WireFormat::JSON: - return absl::UnimplementedError("output json"); - case conformance::WireFormat::JSPB: - return absl::UnimplementedError("output jspb"); - case conformance::WireFormat::TEXT_FORMAT: - return absl::UnimplementedError("output text"); - default: { - int num = static_cast(request.requested_output_format); - return absl::UnimplementedError("unknown output type: " + - std::to_string(num)); - } - } - return response; -} - -absl::StatusOr Harness::RunTest( - const ConformanceRequest& request) { - std::string pb2 = "protobuf_test_messages.proto2.TestAllTypesProto2"; - std::string pb3 = "protobuf_test_messages.proto3.TestAllTypesProto3"; - if (request.message_type == pb2) { - using Message = protobuf_test_messages::proto2::TestAllTypesProto2; - return run_test(request); - } - else if (request.message_type == pb3) { - using Message = protobuf_test_messages::proto3::TestAllTypesProto3; - return run_test(request); - } - else if (request.message_type == "conformance.FailureSet") { - return run_test(request); - } - else { - return absl::NotFoundError( - absl::StrCat("No such message type: ", request.message_type)); - } -} - -absl::StatusOr Harness::ServeConformanceRequest() { - uint32_t in_len; - if (!ReadFd(STDIN_FILENO, reinterpret_cast(&in_len), sizeof(in_len)) - .ok()) { - // EOF means we're done. - return true; - } - - std::string serialized_input; - serialized_input.resize(in_len); - RETURN_IF_ERROR(ReadFd(STDIN_FILENO, &serialized_input[0], in_len)); - - ConformanceRequest request{}; - const auto& buffer = serialized_input; - bool ok = struct_pb::internal::deserialize_to(request, buffer.data(), - buffer.size()); - if (!ok) { - return false; - } - - absl::StatusOr response = RunTest(request); - RETURN_IF_ERROR(response.status()); - - std::string serialized_output = struct_pb::serialize(*response); - - uint32_t out_len = static_cast(serialized_output.size()); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, &out_len, sizeof(out_len))); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, serialized_output.data(), out_len)); - if (verbose_) { - std::cerr << "conformance-cpp: request="; - std::cerr << request.message_type << std::endl; - } - return false; -} - -int main() { - Harness harness; - int total_runs = 0; - while (true) { - auto is_done = harness.ServeConformanceRequest(); - if (!is_done.ok()) { - std::cerr << is_done.status(); - } - if (*is_done) { - break; - } - total_runs++; - } - std::cerr << "conformance-struct_pb: received EOF from test runner after "; - std::cerr << total_runs << " tests" << std::endl; - return 0; -} - -// -// the following code is useful for debugging when struct_pb conformance test -// failed. -// - -std::string read_file(const std::string& tag, int index, - const std::string& suffix) { - std::string filename = tag + "/" + std::to_string(index) + "." + suffix; - std::ifstream ifs; - ifs.open(filename, std::ios::in | std::ios::binary); - std::size_t sz = fs::file_size(filename); - std::string buffer; - buffer.resize(sz); - ifs.read(buffer.data(), buffer.size()); - return buffer; -} -int debug_struct_pb() { - Harness harness; - int index = 0; - while (index < 1283) { - // use data generated by conformance_cpp - auto in_buf = read_file("in", index, "bin"); - auto out_buf = read_file("out", index, "bin"); - ConformanceRequest req{}; - bool ok = - struct_pb::internal::deserialize_to(req, in_buf.data(), in_buf.size()); - if (!ok) { - std::cout << "ERROR: " << index << " decode" << std::endl; - return 1; - } - auto ret = harness.RunTest(req); - if (!ret.ok()) { - std::cout << "ERROR: " << index << " run test" << std::endl; - return 2; - } - auto buf = struct_pb::serialize(*ret); - if (buf != out_buf) { - std::cout << "ERROR: " << index << " test fail" << std::endl; - return 3; - } - index++; - } - return 0; -} diff --git a/src/struct_pb/conformance/conformance_test.cc b/src/struct_pb/conformance/conformance_test.cc deleted file mode 100644 index 0f27ab2b7..000000000 --- a/src/struct_pb/conformance/conformance_test.cc +++ /dev/null @@ -1,526 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "conformance_test.h" - -#include - -#include -#include -#include - -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "conformance/conformance.pb.h" -#include "google/protobuf/message.h" -#include "google/protobuf/text_format.h" -#include "google/protobuf/util/field_comparator.h" -#include "google/protobuf/util/json_util.h" -#include "google/protobuf/util/message_differencer.h" - -using conformance::ConformanceRequest; -using conformance::ConformanceResponse; -using conformance::WireFormat; -using google::protobuf::TextFormat; -using google::protobuf::util::DefaultFieldComparator; -using google::protobuf::util::MessageDifferencer; -using std::string; - -namespace { - -static string ToOctString(const string& binary_string) { - string oct_string; - for (size_t i = 0; i < binary_string.size(); i++) { - uint8_t c = binary_string.at(i); - uint8_t high = c / 64; - uint8_t mid = (c % 64) / 8; - uint8_t low = c % 8; - oct_string.push_back('\\'); - oct_string.push_back('0' + high); - oct_string.push_back('0' + mid); - oct_string.push_back('0' + low); - } - return oct_string; -} - -} // namespace - -namespace google { -namespace protobuf { - -ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting( - ConformanceLevel level, conformance::WireFormat input_format, - conformance::WireFormat output_format, - conformance::TestCategory test_category, const Message& prototype_message, - const string& test_name, const string& input) - : level_(level), - input_format_(input_format), - output_format_(output_format), - prototype_message_(prototype_message), - prototype_message_for_compare_(prototype_message.New()), - test_name_(test_name) { - switch (input_format) { - case conformance::PROTOBUF: { - request_.set_protobuf_payload(input); - break; - } - - case conformance::JSON: { - request_.set_json_payload(input); - break; - } - - case conformance::JSPB: { - request_.set_jspb_payload(input); - break; - } - - case conformance::TEXT_FORMAT: { - request_.set_text_payload(input); - break; - } - - default: - GOOGLE_LOG(FATAL) << "Unspecified input format"; - } - - request_.set_test_category(test_category); - - request_.set_message_type(prototype_message.GetDescriptor()->full_name()); - request_.set_requested_output_format(output_format); -} - -std::unique_ptr -ConformanceTestSuite::ConformanceRequestSetting::NewTestMessage() const { - return std::unique_ptr(prototype_message_for_compare_->New()); -} - -string ConformanceTestSuite::ConformanceRequestSetting::GetTestName() const { - string rname = prototype_message_.GetDescriptor()->file()->syntax() == - FileDescriptor::SYNTAX_PROTO3 - ? "Proto3" - : "Proto2"; - - return absl::StrCat(ConformanceLevelToString(level_), ".", rname, ".", - InputFormatString(input_format_), ".", test_name_, ".", - OutputFormatString(output_format_)); -} - -string -ConformanceTestSuite::ConformanceRequestSetting::ConformanceLevelToString( - ConformanceLevel level) const { - switch (level) { - case REQUIRED: - return "Required"; - case RECOMMENDED: - return "Recommended"; - } - GOOGLE_LOG(FATAL) << "Unknown value: " << level; - return ""; -} - -string ConformanceTestSuite::ConformanceRequestSetting::InputFormatString( - conformance::WireFormat format) const { - switch (format) { - case conformance::PROTOBUF: - return "ProtobufInput"; - case conformance::JSON: - return "JsonInput"; - case conformance::TEXT_FORMAT: - return "TextFormatInput"; - default: - GOOGLE_LOG(FATAL) << "Unspecified output format"; - } - return ""; -} - -string ConformanceTestSuite::ConformanceRequestSetting::OutputFormatString( - conformance::WireFormat format) const { - switch (format) { - case conformance::PROTOBUF: - return "ProtobufOutput"; - case conformance::JSON: - return "JsonOutput"; - case conformance::TEXT_FORMAT: - return "TextFormatOutput"; - default: - GOOGLE_LOG(FATAL) << "Unspecified output format"; - } - return ""; -} - -void ConformanceTestSuite::TruncateDebugPayload(string* payload) { - if (payload != nullptr && payload->size() > 200) { - payload->resize(200); - payload->append("...(truncated)"); - } -} - -const ConformanceRequest ConformanceTestSuite::TruncateRequest( - const ConformanceRequest& request) { - ConformanceRequest debug_request(request); - switch (debug_request.payload_case()) { - case ConformanceRequest::kProtobufPayload: - TruncateDebugPayload(debug_request.mutable_protobuf_payload()); - break; - case ConformanceRequest::kJsonPayload: - TruncateDebugPayload(debug_request.mutable_json_payload()); - break; - case ConformanceRequest::kTextPayload: - TruncateDebugPayload(debug_request.mutable_text_payload()); - break; - case ConformanceRequest::kJspbPayload: - TruncateDebugPayload(debug_request.mutable_jspb_payload()); - break; - default: - // Do nothing. - break; - } - return debug_request; -} - -const ConformanceResponse ConformanceTestSuite::TruncateResponse( - const ConformanceResponse& response) { - ConformanceResponse debug_response(response); - switch (debug_response.result_case()) { - case ConformanceResponse::kProtobufPayload: - TruncateDebugPayload(debug_response.mutable_protobuf_payload()); - break; - case ConformanceResponse::kJsonPayload: - TruncateDebugPayload(debug_response.mutable_json_payload()); - break; - case ConformanceResponse::kTextPayload: - TruncateDebugPayload(debug_response.mutable_text_payload()); - break; - case ConformanceResponse::kJspbPayload: - TruncateDebugPayload(debug_response.mutable_jspb_payload()); - break; - default: - // Do nothing. - break; - } - return debug_response; -} - -void ConformanceTestSuite::ReportSuccess(const string& test_name) { - if (expected_to_fail_.erase(test_name) != 0) { - absl::StrAppendFormat( - &output_, - "ERROR: test %s is in the failure list, but test succeeded. " - "Remove it from the failure list.\n", - test_name); - unexpected_succeeding_tests_.insert(test_name); - } - successes_++; -} - -void ConformanceTestSuite::ReportFailure(const string& test_name, - ConformanceLevel level, - const ConformanceRequest& request, - const ConformanceResponse& response, - std::string_view message) { - if (expected_to_fail_.erase(test_name) == 1) { - expected_failures_++; - if (!verbose_) - return; - } - else if (level == RECOMMENDED && !enforce_recommended_) { - absl::StrAppendFormat(&output_, "WARNING, test=%s: ", test_name); - } - else { - absl::StrAppendFormat(&output_, "ERROR, test=%s: ", test_name); - unexpected_failing_tests_.insert(test_name); - } - - absl::StrAppendFormat(&output_, "%s, request=%s, response=%s\n", message, - TruncateRequest(request).ShortDebugString(), - TruncateResponse(response).ShortDebugString()); -} - -void ConformanceTestSuite::ReportSkip(const string& test_name, - const ConformanceRequest& request, - const ConformanceResponse& response) { - if (verbose_) { - absl::StrAppendFormat( - &output_, "SKIPPED, test=%s request=%s, response=%s\n", test_name, - request.ShortDebugString(), response.ShortDebugString()); - } - skipped_.insert(test_name); -} - -void ConformanceTestSuite::RunValidInputTest( - const ConformanceRequestSetting& setting, - const string& equivalent_text_format) { - std::unique_ptr reference_message(setting.NewTestMessage()); - GOOGLE_CHECK(TextFormat::ParseFromString(equivalent_text_format, - reference_message.get())) - << "Failed to parse data for test case: " << setting.GetTestName() - << ", data: " << equivalent_text_format; - const string equivalent_wire_format = reference_message->SerializeAsString(); - RunValidBinaryInputTest(setting, equivalent_wire_format); -} - -void ConformanceTestSuite::RunValidBinaryInputTest( - const ConformanceRequestSetting& setting, - const string& equivalent_wire_format, bool require_same_wire_format) { - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - RunTest(setting.GetTestName(), request, &response); - VerifyResponse(setting, equivalent_wire_format, response, true, - require_same_wire_format); -} - -void ConformanceTestSuite::VerifyResponse( - const ConformanceRequestSetting& setting, - const string& equivalent_wire_format, const ConformanceResponse& response, - bool need_report_success, bool require_same_wire_format) { - std::unique_ptr test_message(setting.NewTestMessage()); - const ConformanceRequest& request = setting.GetRequest(); - const string& test_name = setting.GetTestName(); - ConformanceLevel level = setting.GetLevel(); - std::unique_ptr reference_message = setting.NewTestMessage(); - - GOOGLE_CHECK(reference_message->ParseFromString(equivalent_wire_format)) - << "Failed to parse wire data for test case: " << test_name; - - switch (response.result_case()) { - case ConformanceResponse::RESULT_NOT_SET: - ReportFailure(test_name, level, request, response, - "Response didn't have any field in the Response."); - return; - - case ConformanceResponse::kParseError: - case ConformanceResponse::kTimeoutError: - case ConformanceResponse::kRuntimeError: - case ConformanceResponse::kSerializeError: - ReportFailure(test_name, level, request, response, - "Failed to parse input or produce output."); - return; - - case ConformanceResponse::kSkipped: - ReportSkip(test_name, request, response); - return; - - default: - if (!ParseResponse(response, setting, test_message.get())) - return; - } - - MessageDifferencer differencer; - DefaultFieldComparator field_comparator; - field_comparator.set_treat_nan_as_equal(true); - differencer.set_field_comparator(&field_comparator); - string differences; - differencer.ReportDifferencesToString(&differences); - - bool check = false; - - if (require_same_wire_format) { - GOOGLE_DCHECK_EQ(response.result_case(), - ConformanceResponse::kProtobufPayload); - const string& protobuf_payload = response.protobuf_payload(); - check = equivalent_wire_format == protobuf_payload; - differences = absl::StrCat("Expect: ", ToOctString(equivalent_wire_format), - ", but got: ", ToOctString(protobuf_payload)); - } - else { - check = differencer.Compare(*reference_message, *test_message); - } - - if (check) { - if (need_report_success) { - ReportSuccess(test_name); - } - } - else { - ReportFailure( - test_name, level, request, response, - absl::StrCat("Output was not equivalent to reference message: ", - differences)); - } -} - -void ConformanceTestSuite::RunTest(const string& test_name, - const ConformanceRequest& request, - ConformanceResponse* response) { - if (test_names_.insert(test_name).second == false) { - GOOGLE_LOG(FATAL) << "Duplicated test name: " << test_name; - } - - string serialized_request; - string serialized_response; - request.SerializeToString(&serialized_request); - - runner_->RunTest(test_name, serialized_request, &serialized_response); - - if (!response->ParseFromString(serialized_response)) { - response->Clear(); - response->set_runtime_error("response proto could not be parsed."); - } - - if (verbose_) { - absl::StrAppendFormat( - &output_, "conformance test: name=%s, request=%s, response=%s\n", - test_name, TruncateRequest(request).ShortDebugString(), - TruncateResponse(*response).ShortDebugString()); - } -} - -bool ConformanceTestSuite::CheckSetEmpty(const std::set& set_to_check, - const std::string& write_to_file, - const std::string& msg) { - if (set_to_check.empty()) { - return true; - } - else { - absl::StrAppendFormat(&output_, "\n"); - absl::StrAppendFormat(&output_, "%s\n\n", msg); - for (std::string_view v : set_to_check) { - absl::StrAppendFormat(&output_, " %s\n", v); - } - absl::StrAppendFormat(&output_, "\n"); - - if (!write_to_file.empty()) { - std::string full_filename; - const std::string* filename = &write_to_file; - if (!output_dir_.empty()) { - full_filename = output_dir_; - if (*output_dir_.rbegin() != '/') { - full_filename.push_back('/'); - } - full_filename += write_to_file; - filename = &full_filename; - } - std::ofstream os(*filename); - if (os) { - for (std::string_view v : set_to_check) { - os << v << "\n"; - } - } - else { - absl::StrAppendFormat(&output_, "Failed to open file: %s\n", *filename); - } - } - - return false; - } -} - -string ConformanceTestSuite::WireFormatToString(WireFormat wire_format) { - switch (wire_format) { - case conformance::PROTOBUF: - return "PROTOBUF"; - case conformance::JSON: - return "JSON"; - case conformance::JSPB: - return "JSPB"; - case conformance::TEXT_FORMAT: - return "TEXT_FORMAT"; - case conformance::UNSPECIFIED: - return "UNSPECIFIED"; - default: - GOOGLE_LOG(FATAL) << "unknown wire type: " << wire_format; - } - return ""; -} - -void ConformanceTestSuite::AddExpectedFailedTest(const std::string& test_name) { - expected_to_fail_.insert(test_name); -} - -bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner, - std::string* output, const string& filename, - conformance::FailureSet* failure_list) { - runner_ = runner; - successes_ = 0; - expected_failures_ = 0; - skipped_.clear(); - test_names_.clear(); - unexpected_failing_tests_.clear(); - unexpected_succeeding_tests_.clear(); - - output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n"; - - failure_list_filename_ = filename; - expected_to_fail_.clear(); - for (const string& failure : failure_list->failure()) { - AddExpectedFailedTest(failure); - } - RunSuiteImpl(); - - bool ok = true; - if (!CheckSetEmpty(expected_to_fail_, "nonexistent_tests.txt", - "These tests were listed in the failure list, but they " - "don't exist. Remove them from the failure list by " - "running:\n" - " ./update_failure_list.py " + - failure_list_filename_ + - " --remove nonexistent_tests.txt")) { - ok = false; - } - if (!CheckSetEmpty(unexpected_failing_tests_, "failing_tests.txt", - "These tests failed. If they can't be fixed right now, " - "you can add them to the failure list so the overall " - "suite can succeed. Add them to the failure list by " - "running:\n" - " ./update_failure_list.py " + - failure_list_filename_ + " --add failing_tests.txt")) { - ok = false; - } - if (!CheckSetEmpty(unexpected_succeeding_tests_, "succeeding_tests.txt", - "These tests succeeded, even though they were listed in " - "the failure list. Remove them from the failure list " - "by running:\n" - " ./update_failure_list.py " + - failure_list_filename_ + - " --remove succeeding_tests.txt")) { - ok = false; - } - - if (verbose_) { - CheckSetEmpty(skipped_, "", - "These tests were skipped (probably because support for some " - "features is not implemented)"); - } - - absl::StrAppendFormat(&output_, - "CONFORMANCE SUITE %s: %d successes, %zu skipped, " - "%d expected failures, %zu unexpected failures.\n", - ok ? "PASSED" : "FAILED", successes_, skipped_.size(), - expected_failures_, unexpected_failing_tests_.size()); - absl::StrAppendFormat(&output_, "\n"); - - output->assign(output_); - - return ok; -} - -} // namespace protobuf -} // namespace google diff --git a/src/struct_pb/conformance/conformance_test.h b/src/struct_pb/conformance/conformance_test.h deleted file mode 100644 index cf09234aa..000000000 --- a/src/struct_pb/conformance/conformance_test.h +++ /dev/null @@ -1,331 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file defines a protocol for running the conformance test suite -// in-process. In other words, the suite itself will run in the same process as -// the code under test. -// -// For pros and cons of this approach, please see conformance.proto. - -#ifndef CONFORMANCE_CONFORMANCE_TEST_H -#define CONFORMANCE_CONFORMANCE_TEST_H - -#include -#include -#include - -#include "conformance/conformance.pb.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/util/type_resolver.h" -#include "google/protobuf/wire_format_lite.h" - -namespace conformance { -class ConformanceRequest; -class ConformanceResponse; -} // namespace conformance - -namespace protobuf_test_messages { -namespace proto3 { -class TestAllTypesProto3; -} // namespace proto3 -} // namespace protobuf_test_messages - -namespace google { -namespace protobuf { - -class ConformanceTestSuite; - -class ConformanceTestRunner { - public: - virtual ~ConformanceTestRunner() {} - - // Call to run a single conformance test. - // - // "input" is a serialized conformance.ConformanceRequest. - // "output" should be set to a serialized conformance.ConformanceResponse. - // - // If there is any error in running the test itself, set "runtime_error" in - // the response. - virtual void RunTest(const std::string& test_name, const std::string& input, - std::string* output) = 0; -}; - -// Test runner that spawns the process being tested and communicates with it -// over a pipe. -class ForkPipeRunner : public ConformanceTestRunner { - public: - // Note: Run() doesn't take ownership of the pointers inside suites. - static int Run(int argc, char* argv[], - const std::vector& suites); - - ForkPipeRunner(const std::string& executable, - const std::vector& executable_args, - bool performance) - : child_pid_(-1), - executable_(executable), - executable_args_(executable_args), - performance_(performance) {} - - explicit ForkPipeRunner(const std::string& executable) - : child_pid_(-1), executable_(executable) {} - - virtual ~ForkPipeRunner() {} - - void RunTest(const std::string& test_name, const std::string& request, - std::string* response); - - private: - void SpawnTestProgram(); - - void CheckedWrite(int fd, const void* buf, size_t len); - bool TryRead(int fd, void* buf, size_t len); - void CheckedRead(int fd, void* buf, size_t len); - - int write_fd_; - int read_fd_; - pid_t child_pid_; - std::string executable_; - const std::vector executable_args_; - bool performance_; - std::string current_test_name_; -}; - -// Class representing the test suite itself. To run it, implement your own -// class derived from ConformanceTestRunner, class derived from -// ConformanceTestSuite and then write code like: -// -// class MyConformanceTestSuite : public ConformanceTestSuite { -// public: -// void RunSuiteImpl() { -// // INSERT ACTUAL TESTS. -// } -// }; -// -// class MyConformanceTestRunner : public ConformanceTestRunner { -// public: -// static int Run(int argc, char *argv[], -// ConformanceTestSuite* suite); -// -// private: -// virtual void RunTest(...) { -// // INSERT YOUR FRAMEWORK-SPECIFIC CODE HERE. -// } -// }; -// -// int main() { -// MyConformanceTestSuite suite; -// MyConformanceTestRunner::Run(argc, argv, &suite); -// } -// -class ConformanceTestSuite { - public: - ConformanceTestSuite() - : verbose_(false), - performance_(false), - enforce_recommended_(false), - failure_list_flag_name_("--failure_list") {} - virtual ~ConformanceTestSuite() {} - - void SetPerformance(bool performance) { performance_ = performance; } - void SetVerbose(bool verbose) { verbose_ = verbose; } - - // Whether to require the testee to pass RECOMMENDED tests. By default failing - // a RECOMMENDED test case will not fail the entire suite but will only - // generated a warning. If this flag is set to true, RECOMMENDED tests will - // be treated the same way as REQUIRED tests and failing a RECOMMENDED test - // case will cause the entire test suite to fail as well. An implementation - // can enable this if it wants to be strictly conforming to protobuf spec. - // See the comments about ConformanceLevel below to learn more about the - // difference between REQUIRED and RECOMMENDED test cases. - void SetEnforceRecommended(bool value) { enforce_recommended_ = value; } - - // Gets the flag name to the failure list file. - // By default, this would return --failure_list - std::string GetFailureListFlagName() { return failure_list_flag_name_; } - - void SetFailureListFlagName(const std::string& failure_list_flag_name) { - failure_list_flag_name_ = failure_list_flag_name; - } - - // Sets the path of the output directory. - void SetOutputDir(const char* output_dir) { output_dir_ = output_dir; } - - // Run all the conformance tests against the given test runner. - // Test output will be stored in "output". - // - // Returns true if the set of failing tests was exactly the same as the - // failure list. - // The filename here is *only* used to create/format useful error messages for - // how to update the failure list. We do NOT read this file at all. - bool RunSuite(ConformanceTestRunner* runner, std::string* output, - const std::string& filename, - conformance::FailureSet* failure_list); - - protected: - // Test cases are classified into a few categories: - // REQUIRED: the test case must be passed for an implementation to be - // interoperable with other implementations. For example, a - // parser implementation must accept both packed and unpacked - // form of repeated primitive fields. - // RECOMMENDED: the test case is not required for the implementation to - // be interoperable with other implementations, but is - // recommended for best performance and compatibility. For - // example, a proto3 serializer should serialize repeated - // primitive fields in packed form, but an implementation - // failing to do so will still be able to communicate with - // other implementations. - enum ConformanceLevel { - REQUIRED = 0, - RECOMMENDED = 1, - }; - - class ConformanceRequestSetting { - public: - ConformanceRequestSetting(ConformanceLevel level, - conformance::WireFormat input_format, - conformance::WireFormat output_format, - conformance::TestCategory test_category, - const Message& prototype_message, - const std::string& test_name, - const std::string& input); - virtual ~ConformanceRequestSetting() {} - - std::unique_ptr NewTestMessage() const; - - std::string GetTestName() const; - - const conformance::ConformanceRequest& GetRequest() const { - return request_; - } - - const ConformanceLevel GetLevel() const { return level_; } - - std::string ConformanceLevelToString(ConformanceLevel level) const; - - void SetPrintUnknownFields(bool print_unknown_fields) { - request_.set_print_unknown_fields(true); - } - - void SetPrototypeMessageForCompare(const Message& message) { - prototype_message_for_compare_.reset(message.New()); - } - - protected: - virtual std::string InputFormatString(conformance::WireFormat format) const; - virtual std::string OutputFormatString( - conformance::WireFormat format) const; - conformance::ConformanceRequest request_; - - private: - ConformanceLevel level_; - ::conformance::WireFormat input_format_; - ::conformance::WireFormat output_format_; - const Message& prototype_message_; - std::unique_ptr prototype_message_for_compare_; - std::string test_name_; - }; - - bool CheckSetEmpty(const std::set& set_to_check, - const std::string& write_to_file, const std::string& msg); - std::string WireFormatToString(conformance::WireFormat wire_format); - - // Parse payload in the response to the given message. Returns true on - // success. - virtual bool ParseResponse(const conformance::ConformanceResponse& response, - const ConformanceRequestSetting& setting, - Message* test_message) = 0; - - void VerifyResponse(const ConformanceRequestSetting& setting, - const std::string& equivalent_wire_format, - const conformance::ConformanceResponse& response, - bool need_report_success, bool require_same_wire_format); - - void TruncateDebugPayload(std::string* payload); - const conformance::ConformanceRequest TruncateRequest( - const conformance::ConformanceRequest& request); - const conformance::ConformanceResponse TruncateResponse( - const conformance::ConformanceResponse& response); - - void ReportSuccess(const std::string& test_name); - void ReportFailure(const std::string& test_name, ConformanceLevel level, - const conformance::ConformanceRequest& request, - const conformance::ConformanceResponse& response, - std::string_view message); - void ReportSkip(const std::string& test_name, - const conformance::ConformanceRequest& request, - const conformance::ConformanceResponse& response); - - void RunValidInputTest(const ConformanceRequestSetting& setting, - const std::string& equivalent_text_format); - void RunValidBinaryInputTest(const ConformanceRequestSetting& setting, - const std::string& equivalent_wire_format, - bool require_same_wire_format = false); - - void RunTest(const std::string& test_name, - const conformance::ConformanceRequest& request, - conformance::ConformanceResponse* response); - - void AddExpectedFailedTest(const std::string& test_name); - - virtual void RunSuiteImpl() = 0; - - ConformanceTestRunner* runner_; - int successes_; - int expected_failures_; - bool verbose_; - bool performance_; - bool enforce_recommended_; - std::string output_; - std::string output_dir_; - std::string failure_list_flag_name_; - std::string failure_list_filename_; - - // The set of test names that are expected to fail in this run, but haven't - // failed yet. - std::set expected_to_fail_; - - // The set of test names that have been run. Used to ensure that there are no - // duplicate names in the suite. - std::set test_names_; - - // The set of tests that failed, but weren't expected to. - std::set unexpected_failing_tests_; - - // The set of tests that succeeded, but weren't expected to. - std::set unexpected_succeeding_tests_; - - // The set of tests that the testee opted out of; - std::set skipped_; -}; - -} // namespace protobuf -} // namespace google - -#endif // CONFORMANCE_CONFORMANCE_TEST_H diff --git a/src/struct_pb/conformance/conformance_test_main.cc b/src/struct_pb/conformance/conformance_test_main.cc deleted file mode 100644 index fe958f90a..000000000 --- a/src/struct_pb/conformance/conformance_test_main.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "binary_json_conformance_suite.h" -#include "conformance_test.h" - -int main(int argc, char *argv[]) { - google::protobuf::BinaryAndJsonConformanceSuite binary_and_json_suite; - return google::protobuf::ForkPipeRunner::Run(argc, argv, - {&binary_and_json_suite}); -} diff --git a/src/struct_pb/conformance/conformance_test_runner.cc b/src/struct_pb/conformance/conformance_test_runner.cc deleted file mode 100644 index c52f650be..000000000 --- a/src/struct_pb/conformance/conformance_test_runner.cc +++ /dev/null @@ -1,407 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file contains a program for running the test suite in a separate -// process. The other alternative is to run the suite in-process. See -// conformance.proto for pros/cons of these two options. -// -// This program will fork the process under test and communicate with it over -// its stdin/stdout: -// -// +--------+ pipe +----------+ -// | tester | <------> | testee | -// | | | | -// | C++ | | any lang | -// +--------+ +----------+ -// -// The tester contains all of the test cases and their expected output. -// The testee is a simple program written in the target language that reads -// each test case and attempts to produce acceptable output for it. -// -// Every test consists of a ConformanceRequest/ConformanceResponse -// request/reply pair. The protocol on the pipe is simply: -// -// 1. tester sends 4-byte length N (little endian) -// 2. tester sends N bytes representing a ConformanceRequest proto -// 3. testee sends 4-byte length M (little endian) -// 4. testee sends M bytes representing a ConformanceResponse proto - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -// #include "absl/strings/str_format.h" -#include "conformance/conformance.pb.h" -#include "conformance_test.h" - -using conformance::ConformanceResponse; -using google::protobuf::ConformanceTestSuite; -using std::string; -using std::vector; - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define GOOGLE_CHECK_SYSCALL(call) \ - if (call < 0) { \ - perror(#call " " __FILE__ ":" TOSTRING(__LINE__)); \ - exit(1); \ - } - -namespace google { -namespace protobuf { - -void ParseFailureList(const char *filename, - conformance::FailureSet *failure_list) { - std::ifstream infile(filename); - - if (!infile.is_open()) { - fprintf(stderr, "Couldn't open failure list file: %s\n", filename); - exit(1); - } - - for (string line; getline(infile, line);) { - // Remove whitespace. - line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end()); - - // Remove comments. - line = line.substr(0, line.find("#")); - - if (!line.empty()) { - failure_list->add_failure(line); - } - } -} - -void UsageError() { - fprintf(stderr, "Usage: conformance-test-runner [options] \n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Options:\n"); - fprintf(stderr, - " --failure_list Use to specify list of tests\n"); - fprintf(stderr, - " that are expected to fail. File\n"); - fprintf(stderr, - " should contain one test name per\n"); - fprintf(stderr, - " line. Use '#' for comments.\n"); - fprintf(stderr, - " --text_format_failure_list Use to specify list \n"); - fprintf(stderr, - " of tests that are expected to \n"); - fprintf(stderr, " fail in the \n"); - fprintf(stderr, - " text_format_conformance_suite. \n"); - fprintf(stderr, - " File should contain one test name \n"); - fprintf(stderr, - " per line. Use '#' for comments.\n"); - - fprintf(stderr, - " --enforce_recommended Enforce that recommended test\n"); - fprintf(stderr, - " cases are also passing. Specify\n"); - fprintf(stderr, - " this flag if you want to be\n"); - fprintf(stderr, - " strictly conforming to protobuf\n"); - fprintf(stderr, " spec.\n"); - fprintf(stderr, - " --output_dir Directory to write\n" - " output files.\n"); - exit(1); -} - -void ForkPipeRunner::RunTest(const std::string &test_name, - const std::string &request, - std::string *response) { - if (child_pid_ < 0) { - SpawnTestProgram(); - } - current_test_name_ = test_name; - - uint32_t len = request.size(); - CheckedWrite(write_fd_, &len, sizeof(uint32_t)); - CheckedWrite(write_fd_, request.c_str(), request.size()); - - if (!TryRead(read_fd_, &len, sizeof(uint32_t))) { - // We failed to read from the child, assume a crash and try to reap. - GOOGLE_LOG(INFO) << "Trying to reap child, pid=" << child_pid_; - - int status = 0; - waitpid(child_pid_, &status, WEXITED); - - string error_msg; - conformance::ConformanceResponse response_obj; - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) == 0) { - error_msg = "child timed out, killed by signal " + - std::to_string(WTERMSIG(status)); - response_obj.set_timeout_error(error_msg); - } - else { - error_msg = - "child exited, status=" + std::to_string(WEXITSTATUS(status)); - response_obj.set_runtime_error(error_msg); - } - } - else if (WIFSIGNALED(status)) { - error_msg = "child killed by signal " + std::to_string(WTERMSIG(status)); - } - GOOGLE_LOG(INFO) << error_msg; - child_pid_ = -1; - - response_obj.SerializeToString(response); - return; - } - - response->resize(len); - CheckedRead(read_fd_, (void *)response->c_str(), len); -} - -int ForkPipeRunner::Run(int argc, char *argv[], - const std::vector &suites) { - if (suites.empty()) { - fprintf(stderr, "No test suites found.\n"); - return EXIT_FAILURE; - } - bool all_ok = true; - for (ConformanceTestSuite *suite : suites) { - string program; - std::vector program_args; - string failure_list_filename; - conformance::FailureSet failure_list; - - bool performance = false; - for (int arg = 1; arg < argc; ++arg) { - if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) { - if (++arg == argc) - UsageError(); - failure_list_filename = argv[arg]; - ParseFailureList(argv[arg], &failure_list); - } - else if (strcmp(argv[arg], "--performance") == 0) { - performance = true; - suite->SetPerformance(true); - } - else if (strcmp(argv[arg], "--verbose") == 0) { - suite->SetVerbose(true); - } - else if (strcmp(argv[arg], "--enforce_recommended") == 0) { - suite->SetEnforceRecommended(true); - } - else if (strcmp(argv[arg], "--output_dir") == 0) { - if (++arg == argc) - UsageError(); - suite->SetOutputDir(argv[arg]); - } - else if (argv[arg][0] == '-') { - bool recognized_flag = false; - for (ConformanceTestSuite *suite : suites) { - if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) { - if (++arg == argc) - UsageError(); - recognized_flag = true; - } - } - if (!recognized_flag) { - fprintf(stderr, "Unknown option: %s\n", argv[arg]); - UsageError(); - } - } - else { - program += argv[arg++]; - while (arg < argc) { - program_args.push_back(argv[arg]); - arg++; - } - } - } - - ForkPipeRunner runner(program, program_args, performance); - - std::string output; - all_ok = all_ok && suite->RunSuite(&runner, &output, failure_list_filename, - &failure_list); - - fwrite(output.c_str(), 1, output.size(), stderr); - } - return all_ok ? EXIT_SUCCESS : EXIT_FAILURE; -} - -// TODO(haberman): make this work on Windows, instead of using these -// UNIX-specific APIs. -// -// There is a platform-agnostic API in -// src/google/protobuf/compiler/subprocess.h -// -// However that API only supports sending a single message to the subprocess. -// We really want to be able to send messages and receive responses one at a -// time: -// -// 1. Spawning a new process for each test would take way too long for thousands -// of tests and subprocesses like java that can take 100ms or more to start -// up. -// -// 2. Sending all the tests in one big message and receiving all results in one -// big message would take away our visibility about which test(s) caused a -// crash or other fatal error. It would also give us only a single failure -// instead of all of them. -void ForkPipeRunner::SpawnTestProgram() { - int toproc_pipe_fd[2]; - int fromproc_pipe_fd[2]; - if (pipe(toproc_pipe_fd) < 0 || pipe(fromproc_pipe_fd) < 0) { - perror("pipe"); - exit(1); - } - - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); - exit(1); - } - - if (pid) { - // Parent. - GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[0])); - GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[1])); - write_fd_ = toproc_pipe_fd[1]; - read_fd_ = fromproc_pipe_fd[0]; - child_pid_ = pid; - } - else { - // Child. - GOOGLE_CHECK_SYSCALL(close(STDIN_FILENO)); - GOOGLE_CHECK_SYSCALL(close(STDOUT_FILENO)); - GOOGLE_CHECK_SYSCALL(dup2(toproc_pipe_fd[0], STDIN_FILENO)); - GOOGLE_CHECK_SYSCALL(dup2(fromproc_pipe_fd[1], STDOUT_FILENO)); - - GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[0])); - GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[1])); - GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[1])); - GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[0])); - - std::unique_ptr executable(new char[executable_.size() + 1]); - memcpy(executable.get(), executable_.c_str(), executable_.size()); - executable[executable_.size()] = '\0'; - - std::vector argv; - argv.push_back(executable.get()); - GOOGLE_LOG(INFO) << argv[0]; - for (size_t i = 0; i < executable_args_.size(); ++i) { - argv.push_back(executable_args_[i].c_str()); - GOOGLE_LOG(INFO) << executable_args_[i]; - } - argv.push_back(nullptr); - // Never returns. - GOOGLE_CHECK_SYSCALL( - execv(executable.get(), const_cast(argv.data()))); - } -} - -void ForkPipeRunner::CheckedWrite(int fd, const void *buf, size_t len) { - if (static_cast(write(fd, buf, len)) != len) { - GOOGLE_LOG(FATAL) << current_test_name_ - << ": error writing to test program: " << strerror(errno); - } -} - -bool ForkPipeRunner::TryRead(int fd, void *buf, size_t len) { - size_t ofs = 0; - while (len > 0) { - std::future future = std::async( - std::launch::async, - [](int fd, void *buf, size_t ofs, size_t len) { - return read(fd, (char *)buf + ofs, len); - }, - fd, buf, ofs, len); - std::future_status status; - if (performance_) { - status = future.wait_for(std::chrono::seconds(5)); - if (status == std::future_status::timeout) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": timeout from test program"; - kill(child_pid_, SIGQUIT); - // TODO(sandyzhang): Only log in flag-guarded mode, since reading output - // from SIGQUIT is slow and verbose. - std::vector err; - err.resize(5000); - ssize_t err_bytes_read; - size_t err_ofs = 0; - do { - err_bytes_read = - read(fd, (void *)&err[err_ofs], err.size() - err_ofs); - err_ofs += err_bytes_read; - } while (err_bytes_read > 0 && err_ofs < err.size()); - GOOGLE_LOG(ERROR) << "child_pid_=" << child_pid_ << " SIGQUIT: \n" - << &err[0]; - return false; - } - } - else { - future.wait(); - } - ssize_t bytes_read = future.get(); - if (bytes_read == 0) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": unexpected EOF from test program"; - return false; - } - else if (bytes_read < 0) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": error reading from test program: " - << strerror(errno); - return false; - } - - len -= bytes_read; - ofs += bytes_read; - } - - return true; -} - -void ForkPipeRunner::CheckedRead(int fd, void *buf, size_t len) { - if (!TryRead(fd, buf, len)) { - GOOGLE_LOG(FATAL) << current_test_name_ - << ": error reading from test program: " - << strerror(errno); - } -} - -} // namespace protobuf -} // namespace google diff --git a/src/struct_pb/conformance/failure_list_cpp.txt b/src/struct_pb/conformance/failure_list_cpp.txt deleted file mode 100644 index 9974dbf67..000000000 --- a/src/struct_pb/conformance/failure_list_cpp.txt +++ /dev/null @@ -1,9 +0,0 @@ -# This is the list of conformance tests that are known to fail for the C++ -# implementation right now. These should be fixed. -# -# By listing them here we can keep tabs on which ones are failing and be sure -# that we don't introduce regressions in other tests. -# -# TODO(haberman): insert links to corresponding bugs tracking the issue. -# Should we use GitHub issues or the Google-internal bug tracker? - diff --git a/src/struct_pb/conformance/google/protobuf/any.proto b/src/struct_pb/conformance/google/protobuf/any.proto deleted file mode 100644 index 561da0cb1..000000000 --- a/src/struct_pb/conformance/google/protobuf/any.proto +++ /dev/null @@ -1,161 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/known/anypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "AnyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// // or ... -// if (any.isSameTypeAs(Foo.getDefaultInstance())) { -// foo = any.unpack(Foo.getDefaultInstance()); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := anypb.New(foo) -// if err != nil { -// ... -// } -// ... -// foo := &pb.Foo{} -// if err := any.UnmarshalTo(foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// JSON -// -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -message Any { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. This string must contain at least - // one "/" character. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - string type_url = 1; - - // Must be a valid serialized protocol buffer of the above specified type. - bytes value = 2; -} diff --git a/src/struct_pb/conformance/google/protobuf/descriptor.proto b/src/struct_pb/conformance/google/protobuf/descriptor.proto deleted file mode 100644 index b65c0ea83..000000000 --- a/src/struct_pb/conformance/google/protobuf/descriptor.proto +++ /dev/null @@ -1,921 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// The messages in this file describe the definitions found in .proto files. -// A valid .proto file can be translated directly to a FileDescriptorProto -// without any other information (e.g. without reading its imports). - -syntax = "proto2"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/descriptorpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; -option objc_class_prefix = "GPB"; -option cc_enable_arenas = true; - -// descriptor.proto must be optimized for speed because reflection-based -// algorithms don't work during bootstrapping. -option optimize_for = SPEED; - -// The protocol compiler can output a FileDescriptorSet containing the .proto -// files it parses. -message FileDescriptorSet { - repeated FileDescriptorProto file = 1; -} - -// Describes a complete .proto file. -message FileDescriptorProto { - optional string name = 1; // file name, relative to root of source tree - optional string package = 2; // e.g. "foo", "foo.bar", etc. - - // Names of files imported by this file. - repeated string dependency = 3; - // Indexes of the public imported files in the dependency list above. - repeated int32 public_dependency = 10; - // Indexes of the weak imported files in the dependency list. - // For Google-internal migration only. Do not use. - repeated int32 weak_dependency = 11; - - // All top-level definitions in this file. - repeated DescriptorProto message_type = 4; - repeated EnumDescriptorProto enum_type = 5; - repeated ServiceDescriptorProto service = 6; - repeated FieldDescriptorProto extension = 7; - - optional FileOptions options = 8; - - // This field contains optional information about the original source code. - // You may safely remove this entire field without harming runtime - // functionality of the descriptors -- the information is needed only by - // development tools. - optional SourceCodeInfo source_code_info = 9; - - // The syntax of the proto file. - // The supported values are "proto2", "proto3", and "editions". - // - // If `edition` is present, this value must be "editions". - optional string syntax = 12; - - // The edition of the proto file, which is an opaque string. - optional string edition = 13; -} - -// Describes a message type. -message DescriptorProto { - optional string name = 1; - - repeated FieldDescriptorProto field = 2; - repeated FieldDescriptorProto extension = 6; - - repeated DescriptorProto nested_type = 3; - repeated EnumDescriptorProto enum_type = 4; - - message ExtensionRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - - optional ExtensionRangeOptions options = 3; - } - repeated ExtensionRange extension_range = 5; - - repeated OneofDescriptorProto oneof_decl = 8; - - optional MessageOptions options = 7; - - // Range of reserved tag numbers. Reserved tag numbers may not be used by - // fields or extension ranges in the same message. Reserved ranges may - // not overlap. - message ReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - } - repeated ReservedRange reserved_range = 9; - // Reserved field names, which may not be used by fields in the same message. - // A given name may only be reserved once. - repeated string reserved_name = 10; -} - -message ExtensionRangeOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// Describes a field within a message. -message FieldDescriptorProto { - enum Type { - // 0 is reserved for errors. - // Order is weird for historical reasons. - TYPE_DOUBLE = 1; - TYPE_FLOAT = 2; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - // negative values are likely. - TYPE_INT64 = 3; - TYPE_UINT64 = 4; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - // negative values are likely. - TYPE_INT32 = 5; - TYPE_FIXED64 = 6; - TYPE_FIXED32 = 7; - TYPE_BOOL = 8; - TYPE_STRING = 9; - // Tag-delimited aggregate. - // Group type is deprecated and not supported in proto3. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. - TYPE_GROUP = 10; - TYPE_MESSAGE = 11; // Length-delimited aggregate. - - // New in version 2. - TYPE_BYTES = 12; - TYPE_UINT32 = 13; - TYPE_ENUM = 14; - TYPE_SFIXED32 = 15; - TYPE_SFIXED64 = 16; - TYPE_SINT32 = 17; // Uses ZigZag encoding. - TYPE_SINT64 = 18; // Uses ZigZag encoding. - } - - enum Label { - // 0 is reserved for errors - LABEL_OPTIONAL = 1; - LABEL_REQUIRED = 2; - LABEL_REPEATED = 3; - } - - optional string name = 1; - optional int32 number = 3; - optional Label label = 4; - - // If type_name is set, this need not be set. If both this and type_name - // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - optional Type type = 5; - - // For message and enum types, this is the name of the type. If the name - // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - // rules are used to find the type (i.e. first the nested types within this - // message are searched, then within the parent, on up to the root - // namespace). - optional string type_name = 6; - - // For extensions, this is the name of the type being extended. It is - // resolved in the same manner as type_name. - optional string extendee = 2; - - // For numeric types, contains the original text representation of the value. - // For booleans, "true" or "false". - // For strings, contains the default text contents (not escaped in any way). - // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - optional string default_value = 7; - - // If set, gives the index of a oneof in the containing type's oneof_decl - // list. This field is a member of that oneof. - optional int32 oneof_index = 9; - - // JSON name of this field. The value is set by protocol compiler. If the - // user has set a "json_name" option on this field, that option's value - // will be used. Otherwise, it's deduced from the field's name by converting - // it to camelCase. - optional string json_name = 10; - - optional FieldOptions options = 8; - - // If true, this is a proto3 "optional". When a proto3 field is optional, it - // tracks presence regardless of field type. - // - // When proto3_optional is true, this field must be belong to a oneof to - // signal to old proto3 clients that presence is tracked for this field. This - // oneof is known as a "synthetic" oneof, and this field must be its sole - // member (each proto3 optional field gets its own synthetic oneof). Synthetic - // oneofs exist in the descriptor only, and do not generate any API. Synthetic - // oneofs must be ordered after all "real" oneofs. - // - // For message fields, proto3_optional doesn't create any semantic change, - // since non-repeated message fields always track presence. However it still - // indicates the semantic detail of whether the user wrote "optional" or not. - // This can be useful for round-tripping the .proto file. For consistency we - // give message fields a synthetic oneof also, even though it is not required - // to track presence. This is especially important because the parser can't - // tell if a field is a message or an enum, so it must always create a - // synthetic oneof. - // - // Proto2 optional fields do not set this flag, because they already indicate - // optional with `LABEL_OPTIONAL`. - optional bool proto3_optional = 17; -} - -// Describes a oneof. -message OneofDescriptorProto { - optional string name = 1; - optional OneofOptions options = 2; -} - -// Describes an enum type. -message EnumDescriptorProto { - optional string name = 1; - - repeated EnumValueDescriptorProto value = 2; - - optional EnumOptions options = 3; - - // Range of reserved numeric values. Reserved values may not be used by - // entries in the same enum. Reserved ranges may not overlap. - // - // Note that this is distinct from DescriptorProto.ReservedRange in that it - // is inclusive such that it can appropriately represent the entire int32 - // domain. - message EnumReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Inclusive. - } - - // Range of reserved numeric values. Reserved numeric values may not be used - // by enum values in the same enum declaration. Reserved ranges may not - // overlap. - repeated EnumReservedRange reserved_range = 4; - - // Reserved enum value names, which may not be reused. A given name may only - // be reserved once. - repeated string reserved_name = 5; -} - -// Describes a value within an enum. -message EnumValueDescriptorProto { - optional string name = 1; - optional int32 number = 2; - - optional EnumValueOptions options = 3; -} - -// Describes a service. -message ServiceDescriptorProto { - optional string name = 1; - repeated MethodDescriptorProto method = 2; - - optional ServiceOptions options = 3; -} - -// Describes a method of a service. -message MethodDescriptorProto { - optional string name = 1; - - // Input and output type names. These are resolved in the same way as - // FieldDescriptorProto.type_name, but must refer to a message type. - optional string input_type = 2; - optional string output_type = 3; - - optional MethodOptions options = 4; - - // Identifies if client streams multiple client messages - optional bool client_streaming = 5 [default = false]; - // Identifies if server streams multiple server messages - optional bool server_streaming = 6 [default = false]; -} - -// =================================================================== -// Options - -// Each of the definitions above may have "options" attached. These are -// just annotations which may cause code to be generated slightly differently -// or may contain hints for code that manipulates protocol messages. -// -// Clients may define custom options as extensions of the *Options messages. -// These extensions may not yet be known at parsing time, so the parser cannot -// store the values in them. Instead it stores them in a field in the *Options -// message called uninterpreted_option. This field must have the same name -// across all *Options messages. We then use this field to populate the -// extensions when we build a descriptor, at which point all protos have been -// parsed and so all extensions are known. -// -// Extension numbers for custom options may be chosen as follows: -// * For options which will only be used within a single application or -// organization, or for experimental options, use field numbers 50000 -// through 99999. It is up to you to ensure that you do not use the -// same number for multiple options. -// * For options which will be published and used publicly by multiple -// independent entities, e-mail protobuf-global-extension-registry@google.com -// to reserve extension numbers. Simply provide your project name (e.g. -// Objective-C plugin) and your project website (if available) -- there's no -// need to explain how you intend to use them. Usually you only need one -// extension number. You can declare multiple options with only one extension -// number by putting them in a sub-message. See the Custom Options section of -// the docs for examples: -// https://developers.google.com/protocol-buffers/docs/proto#options -// If this turns out to be popular, a web service will be set up -// to automatically assign option numbers. - -message FileOptions { - - // Sets the Java package where classes generated from this .proto will be - // placed. By default, the proto package is used, but this is often - // inappropriate because proto packages do not normally start with backwards - // domain names. - optional string java_package = 1; - - // Controls the name of the wrapper Java class generated for the .proto file. - // That class will always contain the .proto file's getDescriptor() method as - // well as any top-level extensions defined in the .proto file. - // If java_multiple_files is disabled, then all the other classes from the - // .proto file will be nested inside the single wrapper outer class. - optional string java_outer_classname = 8; - - // If enabled, then the Java code generator will generate a separate .java - // file for each top-level message, enum, and service defined in the .proto - // file. Thus, these types will *not* be nested inside the wrapper class - // named by java_outer_classname. However, the wrapper class will still be - // generated to contain the file's getDescriptor() method as well as any - // top-level extensions defined in the file. - optional bool java_multiple_files = 10 [default = false]; - - // This option does nothing. - optional bool java_generate_equals_and_hash = 20 [deprecated = true]; - - // If set true, then the Java2 code generator will generate code that - // throws an exception whenever an attempt is made to assign a non-UTF-8 - // byte sequence to a string field. - // Message reflection will do the same. - // However, an extension field still accepts non-UTF-8 byte sequences. - // This option has no effect on when used with the lite runtime. - optional bool java_string_check_utf8 = 27 [default = false]; - - // Generated classes can be optimized for speed or code size. - enum OptimizeMode { - SPEED = 1; // Generate complete code for parsing, serialization, - // etc. - CODE_SIZE = 2; // Use ReflectionOps to implement these methods. - LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. - } - optional OptimizeMode optimize_for = 9 [default = SPEED]; - - // Sets the Go package where structs generated from this .proto will be - // placed. If omitted, the Go package will be derived from the following: - // - The basename of the package import path, if provided. - // - Otherwise, the package statement in the .proto file, if present. - // - Otherwise, the basename of the .proto file, without extension. - optional string go_package = 11; - - // Should generic services be generated in each language? "Generic" services - // are not specific to any particular RPC system. They are generated by the - // main code generators in each language (without additional plugins). - // Generic services were the only kind of service generation supported by - // early versions of google.protobuf. - // - // Generic services are now considered deprecated in favor of using plugins - // that generate code specific to your particular RPC system. Therefore, - // these default to false. Old code which depends on generic services should - // explicitly set them to true. - optional bool cc_generic_services = 16 [default = false]; - optional bool java_generic_services = 17 [default = false]; - optional bool py_generic_services = 18 [default = false]; - optional bool php_generic_services = 42 [default = false]; - - // Is this file deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for everything in the file, or it will be completely ignored; in the very - // least, this is a formalization for deprecating files. - optional bool deprecated = 23 [default = false]; - - // Enables the use of arenas for the proto messages in this file. This applies - // only to generated classes for C++. - optional bool cc_enable_arenas = 31 [default = true]; - - // Sets the objective c class prefix which is prepended to all objective c - // generated classes from this .proto. There is no default. - optional string objc_class_prefix = 36; - - // Namespace for generated classes; defaults to the package. - optional string csharp_namespace = 37; - - // By default Swift generators will take the proto package and CamelCase it - // replacing '.' with underscore and use that to prefix the types/symbols - // defined. When this options is provided, they will use this value instead - // to prefix the types/symbols defined. - optional string swift_prefix = 39; - - // Sets the php class prefix which is prepended to all php generated classes - // from this .proto. Default is empty. - optional string php_class_prefix = 40; - - // Use this option to change the namespace of php generated classes. Default - // is empty. When this option is empty, the package name will be used for - // determining the namespace. - optional string php_namespace = 41; - - // Use this option to change the namespace of php generated metadata classes. - // Default is empty. When this option is empty, the proto file name will be - // used for determining the namespace. - optional string php_metadata_namespace = 44; - - // Use this option to change the package of ruby generated classes. Default - // is empty. When this option is not set, the package name will be used for - // determining the ruby package. - optional string ruby_package = 45; - - // The parser stores options it doesn't recognize here. - // See the documentation for the "Options" section above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. - // See the documentation for the "Options" section above. - extensions 1000 to max; - - reserved 38; -} - -message MessageOptions { - // Set true to use the old proto1 MessageSet wire format for extensions. - // This is provided for backwards-compatibility with the MessageSet wire - // format. You should not use this for any other reason: It's less - // efficient, has fewer features, and is more complicated. - // - // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } - // Note that the message cannot have any defined fields; MessageSets only - // have extensions. - // - // All extensions of your type must be singular messages; e.g. they cannot - // be int32s, enums, or repeated messages. - // - // Because this is an option, the above two restrictions are not enforced by - // the protocol compiler. - optional bool message_set_wire_format = 1 [default = false]; - - // Disables the generation of the standard "descriptor()" accessor, which can - // conflict with a field of the same name. This is meant to make migration - // from proto1 easier; new code should avoid fields named "descriptor". - optional bool no_standard_descriptor_accessor = 2 [default = false]; - - // Is this message deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the message, or it will be completely ignored; in the very least, - // this is a formalization for deprecating messages. - optional bool deprecated = 3 [default = false]; - - reserved 4, 5, 6; - - // NOTE: Do not set the option in .proto files. Always use the maps syntax - // instead. The option should only be implicitly set by the proto compiler - // parser. - // - // Whether the message is an automatically generated map entry type for the - // maps field. - // - // For maps fields: - // map map_field = 1; - // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; - // - // Implementations may choose not to generate the map_entry=true message, but - // use a native map in the target language to hold the keys and values. - // The reflection APIs in such implementations still need to work as - // if the field is a repeated message field. - optional bool map_entry = 7; - - reserved 8; // javalite_serializable - reserved 9; // javanano_as_lite - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message FieldOptions { - // The ctype option instructs the C++ code generator to use a different - // representation of the field than it normally would. See the specific - // options below. This option is not yet implemented in the open source - // release -- sorry, we'll try to include it in a future version! - optional CType ctype = 1 [default = STRING]; - enum CType { - // Default mode. - STRING = 0; - - CORD = 1; - - STRING_PIECE = 2; - } - // The packed option can be enabled for repeated primitive fields to enable - // a more efficient representation on the wire. Rather than repeatedly - // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. - optional bool packed = 2; - - // The jstype option determines the JavaScript type used for values of the - // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - // is represented as JavaScript string, which avoids loss of precision that - // can happen when a large value is converted to a floating point JavaScript. - // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - // use the JavaScript "number" type. The behavior of the default option - // JS_NORMAL is implementation dependent. - // - // This option is an enum to permit additional types to be added, e.g. - // goog.math.Integer. - optional JSType jstype = 6 [default = JS_NORMAL]; - enum JSType { - // Use the default type. - JS_NORMAL = 0; - - // Use JavaScript strings. - JS_STRING = 1; - - // Use JavaScript numbers. - JS_NUMBER = 2; - } - - // Should this field be parsed lazily? Lazy applies only to message-type - // fields. It means that when the outer message is initially parsed, the - // inner message's contents will not be parsed but instead stored in encoded - // form. The inner message will actually be parsed when it is first accessed. - // - // This is only a hint. Implementations are free to choose whether to use - // eager or lazy parsing regardless of the value of this option. However, - // setting this option true suggests that the protocol author believes that - // using lazy parsing on this field is worth the additional bookkeeping - // overhead typically needed to implement it. - // - // This option does not affect the public interface of any generated code; - // all method signatures remain the same. Furthermore, thread-safety of the - // interface is not affected by this option; const methods remain safe to - // call from multiple threads concurrently, while non-const methods continue - // to require exclusive access. - // - // Note that implementations may choose not to check required fields within - // a lazy sub-message. That is, calling IsInitialized() on the outer message - // may return true even if the inner message has missing required fields. - // This is necessary because otherwise the inner message would have to be - // parsed in order to perform the check, defeating the purpose of lazy - // parsing. An implementation which chooses not to check required fields - // must be consistent about it. That is, for any particular sub-message, the - // implementation must either *always* check its required fields, or *never* - // check its required fields, regardless of whether or not the message has - // been parsed. - // - // As of May 2022, lazy verifies the contents of the byte stream during - // parsing. An invalid byte stream will cause the overall parsing to fail. - optional bool lazy = 5 [default = false]; - - // unverified_lazy does no correctness checks on the byte stream. This should - // only be used where lazy with verification is prohibitive for performance - // reasons. - optional bool unverified_lazy = 15 [default = false]; - - // Is this field deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for accessors, or it will be completely ignored; in the very least, this - // is a formalization for deprecating fields. - optional bool deprecated = 3 [default = false]; - - // For Google-internal migration only. Do not use. - optional bool weak = 10 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; - - reserved 4; // removed jtype -} - -message OneofOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumOptions { - - // Set this option to true to allow mapping different tag names to the same - // value. - optional bool allow_alias = 2; - - // Is this enum deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum, or it will be completely ignored; in the very least, this - // is a formalization for deprecating enums. - optional bool deprecated = 3 [default = false]; - - reserved 5; // javanano_as_lite - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumValueOptions { - // Is this enum value deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum value, or it will be completely ignored; in the very least, - // this is a formalization for deprecating enum values. - optional bool deprecated = 1 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message ServiceOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this service deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the service, or it will be completely ignored; in the very least, - // this is a formalization for deprecating services. - optional bool deprecated = 33 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message MethodOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this method deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the method, or it will be completely ignored; in the very least, - // this is a formalization for deprecating methods. - optional bool deprecated = 33 [default = false]; - - // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - // or neither? HTTP based RPC implementation may choose GET verb for safe - // methods, and PUT verb for idempotent methods instead of the default POST. - enum IdempotencyLevel { - IDEMPOTENCY_UNKNOWN = 0; - NO_SIDE_EFFECTS = 1; // implies idempotent - IDEMPOTENT = 2; // idempotent, but may have side effects - } - optional IdempotencyLevel idempotency_level = 34 - [default = IDEMPOTENCY_UNKNOWN]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// A message representing a option the parser does not recognize. This only -// appears in options protos created by the compiler::Parser class. -// DescriptorPool resolves these when building Descriptor objects. Therefore, -// options protos in descriptor objects (e.g. returned by Descriptor::options(), -// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -// in them. -message UninterpretedOption { - // The name of the uninterpreted option. Each string represents a segment in - // a dot-separated name. is_extension is true iff a segment represents an - // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents - // "foo.(bar.baz).moo". - message NamePart { - required string name_part = 1; - required bool is_extension = 2; - } - repeated NamePart name = 2; - - // The value of the uninterpreted option, in whatever type the tokenizer - // identified it as during parsing. Exactly one of these should be set. - optional string identifier_value = 3; - optional uint64 positive_int_value = 4; - optional int64 negative_int_value = 5; - optional double double_value = 6; - optional bytes string_value = 7; - optional string aggregate_value = 8; -} - -// =================================================================== -// Optional source code info - -// Encapsulates information about the original source file from which a -// FileDescriptorProto was generated. -message SourceCodeInfo { - // A Location identifies a piece of source code in a .proto file which - // corresponds to a particular definition. This information is intended - // to be useful to IDEs, code indexers, documentation generators, and similar - // tools. - // - // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } - // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi - // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - // - // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendant. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. - repeated Location location = 1; - message Location { - // Identifies which part of the FileDescriptorProto was defined at this - // location. - // - // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition occurs. - // For example, this path: - // [ 4, 3, 2, 7, 1 ] - // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 - // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; - // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; - // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; - // - // Thus, the above path gives the location of a field name. If we removed - // the last element: - // [ 4, 3, 2, 7 ] - // this path refers to the whole field declaration (from the beginning - // of the label to the terminating semicolon). - repeated int32 path = 1 [packed = true]; - - // Always has exactly three or four elements: start line, start column, - // end line (optional, otherwise assumed same as start line), end column. - // These are packed into a single field for efficiency. Note that line - // and column numbers are zero-based -- typically you will want to add - // 1 to each before displaying to a user. - repeated int32 span = 2 [packed = true]; - - // If this SourceCodeInfo represents a complete declaration, these are any - // comments appearing before and after the declaration which appear to be - // attached to the declaration. - // - // A series of line comments appearing on consecutive lines, with no other - // tokens appearing on those lines, will be treated as a single comment. - // - // leading_detached_comments will keep paragraphs of comments that appear - // before (but not connected to) the current element. Each paragraph, - // separated by empty lines, will be one comment element in the repeated - // field. - // - // Only the comment content is provided; comment markers (e.g. //) are - // stripped out. For block comments, leading whitespace and an asterisk - // will be stripped from the beginning of each line other than the first. - // Newlines are included in the output. - // - // Examples: - // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; - // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. - // - // // Comment attached to moo. - // // - // // Another line attached to moo. - // optional double moo = 4; - // - // // Detached comment for corge. This is not leading or trailing comments - // // to moo or corge because there are blank lines separating it from - // // both. - // - // // Detached comment for corge paragraph 2. - // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; - // - // // ignored detached comments. - optional string leading_comments = 3; - optional string trailing_comments = 4; - repeated string leading_detached_comments = 6; - } -} - -// Describes the relationship between generated code and its original source -// file. A GeneratedCodeInfo message is associated with only one generated -// source file, but may contain references to different source .proto files. -message GeneratedCodeInfo { - // An Annotation connects some span of text in generated code to an element - // of its generating .proto file. - repeated Annotation annotation = 1; - message Annotation { - // Identifies the element in the original source .proto file. This field - // is formatted the same as SourceCodeInfo.Location.path. - repeated int32 path = 1 [packed = true]; - - // Identifies the filesystem path to the original source .proto. - optional string source_file = 2; - - // Identifies the starting offset in bytes in the generated code - // that relates to the identified object. - optional int32 begin = 3; - - // Identifies the ending offset in bytes in the generated code that - // relates to the identified object. The end offset should be one past - // the last relevant byte (so the length of the text = end - begin). - optional int32 end = 4; - - // Represents the identified object's effect on the element in the original - // .proto file. - enum Semantic { - // There is no effect or the effect is indescribable. - NONE = 0; - // The element is set or otherwise mutated. - SET = 1; - // An alias to the element is returned. - ALIAS = 2; - } - optional Semantic semantic = 5; - } -} diff --git a/src/struct_pb/conformance/google/protobuf/duration.proto b/src/struct_pb/conformance/google/protobuf/duration.proto deleted file mode 100644 index 41f40c222..000000000 --- a/src/struct_pb/conformance/google/protobuf/duration.proto +++ /dev/null @@ -1,115 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/durationpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DurationProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Duration represents a signed, fixed-length span of time represented -// as a count of seconds and fractions of seconds at nanosecond -// resolution. It is independent of any calendar and concepts like "day" -// or "month". It is related to Timestamp in that the difference between -// two Timestamp values is a Duration and it can be added or subtracted -// from a Timestamp. Range is approximately +-10,000 years. -// -// # Examples -// -// Example 1: Compute Duration from two Timestamps in pseudo code. -// -// Timestamp start = ...; -// Timestamp end = ...; -// Duration duration = ...; -// -// duration.seconds = end.seconds - start.seconds; -// duration.nanos = end.nanos - start.nanos; -// -// if (duration.seconds < 0 && duration.nanos > 0) { -// duration.seconds += 1; -// duration.nanos -= 1000000000; -// } else if (duration.seconds > 0 && duration.nanos < 0) { -// duration.seconds -= 1; -// duration.nanos += 1000000000; -// } -// -// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -// -// Timestamp start = ...; -// Duration duration = ...; -// Timestamp end = ...; -// -// end.seconds = start.seconds + duration.seconds; -// end.nanos = start.nanos + duration.nanos; -// -// if (end.nanos < 0) { -// end.seconds -= 1; -// end.nanos += 1000000000; -// } else if (end.nanos >= 1000000000) { -// end.seconds += 1; -// end.nanos -= 1000000000; -// } -// -// Example 3: Compute Duration from datetime.timedelta in Python. -// -// td = datetime.timedelta(days=3, minutes=10) -// duration = Duration() -// duration.FromTimedelta(td) -// -// # JSON Mapping -// -// In JSON format, the Duration type is encoded as a string rather than an -// object, where the string ends in the suffix "s" (indicating seconds) and -// is preceded by the number of seconds, with nanoseconds expressed as -// fractional seconds. For example, 3 seconds with 0 nanoseconds should be -// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should -// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 -// microsecond should be expressed in JSON format as "3.000001s". -// -message Duration { - // Signed seconds of the span of time. Must be from -315,576,000,000 - // to +315,576,000,000 inclusive. Note: these bounds are computed from: - // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - int64 seconds = 1; - - // Signed fractions of a second at nanosecond resolution of the span - // of time. Durations less than one second are represented with a 0 - // `seconds` field and a positive or negative `nanos` field. For durations - // of one second or more, a non-zero value for the `nanos` field must be - // of the same sign as the `seconds` field. Must be from -999,999,999 - // to +999,999,999 inclusive. - int32 nanos = 2; -} diff --git a/src/struct_pb/conformance/google/protobuf/field_mask.proto b/src/struct_pb/conformance/google/protobuf/field_mask.proto deleted file mode 100644 index b28334b94..000000000 --- a/src/struct_pb/conformance/google/protobuf/field_mask.proto +++ /dev/null @@ -1,245 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "FieldMaskProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; -option cc_enable_arenas = true; - -// `FieldMask` represents a set of symbolic field paths, for example: -// -// paths: "f.a" -// paths: "f.b.d" -// -// Here `f` represents a field in some root message, `a` and `b` -// fields in the message found in `f`, and `d` a field found in the -// message in `f.b`. -// -// Field masks are used to specify a subset of fields that should be -// returned by a get operation or modified by an update operation. -// Field masks also have a custom JSON encoding (see below). -// -// # Field Masks in Projections -// -// When used in the context of a projection, a response message or -// sub-message is filtered by the API to only contain those fields as -// specified in the mask. For example, if the mask in the previous -// example is applied to a response message as follows: -// -// f { -// a : 22 -// b { -// d : 1 -// x : 2 -// } -// y : 13 -// } -// z: 8 -// -// The result will not contain specific values for fields x,y and z -// (their value will be set to the default, and omitted in proto text -// output): -// -// -// f { -// a : 22 -// b { -// d : 1 -// } -// } -// -// A repeated field is not allowed except at the last position of a -// paths string. -// -// If a FieldMask object is not present in a get operation, the -// operation applies to all fields (as if a FieldMask of all fields -// had been specified). -// -// Note that a field mask does not necessarily apply to the -// top-level response message. In case of a REST get operation, the -// field mask applies directly to the response, but in case of a REST -// list operation, the mask instead applies to each individual message -// in the returned resource list. In case of a REST custom method, -// other definitions may be used. Where the mask applies will be -// clearly documented together with its declaration in the API. In -// any case, the effect on the returned resource/resources is required -// behavior for APIs. -// -// # Field Masks in Update Operations -// -// A field mask in update operations specifies which fields of the -// targeted resource are going to be updated. The API is required -// to only change the values of the fields as specified in the mask -// and leave the others untouched. If a resource is passed in to -// describe the updated values, the API ignores the values of all -// fields not covered by the mask. -// -// If a repeated field is specified for an update operation, new values will -// be appended to the existing repeated field in the target resource. Note that -// a repeated field is only allowed in the last position of a `paths` string. -// -// If a sub-message is specified in the last position of the field mask for an -// update operation, then new value will be merged into the existing sub-message -// in the target resource. -// -// For example, given the target message: -// -// f { -// b { -// d: 1 -// x: 2 -// } -// c: [1] -// } -// -// And an update message: -// -// f { -// b { -// d: 10 -// } -// c: [2] -// } -// -// then if the field mask is: -// -// paths: ["f.b", "f.c"] -// -// then the result will be: -// -// f { -// b { -// d: 10 -// x: 2 -// } -// c: [1, 2] -// } -// -// An implementation may provide options to override this default behavior for -// repeated and message fields. -// -// In order to reset a field's value to the default, the field must -// be in the mask and set to the default value in the provided resource. -// Hence, in order to reset all fields of a resource, provide a default -// instance of the resource and set all fields in the mask, or do -// not provide a mask as described below. -// -// If a field mask is not present on update, the operation applies to -// all fields (as if a field mask of all fields has been specified). -// Note that in the presence of schema evolution, this may mean that -// fields the client does not know and has therefore not filled into -// the request will be reset to their default. If this is unwanted -// behavior, a specific service may require a client to always specify -// a field mask, producing an error if not. -// -// As with get operations, the location of the resource which -// describes the updated values in the request message depends on the -// operation kind. In any case, the effect of the field mask is -// required to be honored by the API. -// -// ## Considerations for HTTP REST -// -// The HTTP kind of an update operation which uses a field mask must -// be set to PATCH instead of PUT in order to satisfy HTTP semantics -// (PUT must only be used for full updates). -// -// # JSON Encoding of Field Masks -// -// In JSON, a field mask is encoded as a single string where paths are -// separated by a comma. Fields name in each path are converted -// to/from lower-camel naming conventions. -// -// As an example, consider the following message declarations: -// -// message Profile { -// User user = 1; -// Photo photo = 2; -// } -// message User { -// string display_name = 1; -// string address = 2; -// } -// -// In proto a field mask for `Profile` may look as such: -// -// mask { -// paths: "user.display_name" -// paths: "photo" -// } -// -// In JSON, the same mask is represented as below: -// -// { -// mask: "user.displayName,photo" -// } -// -// # Field Masks and Oneof Fields -// -// Field masks treat fields in oneofs just as regular fields. Consider the -// following message: -// -// message SampleMessage { -// oneof test_oneof { -// string name = 4; -// SubMessage sub_message = 9; -// } -// } -// -// The field mask can be: -// -// mask { -// paths: "name" -// } -// -// Or: -// -// mask { -// paths: "sub_message" -// } -// -// Note that oneof type names ("test_oneof" in this case) cannot be used in -// paths. -// -// ## Field Mask Verification -// -// The implementation of any API method which has a FieldMask type field in the -// request should verify the included field paths, and return an -// `INVALID_ARGUMENT` error if any path is unmappable. -message FieldMask { - // The set of field mask paths. - repeated string paths = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/source_context.proto b/src/struct_pb/conformance/google/protobuf/source_context.proto deleted file mode 100644 index 135f50fea..000000000 --- a/src/struct_pb/conformance/google/protobuf/source_context.proto +++ /dev/null @@ -1,48 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "SourceContextProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; - -// `SourceContext` represents information about the source of a -// protobuf element, like the file in which it is defined. -message SourceContext { - // The path-qualified name of the .proto file that contained the associated - // protobuf element. For example: `"google/protobuf/source_context.proto"`. - string file_name = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/struct.proto b/src/struct_pb/conformance/google/protobuf/struct.proto deleted file mode 100644 index c4ea6453e..000000000 --- a/src/struct_pb/conformance/google/protobuf/struct.proto +++ /dev/null @@ -1,95 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/structpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "StructProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Struct` represents a structured data value, consisting of fields -// which map to dynamically typed values. In some languages, `Struct` -// might be supported by a native representation. For example, in -// scripting languages like JS a struct is represented as an -// object. The details of that representation are described together -// with the proto support for the language. -// -// The JSON representation for `Struct` is JSON object. -message Struct { - // Unordered map of dynamically typed values. - map fields = 1; -} - -// `Value` represents a dynamically typed value which can be either -// null, a number, a string, a boolean, a recursive struct value, or a -// list of values. A producer of value is expected to set one of these -// variants. Absence of any variant indicates an error. -// -// The JSON representation for `Value` is JSON value. -message Value { - // The kind of value. - oneof kind { - // Represents a null value. - NullValue null_value = 1; - // Represents a double value. - double number_value = 2; - // Represents a string value. - string string_value = 3; - // Represents a boolean value. - bool bool_value = 4; - // Represents a structured value. - Struct struct_value = 5; - // Represents a repeated `Value`. - ListValue list_value = 6; - } -} - -// `NullValue` is a singleton enumeration to represent the null value for the -// `Value` type union. -// -// The JSON representation for `NullValue` is JSON `null`. -enum NullValue { - // Null value. - NULL_VALUE = 0; -} - -// `ListValue` is a wrapper around a repeated field of values. -// -// The JSON representation for `ListValue` is JSON array. -message ListValue { - // Repeated field of dynamically typed values. - repeated Value values = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto b/src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto deleted file mode 100644 index bd0324eb7..000000000 --- a/src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto +++ /dev/null @@ -1,303 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Test schema for proto2 messages. This test schema is used by: -// -// - conformance tests -// - -// LINT: ALLOW_GROUPS - -syntax = "proto2"; - -package protobuf_test_messages.proto2; - -option java_package = "com.google.protobuf_test_messages.proto2"; -option objc_class_prefix = "Proto2"; - -// This is the default, but we specify it here explicitly. -option optimize_for = SPEED; - -option cc_enable_arenas = true; - -// This proto includes every type of field in both singular and repeated -// forms. -// -// Also, crucially, all messages and enums in this file are eventually -// submessages of this message. So for example, a fuzz test of TestAllTypes -// could trigger bugs that occur in any message type in this file. We verify -// this stays true in a unit test. -message TestAllTypesProto2 { - message NestedMessage { - optional int32 a = 1; - optional TestAllTypesProto2 corecursive = 2; - } - - enum NestedEnum { - FOO = 0; - BAR = 1; - BAZ = 2; - NEG = -1; // Intentionally negative. - } - - // Singular - optional int32 optional_int32 = 1; - optional int64 optional_int64 = 2; - optional uint32 optional_uint32 = 3; - optional uint64 optional_uint64 = 4; - optional sint32 optional_sint32 = 5; - optional sint64 optional_sint64 = 6; - optional fixed32 optional_fixed32 = 7; - optional fixed64 optional_fixed64 = 8; - optional sfixed32 optional_sfixed32 = 9; - optional sfixed64 optional_sfixed64 = 10; - optional float optional_float = 11; - optional double optional_double = 12; - optional bool optional_bool = 13; - optional string optional_string = 14; - optional bytes optional_bytes = 15; - - optional NestedMessage optional_nested_message = 18; - optional ForeignMessageProto2 optional_foreign_message = 19; - - optional NestedEnum optional_nested_enum = 21; - optional ForeignEnumProto2 optional_foreign_enum = 22; - - optional string optional_string_piece = 24 [ctype = STRING_PIECE]; - optional string optional_cord = 25 [ctype = CORD]; - - optional TestAllTypesProto2 recursive_message = 27; - - // Repeated - repeated int32 repeated_int32 = 31; - repeated int64 repeated_int64 = 32; - repeated uint32 repeated_uint32 = 33; - repeated uint64 repeated_uint64 = 34; - repeated sint32 repeated_sint32 = 35; - repeated sint64 repeated_sint64 = 36; - repeated fixed32 repeated_fixed32 = 37; - repeated fixed64 repeated_fixed64 = 38; - repeated sfixed32 repeated_sfixed32 = 39; - repeated sfixed64 repeated_sfixed64 = 40; - repeated float repeated_float = 41; - repeated double repeated_double = 42; - repeated bool repeated_bool = 43; - repeated string repeated_string = 44; - repeated bytes repeated_bytes = 45; - - repeated NestedMessage repeated_nested_message = 48; - repeated ForeignMessageProto2 repeated_foreign_message = 49; - - repeated NestedEnum repeated_nested_enum = 51; - repeated ForeignEnumProto2 repeated_foreign_enum = 52; - - repeated string repeated_string_piece = 54 [ctype = STRING_PIECE]; - repeated string repeated_cord = 55 [ctype = CORD]; - - // Packed - repeated int32 packed_int32 = 75 [packed = true]; - repeated int64 packed_int64 = 76 [packed = true]; - repeated uint32 packed_uint32 = 77 [packed = true]; - repeated uint64 packed_uint64 = 78 [packed = true]; - repeated sint32 packed_sint32 = 79 [packed = true]; - repeated sint64 packed_sint64 = 80 [packed = true]; - repeated fixed32 packed_fixed32 = 81 [packed = true]; - repeated fixed64 packed_fixed64 = 82 [packed = true]; - repeated sfixed32 packed_sfixed32 = 83 [packed = true]; - repeated sfixed64 packed_sfixed64 = 84 [packed = true]; - repeated float packed_float = 85 [packed = true]; - repeated double packed_double = 86 [packed = true]; - repeated bool packed_bool = 87 [packed = true]; - repeated NestedEnum packed_nested_enum = 88 [packed = true]; - - // Unpacked - repeated int32 unpacked_int32 = 89 [packed = false]; - repeated int64 unpacked_int64 = 90 [packed = false]; - repeated uint32 unpacked_uint32 = 91 [packed = false]; - repeated uint64 unpacked_uint64 = 92 [packed = false]; - repeated sint32 unpacked_sint32 = 93 [packed = false]; - repeated sint64 unpacked_sint64 = 94 [packed = false]; - repeated fixed32 unpacked_fixed32 = 95 [packed = false]; - repeated fixed64 unpacked_fixed64 = 96 [packed = false]; - repeated sfixed32 unpacked_sfixed32 = 97 [packed = false]; - repeated sfixed64 unpacked_sfixed64 = 98 [packed = false]; - repeated float unpacked_float = 99 [packed = false]; - repeated double unpacked_double = 100 [packed = false]; - repeated bool unpacked_bool = 101 [packed = false]; - repeated NestedEnum unpacked_nested_enum = 102 [packed = false]; - - // Map - map map_int32_int32 = 56; - map map_int64_int64 = 57; - map map_uint32_uint32 = 58; - map map_uint64_uint64 = 59; - map map_sint32_sint32 = 60; - map map_sint64_sint64 = 61; - map map_fixed32_fixed32 = 62; - map map_fixed64_fixed64 = 63; - map map_sfixed32_sfixed32 = 64; - map map_sfixed64_sfixed64 = 65; - map map_int32_float = 66; - map map_int32_double = 67; - map map_bool_bool = 68; - map map_string_string = 69; - map map_string_bytes = 70; - map map_string_nested_message = 71; - map map_string_foreign_message = 72; - map map_string_nested_enum = 73; - map map_string_foreign_enum = 74; - - oneof oneof_field { - uint32 oneof_uint32 = 111; - NestedMessage oneof_nested_message = 112; - string oneof_string = 113; - bytes oneof_bytes = 114; - bool oneof_bool = 115; - uint64 oneof_uint64 = 116; - float oneof_float = 117; - double oneof_double = 118; - NestedEnum oneof_enum = 119; - } - - // extensions - extensions 120 to 200; - - // groups - optional group Data = 201 { - optional int32 group_int32 = 202; - optional uint32 group_uint32 = 203; - } - - // default values - optional int32 default_int32 = 241 [default = -123456789]; - optional int64 default_int64 = 242 [default = -9123456789123456789]; - optional uint32 default_uint32 = 243 [default = 2123456789]; - optional uint64 default_uint64 = 244 [default = 10123456789123456789]; - optional sint32 default_sint32 = 245 [default = -123456789]; - optional sint64 default_sint64 = 246 [default = -9123456789123456789]; - optional fixed32 default_fixed32 = 247 [default = 2123456789]; - optional fixed64 default_fixed64 = 248 [default = 10123456789123456789]; - optional sfixed32 default_sfixed32 = 249 [default = -123456789]; - optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789]; - optional float default_float = 251 [default = 9e9]; - optional double default_double = 252 [default = 7e22]; - optional bool default_bool = 253 [default = true]; - optional string default_string = 254 [default = "Rosebud"]; - optional bytes default_bytes = 255 [default = "joshua"]; - - // Test field-name-to-JSON-name convention. - // (protobuf says names can be any valid C/C++ identifier.) - optional int32 fieldname1 = 401; - optional int32 field_name2 = 402; - optional int32 _field_name3 = 403; - optional int32 field__name4_ = 404; - optional int32 field0name5 = 405; - optional int32 field_0_name6 = 406; - optional int32 fieldName7 = 407; - optional int32 FieldName8 = 408; - optional int32 field_Name9 = 409; - optional int32 Field_Name10 = 410; - optional int32 FIELD_NAME11 = 411; - optional int32 FIELD_name12 = 412; - optional int32 __field_name13 = 413; - optional int32 __Field_name14 = 414; - optional int32 field__name15 = 415; - optional int32 field__Name16 = 416; - optional int32 field_name17__ = 417; - optional int32 Field_name18__ = 418; - - // Reserved for unknown fields test. - reserved 1000 to 9999; - - // message_set test case. - message MessageSetCorrect { - option message_set_wire_format = true; - - extensions 4 to max; - } - - message MessageSetCorrectExtension1 { - extend MessageSetCorrect { - optional MessageSetCorrectExtension1 message_set_extension = 1547769; - } - optional string str = 25; - } - - message MessageSetCorrectExtension2 { - extend MessageSetCorrect { - optional MessageSetCorrectExtension2 message_set_extension = 4135312; - } - optional int32 i = 9; - } -} - -message ForeignMessageProto2 { - optional int32 c = 1; -} - -enum ForeignEnumProto2 { - FOREIGN_FOO = 0; - FOREIGN_BAR = 1; - FOREIGN_BAZ = 2; -} - -extend TestAllTypesProto2 { - optional int32 extension_int32 = 120; -} - -message UnknownToTestAllTypes { - optional int32 optional_int32 = 1001; - optional string optional_string = 1002; - optional ForeignMessageProto2 nested_message = 1003; - optional group OptionalGroup = 1004 { - optional int32 a = 1; - } - optional bool optional_bool = 1006; - repeated int32 repeated_int32 = 1011; -} - -message NullHypothesisProto2 {} - -message EnumOnlyProto2 { - enum Bool { - kFalse = 0; - kTrue = 1; - } -} - -message OneStringProto2 { - optional string data = 1; -} - -message ProtoWithKeywords { - optional int32 inline = 1; - // optional string concept = 2; - // repeated string requires = 3; -} diff --git a/src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto b/src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto deleted file mode 100644 index 1e1285eab..000000000 --- a/src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto +++ /dev/null @@ -1,288 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Test schema for proto3 messages. This test schema is used by: -// -// - benchmarks -// - fuzz tests -// - conformance tests -// - -syntax = "proto3"; - -package protobuf_test_messages.proto3; - -option java_package = "com.google.protobuf_test_messages.proto3"; -option objc_class_prefix = "Proto3"; - -// This is the default, but we specify it here explicitly. -option optimize_for = SPEED; - -import "google/protobuf/any.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/field_mask.proto"; -import "google/protobuf/struct.proto"; -import "google/protobuf/timestamp.proto"; -import "google/protobuf/wrappers.proto"; - -option cc_enable_arenas = true; - -// This proto includes every type of field in both singular and repeated -// forms. -// -// Also, crucially, all messages and enums in this file are eventually -// submessages of this message. So for example, a fuzz test of TestAllTypes -// could trigger bugs that occur in any message type in this file. We verify -// this stays true in a unit test. -message TestAllTypesProto3 { - message NestedMessage { - int32 a = 1; - TestAllTypesProto3 corecursive = 2; - } - - enum NestedEnum { - FOO = 0; - BAR = 1; - BAZ = 2; - NEG = -1; // Intentionally negative. - } - - enum AliasedEnum { - option allow_alias = true; - - ALIAS_FOO = 0; - ALIAS_BAR = 1; - ALIAS_BAZ = 2; - MOO = 2; - moo = 2; - bAz = 2; - } - - // Singular - int32 optional_int32 = 1; - int64 optional_int64 = 2; - uint32 optional_uint32 = 3; - uint64 optional_uint64 = 4; - sint32 optional_sint32 = 5; - sint64 optional_sint64 = 6; - fixed32 optional_fixed32 = 7; - fixed64 optional_fixed64 = 8; - sfixed32 optional_sfixed32 = 9; - sfixed64 optional_sfixed64 = 10; - float optional_float = 11; - double optional_double = 12; - bool optional_bool = 13; - string optional_string = 14; - bytes optional_bytes = 15; - - NestedMessage optional_nested_message = 18; - ForeignMessage optional_foreign_message = 19; - - NestedEnum optional_nested_enum = 21; - ForeignEnum optional_foreign_enum = 22; - AliasedEnum optional_aliased_enum = 23; - - string optional_string_piece = 24 [ctype = STRING_PIECE]; - string optional_cord = 25 [ctype = CORD]; - - TestAllTypesProto3 recursive_message = 27; - - // Repeated - repeated int32 repeated_int32 = 31; - repeated int64 repeated_int64 = 32; - repeated uint32 repeated_uint32 = 33; - repeated uint64 repeated_uint64 = 34; - repeated sint32 repeated_sint32 = 35; - repeated sint64 repeated_sint64 = 36; - repeated fixed32 repeated_fixed32 = 37; - repeated fixed64 repeated_fixed64 = 38; - repeated sfixed32 repeated_sfixed32 = 39; - repeated sfixed64 repeated_sfixed64 = 40; - repeated float repeated_float = 41; - repeated double repeated_double = 42; - repeated bool repeated_bool = 43; - repeated string repeated_string = 44; - repeated bytes repeated_bytes = 45; - - repeated NestedMessage repeated_nested_message = 48; - repeated ForeignMessage repeated_foreign_message = 49; - - repeated NestedEnum repeated_nested_enum = 51; - repeated ForeignEnum repeated_foreign_enum = 52; - - repeated string repeated_string_piece = 54 [ctype = STRING_PIECE]; - repeated string repeated_cord = 55 [ctype = CORD]; - - // Packed - repeated int32 packed_int32 = 75 [packed = true]; - repeated int64 packed_int64 = 76 [packed = true]; - repeated uint32 packed_uint32 = 77 [packed = true]; - repeated uint64 packed_uint64 = 78 [packed = true]; - repeated sint32 packed_sint32 = 79 [packed = true]; - repeated sint64 packed_sint64 = 80 [packed = true]; - repeated fixed32 packed_fixed32 = 81 [packed = true]; - repeated fixed64 packed_fixed64 = 82 [packed = true]; - repeated sfixed32 packed_sfixed32 = 83 [packed = true]; - repeated sfixed64 packed_sfixed64 = 84 [packed = true]; - repeated float packed_float = 85 [packed = true]; - repeated double packed_double = 86 [packed = true]; - repeated bool packed_bool = 87 [packed = true]; - repeated NestedEnum packed_nested_enum = 88 [packed = true]; - - // Unpacked - repeated int32 unpacked_int32 = 89 [packed = false]; - repeated int64 unpacked_int64 = 90 [packed = false]; - repeated uint32 unpacked_uint32 = 91 [packed = false]; - repeated uint64 unpacked_uint64 = 92 [packed = false]; - repeated sint32 unpacked_sint32 = 93 [packed = false]; - repeated sint64 unpacked_sint64 = 94 [packed = false]; - repeated fixed32 unpacked_fixed32 = 95 [packed = false]; - repeated fixed64 unpacked_fixed64 = 96 [packed = false]; - repeated sfixed32 unpacked_sfixed32 = 97 [packed = false]; - repeated sfixed64 unpacked_sfixed64 = 98 [packed = false]; - repeated float unpacked_float = 99 [packed = false]; - repeated double unpacked_double = 100 [packed = false]; - repeated bool unpacked_bool = 101 [packed = false]; - repeated NestedEnum unpacked_nested_enum = 102 [packed = false]; - - // Map - map map_int32_int32 = 56; - map map_int64_int64 = 57; - map map_uint32_uint32 = 58; - map map_uint64_uint64 = 59; - map map_sint32_sint32 = 60; - map map_sint64_sint64 = 61; - map map_fixed32_fixed32 = 62; - map map_fixed64_fixed64 = 63; - map map_sfixed32_sfixed32 = 64; - map map_sfixed64_sfixed64 = 65; - map map_int32_float = 66; - map map_int32_double = 67; - map map_bool_bool = 68; - map map_string_string = 69; - map map_string_bytes = 70; - map map_string_nested_message = 71; - map map_string_foreign_message = 72; - map map_string_nested_enum = 73; - map map_string_foreign_enum = 74; - - oneof oneof_field { - uint32 oneof_uint32 = 111; - NestedMessage oneof_nested_message = 112; - string oneof_string = 113; - bytes oneof_bytes = 114; - bool oneof_bool = 115; - uint64 oneof_uint64 = 116; - float oneof_float = 117; - double oneof_double = 118; - NestedEnum oneof_enum = 119; - google.protobuf.NullValue oneof_null_value = 120; - } - - // Well-known types - google.protobuf.BoolValue optional_bool_wrapper = 201; - google.protobuf.Int32Value optional_int32_wrapper = 202; - google.protobuf.Int64Value optional_int64_wrapper = 203; - google.protobuf.UInt32Value optional_uint32_wrapper = 204; - google.protobuf.UInt64Value optional_uint64_wrapper = 205; - google.protobuf.FloatValue optional_float_wrapper = 206; - google.protobuf.DoubleValue optional_double_wrapper = 207; - google.protobuf.StringValue optional_string_wrapper = 208; - google.protobuf.BytesValue optional_bytes_wrapper = 209; - - repeated google.protobuf.BoolValue repeated_bool_wrapper = 211; - repeated google.protobuf.Int32Value repeated_int32_wrapper = 212; - repeated google.protobuf.Int64Value repeated_int64_wrapper = 213; - repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 214; - repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 215; - repeated google.protobuf.FloatValue repeated_float_wrapper = 216; - repeated google.protobuf.DoubleValue repeated_double_wrapper = 217; - repeated google.protobuf.StringValue repeated_string_wrapper = 218; - repeated google.protobuf.BytesValue repeated_bytes_wrapper = 219; - - google.protobuf.Duration optional_duration = 301; - google.protobuf.Timestamp optional_timestamp = 302; - google.protobuf.FieldMask optional_field_mask = 303; - google.protobuf.Struct optional_struct = 304; - google.protobuf.Any optional_any = 305; - google.protobuf.Value optional_value = 306; - google.protobuf.NullValue optional_null_value = 307; - - repeated google.protobuf.Duration repeated_duration = 311; - repeated google.protobuf.Timestamp repeated_timestamp = 312; - repeated google.protobuf.FieldMask repeated_fieldmask = 313; - repeated google.protobuf.Struct repeated_struct = 324; - repeated google.protobuf.Any repeated_any = 315; - repeated google.protobuf.Value repeated_value = 316; - repeated google.protobuf.ListValue repeated_list_value = 317; - - // Test field-name-to-JSON-name convention. - // (protobuf says names can be any valid C/C++ identifier.) - int32 fieldname1 = 401; - int32 field_name2 = 402; - int32 _field_name3 = 403; - int32 field__name4_ = 404; - int32 field0name5 = 405; - int32 field_0_name6 = 406; - int32 fieldName7 = 407; - int32 FieldName8 = 408; - int32 field_Name9 = 409; - int32 Field_Name10 = 410; - int32 FIELD_NAME11 = 411; - int32 FIELD_name12 = 412; - int32 __field_name13 = 413; - int32 __Field_name14 = 414; - int32 field__name15 = 415; - int32 field__Name16 = 416; - int32 field_name17__ = 417; - int32 Field_name18__ = 418; - - // Reserved for testing unknown fields - reserved 501 to 510; -} - -message ForeignMessage { - int32 c = 1; -} - -enum ForeignEnum { - FOREIGN_FOO = 0; - FOREIGN_BAR = 1; - FOREIGN_BAZ = 2; -} - -message NullHypothesisProto3 {} - -message EnumOnlyProto3 { - enum Bool { - kFalse = 0; - kTrue = 1; - } -} diff --git a/src/struct_pb/conformance/google/protobuf/timestamp.proto b/src/struct_pb/conformance/google/protobuf/timestamp.proto deleted file mode 100644 index 2fb527c0c..000000000 --- a/src/struct_pb/conformance/google/protobuf/timestamp.proto +++ /dev/null @@ -1,144 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/timestamppb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TimestampProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Timestamp represents a point in time independent of any time zone or local -// calendar, encoded as a count of seconds and fractions of seconds at -// nanosecond resolution. The count is relative to an epoch at UTC midnight on -// January 1, 1970, in the proleptic Gregorian calendar which extends the -// Gregorian calendar backwards to year one. -// -// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap -// second table is needed for interpretation, using a [24-hour linear -// smear](https://developers.google.com/time/smear). -// -// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By -// restricting to that range, we ensure that we can convert to and from [RFC -// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. -// -// # Examples -// -// Example 1: Compute Timestamp from POSIX `time()`. -// -// Timestamp timestamp; -// timestamp.set_seconds(time(NULL)); -// timestamp.set_nanos(0); -// -// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -// -// struct timeval tv; -// gettimeofday(&tv, NULL); -// -// Timestamp timestamp; -// timestamp.set_seconds(tv.tv_sec); -// timestamp.set_nanos(tv.tv_usec * 1000); -// -// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -// -// FILETIME ft; -// GetSystemTimeAsFileTime(&ft); -// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -// -// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -// Timestamp timestamp; -// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -// -// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -// -// long millis = System.currentTimeMillis(); -// -// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -// .setNanos((int) ((millis % 1000) * 1000000)).build(); -// -// Example 5: Compute Timestamp from Java `Instant.now()`. -// -// Instant now = Instant.now(); -// -// Timestamp timestamp = -// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) -// .setNanos(now.getNano()).build(); -// -// Example 6: Compute Timestamp from current time in Python. -// -// timestamp = Timestamp() -// timestamp.GetCurrentTime() -// -// # JSON Mapping -// -// In JSON format, the Timestamp type is encoded as a string in the -// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" -// where {year} is always expressed using four digits while {month}, {day}, -// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -// is required. A proto3 JSON serializer should always use UTC (as indicated by -// "Z") when printing the Timestamp type and a proto3 JSON parser should be -// able to accept both UTC and other timezones (as indicated by an offset). -// -// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -// 01:30 UTC on January 15, 2017. -// -// In JavaScript, one can convert a Date object to this format using the -// standard -// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) -// method. In Python, a standard `datetime.datetime` object can be converted -// to this format using -// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with -// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use -// the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D -// ) to obtain a formatter capable of generating timestamps in this format. -// -message Timestamp { - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. - int64 seconds = 1; - - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. - int32 nanos = 2; -} diff --git a/src/struct_pb/conformance/google/protobuf/type.proto b/src/struct_pb/conformance/google/protobuf/type.proto deleted file mode 100644 index fd25a4193..000000000 --- a/src/struct_pb/conformance/google/protobuf/type.proto +++ /dev/null @@ -1,187 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -import "google/protobuf/any.proto"; -import "google/protobuf/source_context.proto"; - -option cc_enable_arenas = true; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TypeProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/typepb"; - -// A protocol buffer message type. -message Type { - // The fully qualified message name. - string name = 1; - // The list of fields. - repeated Field fields = 2; - // The list of types appearing in `oneof` definitions in this type. - repeated string oneofs = 3; - // The protocol buffer options. - repeated Option options = 4; - // The source context. - SourceContext source_context = 5; - // The source syntax. - Syntax syntax = 6; -} - -// A single field of a message type. -message Field { - // Basic field types. - enum Kind { - // Field type unknown. - TYPE_UNKNOWN = 0; - // Field type double. - TYPE_DOUBLE = 1; - // Field type float. - TYPE_FLOAT = 2; - // Field type int64. - TYPE_INT64 = 3; - // Field type uint64. - TYPE_UINT64 = 4; - // Field type int32. - TYPE_INT32 = 5; - // Field type fixed64. - TYPE_FIXED64 = 6; - // Field type fixed32. - TYPE_FIXED32 = 7; - // Field type bool. - TYPE_BOOL = 8; - // Field type string. - TYPE_STRING = 9; - // Field type group. Proto2 syntax only, and deprecated. - TYPE_GROUP = 10; - // Field type message. - TYPE_MESSAGE = 11; - // Field type bytes. - TYPE_BYTES = 12; - // Field type uint32. - TYPE_UINT32 = 13; - // Field type enum. - TYPE_ENUM = 14; - // Field type sfixed32. - TYPE_SFIXED32 = 15; - // Field type sfixed64. - TYPE_SFIXED64 = 16; - // Field type sint32. - TYPE_SINT32 = 17; - // Field type sint64. - TYPE_SINT64 = 18; - } - - // Whether a field is optional, required, or repeated. - enum Cardinality { - // For fields with unknown cardinality. - CARDINALITY_UNKNOWN = 0; - // For optional fields. - CARDINALITY_OPTIONAL = 1; - // For required fields. Proto2 syntax only. - CARDINALITY_REQUIRED = 2; - // For repeated fields. - CARDINALITY_REPEATED = 3; - } - - // The field type. - Kind kind = 1; - // The field cardinality. - Cardinality cardinality = 2; - // The field number. - int32 number = 3; - // The field name. - string name = 4; - // The field type URL, without the scheme, for message or enumeration - // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. - string type_url = 6; - // The index of the field type in `Type.oneofs`, for message or enumeration - // types. The first type has index 1; zero means the type is not in the list. - int32 oneof_index = 7; - // Whether to use alternative packed wire representation. - bool packed = 8; - // The protocol buffer options. - repeated Option options = 9; - // The field JSON name. - string json_name = 10; - // The string value of the default value of this field. Proto2 syntax only. - string default_value = 11; -} - -// Enum type definition. -message Enum { - // Enum type name. - string name = 1; - // Enum value definitions. - repeated EnumValue enumvalue = 2; - // Protocol buffer options. - repeated Option options = 3; - // The source context. - SourceContext source_context = 4; - // The source syntax. - Syntax syntax = 5; -} - -// Enum value definition. -message EnumValue { - // Enum value name. - string name = 1; - // Enum value number. - int32 number = 2; - // Protocol buffer options. - repeated Option options = 3; -} - -// A protocol buffer option, which can be attached to a message, field, -// enumeration, etc. -message Option { - // The option's name. For protobuf built-in options (options defined in - // descriptor.proto), this is the short name. For example, `"map_entry"`. - // For custom options, it should be the fully-qualified name. For example, - // `"google.api.http"`. - string name = 1; - // The option's value packed in an Any message. If the value is a primitive, - // the corresponding wrapper type defined in google/protobuf/wrappers.proto - // should be used. If the value is an enum, it should be stored as an int32 - // value using the google.protobuf.Int32Value type. - Any value = 2; -} - -// The syntax in which a protocol buffer element is defined. -enum Syntax { - // Syntax `proto2`. - SYNTAX_PROTO2 = 0; - // Syntax `proto3`. - SYNTAX_PROTO3 = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/wrappers.proto b/src/struct_pb/conformance/google/protobuf/wrappers.proto deleted file mode 100644 index 1959fa55a..000000000 --- a/src/struct_pb/conformance/google/protobuf/wrappers.proto +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Wrappers for primitive (non-message) types. These types are useful -// for embedding primitives in the `google.protobuf.Any` type and for places -// where we need to distinguish between the absence of a primitive -// typed field and its default value. -// -// These wrappers have no meaningful use within repeated fields as they lack -// the ability to detect presence on individual elements. -// These wrappers have no meaningful use within a map or a oneof since -// individual entries of a map or fields of a oneof can already detect presence. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "WrappersProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// Wrapper message for `double`. -// -// The JSON representation for `DoubleValue` is JSON number. -message DoubleValue { - // The double value. - double value = 1; -} - -// Wrapper message for `float`. -// -// The JSON representation for `FloatValue` is JSON number. -message FloatValue { - // The float value. - float value = 1; -} - -// Wrapper message for `int64`. -// -// The JSON representation for `Int64Value` is JSON string. -message Int64Value { - // The int64 value. - int64 value = 1; -} - -// Wrapper message for `uint64`. -// -// The JSON representation for `UInt64Value` is JSON string. -message UInt64Value { - // The uint64 value. - uint64 value = 1; -} - -// Wrapper message for `int32`. -// -// The JSON representation for `Int32Value` is JSON number. -message Int32Value { - // The int32 value. - int32 value = 1; -} - -// Wrapper message for `uint32`. -// -// The JSON representation for `UInt32Value` is JSON number. -message UInt32Value { - // The uint32 value. - uint32 value = 1; -} - -// Wrapper message for `bool`. -// -// The JSON representation for `BoolValue` is JSON `true` and `false`. -message BoolValue { - // The bool value. - bool value = 1; -} - -// Wrapper message for `string`. -// -// The JSON representation for `StringValue` is JSON string. -message StringValue { - // The string value. - string value = 1; -} - -// Wrapper message for `bytes`. -// -// The JSON representation for `BytesValue` is JSON string. -message BytesValue { - // The bytes value. - bytes value = 1; -} diff --git a/src/struct_pb/examples/CMakeLists.txt b/src/struct_pb/examples/CMakeLists.txt index 3c0d658fa..4183a5de6 100644 --- a/src/struct_pb/examples/CMakeLists.txt +++ b/src/struct_pb/examples/CMakeLists.txt @@ -4,11 +4,11 @@ if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") else() # else find installed yalantinglibs cmake_minimum_required(VERSION 3.15) - project(coro_rpc_examples) + project(struct_pb_examples) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() - set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) # if you have install ylt @@ -17,11 +17,8 @@ else() # else # include_directories(include) # include_directories(include/ylt/thirdparty) - include(struct_pb_helper.cmake) endif() -find_package(Protobuf QUIET) -if (Protobuf_FOUND) - add_executable(struct_pb_tutorial tutorial.cpp) - target_protos_struct_pb(struct_pb_tutorial PRIVATE addressbook.proto) -endif() +add_executable(struct_pb_examples + main.cpp + ) \ No newline at end of file diff --git a/src/struct_pb/examples/addressbook.proto b/src/struct_pb/examples/addressbook.proto deleted file mode 100644 index 8c33fe2af..000000000 --- a/src/struct_pb/examples/addressbook.proto +++ /dev/null @@ -1,26 +0,0 @@ -syntax = "proto3"; - -package tutorial; - -message Person { - string name = 1; - int32 id = 2; - string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - string number = 1; - PhoneType type = 2; - } - - repeated PhoneNumber phones = 4; -} - -message AddressBook { - repeated Person people = 1; -} diff --git a/src/struct_pb/examples/demo.proto b/src/struct_pb/examples/demo.proto deleted file mode 100644 index 49fdc6a6e..000000000 --- a/src/struct_pb/examples/demo.proto +++ /dev/null @@ -1,50 +0,0 @@ -syntax = "proto3"; - -message SearchRequest { - string query = 1; - int32 page_number = 2; - int32 result_per_page = 3; -} - -enum Corpus { - CORPUS_UNSPECIFIED = 0; - CORPUS_UNIVERSAL = 1; - CORPUS_WEB = 2; - CORPUS_IMAGES = 3; - CORPUS_LOCAL = 4; - CORPUS_NEWS = 5; - CORPUS_PRODUCTS = 6; - CORPUS_VIDEO = 7; -} - -message Outer { // Level 0 - message MiddleAA { // Level 1 - message Inner { // Level 2 - int64 ival = 1; - bool booly = 2; - } - } - message MiddleBB { // Level 1 - message Inner { // Level 2 - int32 ival = 1; - bool booly = 2; - } - } -} - -message SampleMessage { - oneof test_oneof { - string name = 4; - SubMessage sub_message = 9; - } -} -message SubMessage { - int32 val = 1; -} - -message SampleMap { - map projects = 3; -} -message Project { - string name = 1; -} \ No newline at end of file diff --git a/src/struct_pb/examples/main.cpp b/src/struct_pb/examples/main.cpp new file mode 100644 index 000000000..6b631d608 --- /dev/null +++ b/src/struct_pb/examples/main.cpp @@ -0,0 +1,68 @@ +#include +#include +#include + +struct my_struct : struct_pb::base_impl { + my_struct() = default; + my_struct(int a, bool b, struct_pb::fixed64_t c) : x(a), y(b), z(c) {} + int x; + bool y; + struct_pb::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest : struct_pb::base_impl { + nest() = default; + nest(std::string s, my_struct t, int v) + : name(std::move(s)), value(t), var(v) {} + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest, name, value, var); + +struct person { + int id; + std::string name; + int age; +}; +REFLECTION(person, id, name, age); + +int main() { + nest v{"Hi", my_struct{1, false, {3}}, 5}; + std::string s; + struct_pb::to_pb(v, s); + + nest v2; + struct_pb::from_pb(v2, s); + assert(v.var == v2.var); + assert(v.value.y == v2.value.y); + assert(v.value.z == v2.value.z); + + person p{1, "tom", 22}; + std::string str; + struct_pb::to_pb(p, str); + + person p1; + struct_pb::from_pb(p1, str); + assert(p.age == p1.age); + assert(p.name == p1.name); + assert(p.id == p1.id); + + // dynamic reflection + auto t = struct_pb::create_instance("nest"); + auto names = t->get_fields_name(); + bool r = (names == std::vector{"name", "value", "var"}); + assert(r); + + t->set_field_value("name", std::string("tom")); + auto name = t->get_field_value("name"); + assert(name == "tom"); + + auto d = dynamic_cast(t.get()); + assert(d->name == "tom"); + + t->set_field_value("name", "hello"); + auto &field_name = t->get_field_value("name"); + assert(field_name == "hello"); +} \ No newline at end of file diff --git a/src/struct_pb/examples/tutorial.cpp b/src/struct_pb/examples/tutorial.cpp deleted file mode 100644 index ddf310ce5..000000000 --- a/src/struct_pb/examples/tutorial.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include - -#include "addressbook.struct_pb.h" -void prompt_for_address(tutorial::Person& person) { - std::cout << "==================================" << std::endl; - std::cout << " Add People " << std::endl; - std::cout << "==================================" << std::endl; - std::cout << "Enter person ID number: "; - std::cin >> person.id; - std::cin.ignore(256, '\n'); - std::cout << "Enter name: "; - std::getline(std::cin, person.name); - std::cout << "Enter email address (blank for none): "; - std::getline(std::cin, person.email); - while (true) { - std::cout << "Enter a phone number (or leave blank to finish): "; - tutorial::Person::PhoneNumber phone_number; - std::getline(std::cin, phone_number.number); - if (phone_number.number.empty()) { - break; - } - std::cout << "Is this a mobile, home, or work phone? "; - std::string type; - std::getline(std::cin, type); - if (type == "mobile") { - phone_number.type = tutorial::Person::PhoneType::MOBILE; - } - else if (type == "home") { - phone_number.type = tutorial::Person::PhoneType::HOME; - } - else if (type == "work") { - phone_number.type = tutorial::Person::PhoneType::WORK; - } - else { - std::cout << "Unknown phone type: Using default." << std::endl; - } - person.phones.push_back(phone_number); - } -} -void list_people(const tutorial::AddressBook& address_book) { - std::cout << "==================================" << std::endl; - std::cout << " List People " << std::endl; - std::cout << "==================================" << std::endl; - for (const auto& person : address_book.people) { - std::cout << " Person ID: " << person.id << std::endl; - std::cout << " Name: " << person.name << std::endl; - if (!person.email.empty()) { - std::cout << "E-mail address: " << person.email << std::endl; - } - for (const auto& phone : person.phones) { - switch (phone.type) { - case tutorial::Person::PhoneType::MOBILE: - std::cout << "Mobile phone #: "; - break; - case tutorial::Person::PhoneType::HOME: - std::cout << " Home phone #: "; - break; - case tutorial::Person::PhoneType::WORK: - std::cout << " Work phone #: "; - break; - } - std::cout << phone.number << std::endl; - } - } -} -int main(int argc, char* argv[]) { - if (argc != 2) { - std::cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << std::endl; - return -1; - } - tutorial::AddressBook address_book; - std::fstream input(argv[1], std::ios::in | std::ios::binary); - if (!input) { - std::cout << argv[1] << ": File not found. Creating a new file." - << std::endl; - } - else { - input.seekg(0, input.end); - int length = input.tellg(); - input.seekg(0, input.beg); - std::string buffer; - buffer.resize(length); - input.read(buffer.data(), buffer.size()); - input.close(); - bool ok = struct_pb::deserialize_to(address_book, buffer); - if (!ok) { - std::cerr << "Failed to parse address book." << std::endl; - return -1; - } - } - list_people(address_book); - address_book.people.emplace_back(); - prompt_for_address(address_book.people.back()); - std::fstream output(argv[1], - std::ios::out | std::ios::trunc | std::ios::binary); - std::string buffer = struct_pb::serialize(address_book); - output.write(buffer.data(), buffer.size()); - output.close(); - list_people(address_book); - std::cout << "Done!!!" << std::endl; - return 0; -} \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/CMakeLists.txt b/src/struct_pb/protoc-plugin/CMakeLists.txt deleted file mode 100644 index 368d25d33..000000000 --- a/src/struct_pb/protoc-plugin/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/bin) -find_package(Protobuf QUIET) -if (Protobuf_FOUND) - file(GLOB SRCS "*.cpp" "*.h") - add_executable(protoc-gen-struct_pb ${SRCS}) - target_link_libraries(protoc-gen-struct_pb PUBLIC protobuf::libprotoc protobuf::libprotobuf) - install( - TARGETS protoc-gen-struct_pb - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - ) -else () - message(STATUS "struct_pb is skipped. To build struct_pb protoc plugin, you must install libprotoc first\n" - - "see https://alibaba.github.io/yalantinglibs/en/struct_pb/struct_pb_generating_your_struct.html" - ) -endif () diff --git a/src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp b/src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp deleted file mode 100644 index 333d86db7..000000000 --- a/src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp +++ /dev/null @@ -1,328 +0,0 @@ -#include "EnumFieldGenerator.h" - -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor *descriptor, - const Options &options) - : FieldGenerator(descriptor, options) {} -std::string EnumFieldGenerator::cpp_type_name() const { - auto name = qualified_enum_name(d_->enum_type(), options_); - if (is_optional()) { - return "std::optional<" + name + ">"; - } - return name; -} -void EnumFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value + ".value()"); - format(";\n"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - {"value", value}, - {"default_value", default_value()}, - }, - R"( -if ($value$ != $default_value$) { - total += $tag_sz$ + )"); - generate_calculate_size_only(p, value); - p->Print(R"(; -} -)"); - } - else { - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -total += $tag_sz$ + )"); - generate_calculate_size_only(p, value); - p->Print(R"(; -} -)"); - } - } -} -void EnumFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - // auto v = p->WithVars({{"tag", calculate_tag(d_)}, {"value", value}}); - if (is_optional()) { - p->Print({{"tag", calculate_tag_str(d_)}, {"value", value}}, R"( -if ($value$.has_value()) { -)"); - generate_serialization_only(p, value + ".value()"); - p->Print(R"( -} -)"); - } - else { - if (can_ignore_default_value) { - p->Print({{"tag", calculate_tag_str(d_)}, - {"value", value}, - {"default_value", default_value()}}, - R"( -if ($value$ != $default_value$) { -)"); - generate_serialization_only(p, value); - p->Print(R"( -} -)"); - } - else { - generate_serialization_only(p, value); - } - } -} -void EnumFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", calculate_tag_str(d_)}, {"value", value}}, R"( -serialize_varint(data, pos, size, $tag$); -serialize_varint(data, pos, size, static_cast($value$)); -)"); -} -void EnumFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print( - { - {"tag", calculate_tag_str(d_)}, - {"value", value}, - }, - R"( -case $tag$: { -)"); - generate_deserialization_only(p, value); - p->Print(R"( - break; -} -)"); -} -void EnumFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size) const { - auto enum_name = qualified_enum_name(d_->enum_type(), options_); - p->Print( - {{"enum_name", enum_name}, {"output", output}, {"max_size", max_size}}, - R"( -uint64_t enum_val_tmp{}; -ok = deserialize_varint(data, pos, $max_size$, enum_val_tmp); -if (!ok) { - return false; -} -$output$ = static_cast<$enum_name$>(enum_val_tmp); -)"); -} -RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : FieldGenerator(descriptor, options) {} -std::string RepeatedEnumFieldGenerator::cpp_type_name() const { - return "std::vector<" + qualified_enum_name(d_->enum_type(), options_) + ">"; -} - -void RepeatedEnumFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - if (can_ignore_default_value) { - if (is_packed()) { - p->Print({{"value", value}}, R"( -if (!$value$.empty()) { // packed -)"); - generate_calculate_size_only(p, value, "sz"); - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -total += $tag_sz$ + calculate_varint_size(sz) + sz; -} -)"); - } - else { - p->Print({{"value", value}}, R"( -if (!$value$.empty()) { // unpacked -)"); - generate_calculate_size_only(p, value, "sz"); - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( - total += sz; -} -)"); - } - } - else { - if (is_packed()) { - generate_calculate_size_only(p, value, "sz"); - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -// packed -total += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - } - else { - generate_calculate_size_only(p, value, "sz"); - p->Print( - R"( -// unpacked -total += sz; -)"); - } - } -} -void RepeatedEnumFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &output) const { - if (is_packed()) { - p->Print({{"value", value}, - {"output", output}, - {"tag_sz", calculate_tag_size(d_)}}, - R"( -std::size_t $output$ = 0; -for(const auto& v: $value$) { - $output$ += calculate_varint_size(static_cast(v)); -} -)"); - } - else { - p->Print({{"value", value}, - {"output", output}, - {"tag_sz", calculate_tag_size(d_, true)}}, - R"( -std::size_t $output$ = 0; -for(const auto& v: $value$) { - $output$ += $tag_sz$; - $output$ += calculate_varint_size(static_cast(v)); -} -)"); - } -} - -void RepeatedEnumFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - if (can_ignore_default_value) { - p->Print({{"value", value}}, R"( -if (!$value$.empty()) { -)"); - generate_serialization_only(p, value); - p->Print("}\n"); - } - else { - generate_serialization_only(p, value); - } -} -void RepeatedEnumFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - if (is_packed()) { - p->Print({{"tag", std::to_string(calculate_tag(d_))}}, R"( -serialize_varint(data, pos, size, $tag$); -)"); - generate_calculate_size_only(p, value, "sz"); - p->Print({{"value", value}}, - R"( -serialize_varint(data, pos, size, sz); -for(const auto& v: $value$) { - serialize_varint(data, pos, size, static_cast(v)); -} -)"); - } - else { - p->Print( - {{"tag", std::to_string(calculate_tag(d_, true))}, {"value", value}}, - R"( -for(const auto& v: $value$) { - serialize_varint(data, pos, size, $tag$); - serialize_varint(data, pos, size, static_cast(v)); -} -)"); - } -} -void RepeatedEnumFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - // generate packed - p->Print({{"tag", packed_tag()}, - {"value", value}, - {"enum_name", qualified_enum_name(d_->enum_type(), options_)} - - }, - R"( -case $tag$: { - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - std::size_t cur_max_sz = pos + sz; - if (cur_max_sz > size) { - return false; - } - while (pos < cur_max_sz) { - uint64_t enum_val_tmp{}; - ok = deserialize_varint(data, pos, cur_max_sz, enum_val_tmp); - if (!ok) { - return false; - } - $value$.push_back(static_cast<$enum_name$>(enum_val_tmp)); - } - break; -} -)"); - p->Print({{"tag", unpacked_tag()}, - {"value", value}, - {"enum_name", qualified_enum_name(d_->enum_type(), options_)}}, - R"( -case $tag$: { - uint64_t enum_val_tmp{}; - ok = deserialize_varint(data, pos, size, enum_val_tmp); - if (!ok) { - return false; - } - $value$.push_back(static_cast<$enum_name$>(enum_val_tmp)); - break; -} -)"); -} -bool RepeatedEnumFieldGenerator::is_packed() const { - return d_->is_packable() && d_->is_packed(); -} -std::string RepeatedEnumFieldGenerator::packed_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 2; - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -std::string RepeatedEnumFieldGenerator::unpacked_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 0; - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -std::string EnumFieldGenerator::default_value() const { - return qualified_enum_name(d_->enum_type(), options_) + - "::" + d_->default_value_enum()->name(); -} -void EnumFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"value", value}}, - "calculate_varint_size(static_cast($value$))"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/EnumFieldGenerator.h b/src/struct_pb/protoc-plugin/EnumFieldGenerator.h deleted file mode 100644 index beb60e9c8..000000000 --- a/src/struct_pb/protoc-plugin/EnumFieldGenerator.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "FieldGenerator.h" - -namespace struct_pb { -namespace compiler { - -class EnumFieldGenerator : public FieldGenerator { - public: - EnumFieldGenerator(const FieldDescriptor *descriptor, const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size = "size") const; - - private: - std::string default_value() const; -}; -class RepeatedEnumFieldGenerator : public FieldGenerator { - public: - RepeatedEnumFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value, - const std::string &output) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - - private: - bool is_packed() const; - std::string packed_tag() const; - std::string unpacked_tag() const; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/EnumGenerator.cpp b/src/struct_pb/protoc-plugin/EnumGenerator.cpp deleted file mode 100644 index a67c0aa8a..000000000 --- a/src/struct_pb/protoc-plugin/EnumGenerator.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "EnumGenerator.h" - -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -void EnumGenerator::generate(google::protobuf::io::Printer *p) { - std::string enum_name = resolve_keyword(d_->name()); - p->Print({{"enum_name", enum_name}}, R"( -enum class $enum_name$ { -)"); - for (int j = 0; j < d_->value_count(); ++j) { - auto v = d_->value(j); - p->Print({{"name", resolve_keyword(v->name())}, - {"value", std::to_string(v->number())}}, - R"( -$name$ = $value$, -)"); - } - p->Print( - R"( -}; -)"); -} -void EnumGenerator::generate_definition(google::protobuf::io::Printer *p) { - Formatter format(p); - format("enum class $1$: int {\n", resolve_keyword(d_->name())); - format.indent(); - for (int i = 0; i < d_->value_count(); ++i) { - auto value = resolve_keyword(d_->value(i)->name()); - auto number = d_->value(i)->number(); - format("$1$ = $2$,\n", value, number); - } - format.outdent(); - format("};\n"); -} -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/EnumGenerator.h b/src/struct_pb/protoc-plugin/EnumGenerator.h deleted file mode 100644 index b39d80501..000000000 --- a/src/struct_pb/protoc-plugin/EnumGenerator.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include -#include - -#include "GeneratorBase.h" -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -class EnumGenerator : public GeneratorBase { - public: - EnumGenerator(const google::protobuf::EnumDescriptor *d, Options options) - : GeneratorBase(options), d_(d) {} - void generate(google::protobuf::io::Printer *p); - void generate_definition(google::protobuf::io::Printer *p); - - private: - const google::protobuf::EnumDescriptor *d_; -}; -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/FieldGenerator.cpp b/src/struct_pb/protoc-plugin/FieldGenerator.cpp deleted file mode 100644 index 4965e5e7e..000000000 --- a/src/struct_pb/protoc-plugin/FieldGenerator.cpp +++ /dev/null @@ -1,557 +0,0 @@ -#include "FieldGenerator.h" - -#include "EnumFieldGenerator.h" -#include "MapFieldGenerator.h" -#include "MessageFieldGenerator.h" -#include "OneofFieldGenerator.h" -#include "PrimitiveFieldGenerator.h" -#include "StringFieldGenerator.h" -#include "google/protobuf/io/printer.h" -#include "helpers.hpp" - -using namespace google::protobuf; -namespace struct_pb { -namespace compiler { - -bool is_varint(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_BOOL: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - return true; - default: - return false; - } -} -bool is_sint(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - return true; - default: - return false; - } -} -bool is_sint32(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_SINT32: - return true; - default: - return false; - } -} -bool is_enum(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_ENUM; -} -bool is_bool(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_BOOL; -} -bool is_i64(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_DOUBLE: - return true; - default: - return false; - } -} -bool is_i32(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - case FieldDescriptor::TYPE_FLOAT: - return true; - default: - return false; - } -} -bool is_string(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - return true; - default: - return false; - } -} -bool is_message(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_MESSAGE; -} - -bool is_group(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_GROUP; -} - -bool is_number(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_DOUBLE: - case FieldDescriptor::TYPE_FLOAT: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_BOOL: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_SFIXED32: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - return true; - default: - return false; - } -} - -uint32_t calculate_tag(const FieldDescriptor *f, bool ignore_repeated) { - uint32_t number = f->number(); - uint32_t wire_type; - if (f->is_repeated() && !ignore_repeated) { - wire_type = 2; - } - else if (is_varint(f)) { - wire_type = 0; - } - else if (is_i64(f)) { - wire_type = 1; - } - else if (is_i32(f)) { - wire_type = 5; - } - else { - wire_type = 2; - } - return (number << 3) | wire_type; -} - -std::string calculate_tag_str(const FieldDescriptor *f, bool ignore_repeated) { - return std::to_string(calculate_tag(f, ignore_repeated)); -} - -std::size_t calculate_varint_size(uint64_t t) { - std::size_t ret = 0; - do { - ret++; - t >>= 7; - } while (t != 0); - return ret; -} - -std::string calculate_tag_size(const FieldDescriptor *f, bool ignore_repeated) { - auto tag = calculate_tag(f, ignore_repeated); - auto tag_size = calculate_varint_size(tag); - return std::to_string(tag_size); -} - -std::string get_comment(const FieldDescriptor *d_) { - std::string comment; - if (d_->has_optional_keyword()) { - comment += "optional "; - } - if (d_->is_repeated()) { - comment += "repeated "; - } - if (is_message(d_)) { - comment += class_name(d_->message_type()); - } - else { - comment += d_->type_name(); - } - comment += " "; - comment += d_->name(); - comment += " = "; - comment += std::to_string(d_->number()); - comment += ", tag = "; - comment += std::to_string(calculate_tag(d_)); - return comment; -} - -void FieldGenerator::generate_definition( - google::protobuf::io::Printer *p) const { - p->Print( - { - {"type", cpp_type_name()}, - {"name", name()}, - {"pb_type", pb_type_name()}, - {"number", std::to_string(d_->number())}, - }, - R"($type$ $name$; // $pb_type$, field number = $number$ -)"); -} - -std::string FieldGenerator::get_type_name() const { - switch (d_->type()) { - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - return "double"; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - return "float"; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - return "int64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - return "uint64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - return "uint32_t"; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - return "int32_t"; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - return "bool"; - case google::protobuf::FieldDescriptor::TYPE_STRING: - case google::protobuf::FieldDescriptor::TYPE_BYTES: - return "std::string"; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: { - auto m = d_->message_type(); - if (d_->is_map()) { - auto key = m->field(0); - auto value = m->field(1); - std::string type_name = "std::map<"; - type_name += FieldGenerator(key, options_).get_type_name(); - type_name += ", "; - type_name += FieldGenerator(value, options_).get_type_name(); - type_name += ">"; - return type_name; - } - else if (d_->is_repeated()) { - if (is_message(d_)) { - return qualified_class_name(d_->message_type(), options_); - } - else { - return m->name(); - } - } - else { - auto p = d_->containing_type(); - if (is_map_entry(p)) { - return m->name(); - } - else { - return "std::unique_ptr<" + - qualified_class_name(d_->message_type(), options_) + ">"; - } - } - } - case google::protobuf::FieldDescriptor::TYPE_ENUM: - return d_->enum_type()->name(); - case google::protobuf::FieldDescriptor::TYPE_GROUP: - // workaround for group - return "std::string"; - default: { - return "not support now"; - } - } -} - -void FieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - // auto name = value.empty() ? "t." + this->name() : value; - // auto tag = calculate_tag(d_); - // auto v = - // p->WithVars({{"name", name}, {"tag_size", - // calculate_varint_size(tag)}}); - // std::string comment = get_comment(d_); - // p->Print({{"comment", comment}}, R"( - //// $comment$ - //)"); - // if (d_->has_optional_keyword() && !is_message(d_)) { - // p->Print(R"( - // if ($name$.has_value()) { - //)"); - // generate_calculate_one(p, name + ".value()", false); - // p->Print("}\n"); - // } else if (d_->is_repeated()) { - // generate_calculate_vector(p); - // } else { - // generate_calculate_one(p, name, can_ignore_default_value); - // } -} - -void FieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - // auto name = value.empty() ? "t." + this->name() : value; - // auto tag = calculate_tag(d_); - // auto v = - // p->WithVars({{"name", name}, {"tag_size", - // calculate_varint_size(tag)}}); - // auto comment = get_comment(d_); - // p->Print({{"comment", comment}}, R"( - //// $comment$ - //)"); - // if (is_optional()) { - // p->Print(R"( - // if ($name$.has_value()) { - //)"); - // generate_serialize_one(p, name + ".value()", false); - // p->Print("}\n"); - // } else if (d_->is_repeated()) { - // generate_serialize_vector(p); - // } else { - // generate_serialize_one(p, name, can_ignore_default_value); - // } -} -void FieldGenerator::generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const {} -bool FieldGenerator::is_ptr() const { - auto p = d_->containing_type(); - if (p && is_map_entry(p)) { - return false; - } - return true; -} -std::string FieldGenerator::name() const { return resolve_keyword(d_->name()); } -bool FieldGenerator::is_optional() const { - auto p = d_->containing_type(); - if (p && is_map_entry(p)) { - return false; - } - // return d_->is_optional(); - // return d_->has_optional_keyword() && !is_message(d_); - return d_->has_presence(); -} -std::string FieldGenerator::qualified_name() const { - if (is_message(d_)) { - return qualified_class_name(d_->message_type(), options_); - } - else if (is_enum(d_)) { - return qualified_enum_name(d_->enum_type(), options_); - } - else { - return get_type_name(); - } -} -std::string FieldGenerator::pb_type_name() const { return d_->type_name(); } -void FieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, bool can_ignore_default_value) const { - auto oneof = d_->real_containing_oneof(); - if (oneof) { - generate_calculate_size(p, "t." + resolve_keyword(oneof->name()), - can_ignore_default_value); - } - else { - generate_calculate_size(p, "t." + name(), can_ignore_default_value); - } -} -void FieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, bool can_ignore_default_value) const { - auto oneof = d_->real_containing_oneof(); - if (oneof) { - generate_serialization(p, "t." + resolve_keyword(oneof->name()), - can_ignore_default_value); - } - else { - Formatter format(p); - format("// "); - generate_definition(p); - generate_serialization(p, "t." + name(), can_ignore_default_value); - } -} -void FieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p) const { - auto oneof = d_->real_containing_oneof(); - if (oneof) { - generate_deserialization(p, "t." + resolve_keyword(oneof->name())); - } - else { - Formatter format(p); - format("// "); - generate_definition(p); - generate_deserialization(p, "t." + name()); - } -} -std::string FieldGenerator::cpp_type_name() const { - assert(false && "why?"); - return "???"; -} -void OneofGenerator::generate_definition(google::protobuf::io::Printer *p) { - p->Print(R"(std::variantfield_count(); ++i) { - auto f = d_->field(i); - FieldGenerator fg(f, options_); - std::string type_name = fg.get_type_name(); - if (is_message(f)) { - type_name = qualified_class_name(f->message_type(), options_); - type_name = "std::unique_ptr<" + type_name + ">"; - } - else if (is_enum(f)) { - type_name = qualified_enum_name(f->enum_type(), options_); - } - p->Print( - { - {"type", type_name}, - {"name", f->name()}, - {"pb_type", f->type_name()}, - {"number", std::to_string(f->number())}, - }, - R"(, $type$ // $pb_type$, field number = $number$ -)"); - } - p->Print({{"name", name()}}, R"(> $name$; -)"); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - if (is_message(f)) { - MessageOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - else if (is_string(f)) { - StringOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - else if (is_enum(f)) { - EnumOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - else { - PrimitiveOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - } -} -void OneofGenerator::generate_calculate_size(google::protobuf::io::Printer *p) { - Formatter format(p); - format("{\n"); - format.indent(); - format("switch (t.$1$.index()) {\n", name()); - p->Print(R"( -case 0: { - // empty, do nothing - break; -} -)"); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - format("case $1$: {\n", i + 1); - format.indent(); - std::string value = - "std::get<" + std::to_string(i + 1) + ">(t." + name() + ")"; - FieldGenerator(f, options_).generate_calculate_size(p, value, false); - format("break;\n"); - format.outdent(); - format("}\n"); - } - format("}\n"); - format.outdent(); - format("}\n"); -} -void OneofGenerator::generate_serialization( - google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f) { - // auto index = get_index(f); - // assert(index != 0); - // auto v = p->WithVars({{"name", "t." + name()}, {"index", index}}); - // Formatter format(p); - // format("if ($name$.index() == $index$) {\n"); - // format.indent(); - // std::string name = "std::get<"; - // name += std::to_string(index); - // name += ">"; - // name += "("; - // name += "t." + this->name(); - // name += ")"; - // FieldGenerator(f, options_).generate_serialization(p, name, false); - // format.outdent(); - // format("}\n"); -} -void OneofGenerator::generate_deserialization( - google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f) { - // auto index = get_index(f); - // assert(index != 0); - // auto v = p->WithVars({{"name", "t." + name()}, {"index", index}}); - // Formatter format(p); - // FieldGenerator fg(f, options_); - // std::string end = - // "t." + name() + ".emplace<" + std::to_string(index) + ">(tmp);"; - // if (is_message(f)) { - // auto type_name = qualified_class_name(f->message_type(), options_); - // fg.generate_deserialization( - // p, "tmp", type_name + "* tmp = new " + type_name + "();", end); - // } else if (is_enum(f)) { - // auto type_name = qualified_enum_name(f->enum_type(), options_); - // fg.generate_deserialization(p, "tmp", type_name + " tmp{};", end); - // } else { - // fg.generate_deserialization(p, "tmp", fg.get_type_name() + " tmp{};", - // end); - // } -} -int OneofGenerator::get_index( - const google::protobuf::FieldDescriptor *f) const { - auto index = 0; - for (int i = 0; i < d_->field_count(); ++i) { - auto fd = d_->field(i); - if (fd == f) { - index = i + 1; - } - } - return index; -} -std::string OneofGenerator::name() const { return resolve_keyword(d_->name()); } -FieldGenerator *FieldGeneratorMap::MakeGenerator(const FieldDescriptor *field, - const Options &options) { - if (field->is_repeated()) { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: - if (field->is_map()) { - return new MapFieldGenerator(field, options); - } - else { - return new RepeatedMessageFieldGenerator(field, options); - } - case FieldDescriptor::CPPTYPE_STRING: - return new RepeatedStringFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_ENUM: - return new RepeatedEnumFieldGenerator(field, options); - default: - return new RepeatedPrimitiveFieldGenerator(field, options); - } - } - else if (field->real_containing_oneof()) { - return new OneofFieldGenerator(field, options); - // switch (field->cpp_type()) { - // case FieldDescriptor::CPPTYPE_MESSAGE: - // return new MessageOneofFieldGenerator(field, options, scc_analyzer); - // case FieldDescriptor::CPPTYPE_STRING: - // return new StringOneofFieldGenerator(field, options); - // case FieldDescriptor::CPPTYPE_ENUM: - // return new EnumOneofFieldGenerator(field, options); - // default: - // return new PrimitiveOneofFieldGenerator(field, options); - // } - } - else { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_STRING: - return new StringFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_ENUM: - return new EnumFieldGenerator(field, options); - default: - return new PrimitiveFieldGenerator(field, options); - } - } -} -FieldGeneratorMap::FieldGeneratorMap(const Descriptor *descriptor, - const Options &options) - : descriptor_(descriptor), field_generators_(descriptor->field_count()) { - // Construct all the FieldGenerators. - for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset(MakeGenerator(descriptor->field(i), options)); - } -} -const FieldGenerator &FieldGeneratorMap::get( - const FieldDescriptor *field) const { - return *field_generators_[field->index()]; -} -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/FieldGenerator.h b/src/struct_pb/protoc-plugin/FieldGenerator.h deleted file mode 100644 index 8fba31b5a..000000000 --- a/src/struct_pb/protoc-plugin/FieldGenerator.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once -#include "GeneratorBase.h" -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -class OneofGenerator; -bool is_varint(const FieldDescriptor *f); -bool is_sint(const FieldDescriptor *f); -bool is_sint32(const FieldDescriptor *f); -bool is_bool(const FieldDescriptor *f); -bool is_i64(const FieldDescriptor *f); -bool is_i32(const FieldDescriptor *f); -uint32_t calculate_tag(const FieldDescriptor *f, bool ignore_repeated = false); -std::string calculate_tag_str(const FieldDescriptor *f, - bool ignore_repeated = false); -std::string calculate_tag_size(const FieldDescriptor *f, - bool ignore_repeated = false); -class FieldGenerator : public GeneratorBase { - public: - FieldGenerator(const google::protobuf::FieldDescriptor *d, - const Options &options) - : GeneratorBase(options), d_(d) {} - void generate_definition(google::protobuf::io::Printer *p) const; - void generate_calculate_size(google::protobuf::io::Printer *p, - bool can_ignore_default_value) const; - void generate_serialization(google::protobuf::io::Printer *p, - bool can_ignore_default_value) const; - void generate_deserialization(google::protobuf::io::Printer *p) const; - - virtual void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const; - virtual void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const; - virtual void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const; - virtual std::string cpp_type_name() const; - virtual std::string pb_type_name() const; - - protected: - std::string get_type_name() const; - bool is_ptr() const; - std::string name() const; - bool is_optional() const; - std::string qualified_name() const; - - protected: - const google::protobuf::FieldDescriptor *d_; - friend class OneofGenerator; -}; -class OneofGenerator : public GeneratorBase { - public: - OneofGenerator(const google::protobuf::OneofDescriptor *d, - const Options &options) - : GeneratorBase(options), d_(d) {} - void generate_definition(google::protobuf::io::Printer *p); - void generate_calculate_size(google::protobuf::io::Printer *p); - void generate_serialization(google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f); - void generate_deserialization(google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f); - - private: - int get_index(const google::protobuf::FieldDescriptor *f) const; - std::string name() const; - - private: - const google::protobuf::OneofDescriptor *d_; -}; -class MapFieldGenerator; -class FieldGeneratorMap { - public: - FieldGeneratorMap(const Descriptor *descriptor, const Options &options); - FieldGeneratorMap(const FieldGeneratorMap &) = delete; - FieldGeneratorMap &operator=(const FieldGeneratorMap &) = delete; - - const FieldGenerator &get(const FieldDescriptor *field) const; - - private: - const Descriptor *descriptor_; - std::vector> field_generators_; - - static FieldGenerator *MakeGenerator(const FieldDescriptor *field, - const Options &options); - friend class MapFieldGenerator; -}; - -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/FileGenerator.cpp b/src/struct_pb/protoc-plugin/FileGenerator.cpp deleted file mode 100644 index 1525ad9ce..000000000 --- a/src/struct_pb/protoc-plugin/FileGenerator.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "FileGenerator.h" - -#include - -#include "EnumGenerator.h" -#include "MessageGenerator.h" -#include "helpers.hpp" -using namespace google::protobuf; -using namespace google::protobuf::compiler; -namespace struct_pb { -namespace compiler { - -FileGenerator::FileGenerator(const google::protobuf::FileDescriptor *file, - Options options) - : GeneratorBase(options), file_(file) { - // std::vector msgs = flatten_messages_in_file(file); - for (int i = 0; i < file_->message_type_count(); ++i) { - message_generators_.push_back( - std::make_unique(file_->message_type(i), options)); - } - for (int i = 0; i < file->enum_type_count(); ++i) { - enum_generators_.push_back( - std::make_unique(file->enum_type(i), options)); - } -} - -void FileGenerator::generate_enum_definitions( - google::protobuf::io::Printer *p) { - for (int i = 0; i < enum_generators_.size(); ++i) { - enum_generators_[i]->generate_definition(p); - } -} -void FileGenerator::generate_message_definitions( - google::protobuf::io::Printer *p) { - for (int i = 0; i < message_generators_.size(); ++i) { - message_generators_[i]->generate_struct_definition(p); - } -} -void FileGenerator::generate_shared_header_code( - google::protobuf::io::Printer *p) { - generate_fwd_decls(p); - generate_enum_definitions(p); - generate_message_definitions(p); -} -void FileGenerator::generate_header(google::protobuf::io::Printer *p) { - p->Print( - {{"filename", file_->name()}}, - R"(// Generated by the protocol buffer compiler (struct_pb). DO NOT EDIT! -// source: $filename$ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ylt/struct_pb.hpp" -)"); - - generate_dependency_includes(p); - generate_ns_open(p); - generate_shared_header_code(p); - generate_ns_close(p); - generate_message_struct_pb_func_definitions(p); - p->Print("// clang-format on\n"); -} - -void FileGenerator::generate_fwd_decls(google::protobuf::io::Printer *p) { - Formatter format(p); - for (int i = 0; i < file_->message_type_count(); ++i) { - auto m = file_->message_type(i); - format("struct $1$;\n", resolve_keyword(m->name())); - } -} -void FileGenerator::generate_dependency_includes( - google::protobuf::io::Printer *p) { - Formatter format(p); - for (int i = 0; i < file_->dependency_count(); ++i) { - auto dep = file_->dependency(i); - std::string basename = strip_proto(dep->name()); - std::string header_name = basename + ".struct_pb.h"; - format("#include \"$1$\"\n", header_name); - } -} -void FileGenerator::generate_source(google::protobuf::io::Printer *p) { - generate_message_struct_pb_func_source(p); -} -void FileGenerator::generate_message_struct_pb_func_definitions( - google::protobuf::io::Printer *p) { - std::vector msgs = flatten_messages_in_file(file_); - Formatter format(p); - format("namespace struct_pb {\n"); - format("namespace internal {\n"); - for (auto msg : msgs) { - auto name = qualified_class_name(msg, options_); - format("// $1$\n", name); - format( - "template<>\n" - "std::size_t get_needed_size<$1$>(const $1$& t, const " - "::struct_pb::UnknownFields& unknown_fields);\n", - name); - format( - "template<>\n" - "void serialize_to<$1$>(char* data, std::size_t size, const $1$& t, " - "const " - "::struct_pb::UnknownFields& unknown_fields);\n", - name); - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size, " - "::struct_pb::UnknownFields& unknown_fields);\n", - name); - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t " - "size);\n", - name); - format("\n"); - } - format("} // internal\n"); - format("} // struct_pb\n"); -} -void FileGenerator::generate_message_struct_pb_func_source( - google::protobuf::io::Printer *p) { - std::vector msgs = flatten_messages_in_file(file_); - Formatter format(p); - format("namespace struct_pb {\n"); - format("namespace internal {\n"); - for (auto msg : msgs) { - auto name = qualified_class_name(msg, options_); - MessageGenerator g(msg, options_); - format("// $1$\n", name); - format( - "template<>\n" - "std::size_t get_needed_size<$1$>(const $1$& t, const " - "::struct_pb::UnknownFields& unknown_fields) {\n", - name); - format.indent(); - g.generate_get_needed_size(p); - format.outdent(); - format( - "} // std::size_t get_needed_size<$1$>(const $1$& t, const " - "::struct_pb::UnknownFields& unknown_fields)\n", - name); - - format( - "template<>\n" - "void serialize_to<$1$>(char* data, std::size_t size, const $1$& t, " - "const ::struct_pb::UnknownFields& unknown_fields) {\n", - name); - format.indent(); - g.generate_serialize_to(p); - format.outdent(); - format( - "} // void serialize_to<$1$>(char* data, std::size_t size, const $1$& " - "t, " - "const ::struct_pb::UnknownFields& unknown_fields)\n", - name); - - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size, " - "::struct_pb::UnknownFields& unknown_fields) {\n", - name); - format.indent(); - g.generate_deserialize_to(p); - format.outdent(); - format("return true;\n"); - format("} // bool deserialize_to<$1$>($1$&, const char*, std::size_t)\n", - name); - format("// end of $1$\n", name); - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size) " - "{\n", - name); - format.indent(); - format("::struct_pb::UnknownFields unknown_fields{};\n"); - format("return deserialize_to(t,data,size,unknown_fields);\n"); - format.outdent(); - format("}\n"); - format("\n"); - } - format("} // internal\n"); - format("} // struct_pb\n"); -} -void FileGenerator::generate_ns_open(google::protobuf::io::Printer *p) { - NamespaceOpener(p, options_.ns).open(); -} -void FileGenerator::generate_ns_close(google::protobuf::io::Printer *p) { - NamespaceOpener(p, options_.ns).close(); -} - -} // namespace compiler - -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/FileGenerator.h b/src/struct_pb/protoc-plugin/FileGenerator.h deleted file mode 100644 index ee4d50212..000000000 --- a/src/struct_pb/protoc-plugin/FileGenerator.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "EnumGenerator.h" -#include "GeneratorBase.h" -#include "MessageGenerator.h" -#include "Options.hpp" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -class FileGenerator : public GeneratorBase { - public: - FileGenerator(const google::protobuf::FileDescriptor *file, Options options); - ; - void generate_header(google::protobuf::io::Printer *p); - void generate_source(google::protobuf::io::Printer *p); - - private: - void generate_shared_header_code(google::protobuf::io::Printer *p); - void generate_fwd_decls(google::protobuf::io::Printer *p); - void generate_enum_definitions(google::protobuf::io::Printer *p); - void generate_message_definitions(google::protobuf::io::Printer *p); - void generate_message_struct_pb_func_definitions( - google::protobuf::io::Printer *p); - void generate_message_struct_pb_func_source(google::protobuf::io::Printer *p); - void generate_dependency_includes(google::protobuf::io::Printer *p); - void generate_ns_open(google::protobuf::io::Printer *p); - void generate_ns_close(google::protobuf::io::Printer *p); - - private: - const google::protobuf::FileDescriptor *file_; - std::vector> message_generators_; - std::vector> enum_generators_; -}; -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/GeneratorBase.cpp b/src/struct_pb/protoc-plugin/GeneratorBase.cpp deleted file mode 100644 index 9f3546680..000000000 --- a/src/struct_pb/protoc-plugin/GeneratorBase.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "GeneratorBase.h" - -#include -namespace struct_pb { -namespace compiler { - -// Convert lowerCamelCase and UpperCamelCase strings to lower_with_underscore. -std::string convert(const std::string &camelCase) { - std::string str(1, tolower(camelCase[0])); - - // First place underscores between contiguous lower and upper case letters. - // For example, `_LowerCamelCase` becomes `_Lower_Camel_Case`. - for (auto it = camelCase.begin() + 1; it != camelCase.end(); ++it) { - if (isupper(*it) && *(it - 1) != '_' && islower(*(it - 1))) { - str += "_"; - } - str += *it; - } - - // Then convert it to lower case. - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - - return str; -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/GeneratorBase.h b/src/struct_pb/protoc-plugin/GeneratorBase.h deleted file mode 100644 index 9341acae5..000000000 --- a/src/struct_pb/protoc-plugin/GeneratorBase.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "Options.hpp" -#include "google/protobuf/descriptor.h" -namespace struct_pb { -namespace compiler { -using namespace google::protobuf; -class GeneratorBase { - public: - GeneratorBase(Options options) : options_(options) {} - - protected: - Options options_; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/MapFieldGenerator.cpp b/src/struct_pb/protoc-plugin/MapFieldGenerator.cpp deleted file mode 100644 index bbf577f4a..000000000 --- a/src/struct_pb/protoc-plugin/MapFieldGenerator.cpp +++ /dev/null @@ -1,298 +0,0 @@ -#include "MapFieldGenerator.h" - -#include "EnumFieldGenerator.h" -#include "MessageFieldGenerator.h" -#include "PrimitiveFieldGenerator.h" -#include "StringFieldGenerator.h" -namespace struct_pb { -namespace compiler { -MapFieldGenerator::MapFieldGenerator(const FieldDescriptor *field, - const Options &options) - : FieldGenerator(field, options) {} - -static std::string get_type_name_help(FieldDescriptor::Type type) { - switch (type) { - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - return "double"; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - return "float"; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - return "int64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - return "uint64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - return "uint32_t"; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - return "int32_t"; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - return "bool"; - case google::protobuf::FieldDescriptor::TYPE_STRING: - case google::protobuf::FieldDescriptor::TYPE_BYTES: - return "std::string"; - case google::protobuf::FieldDescriptor::TYPE_GROUP: - // workaround for group - return "std::string"; - default: { - return "not support now"; - } - } -} -std::string MapFieldGenerator::cpp_type_name() const { - return "std::map<" + get_key_type_name() + ", " + get_value_type_name() + ">"; -} -std::string MapFieldGenerator::get_value_type_name() const { - return get_kv_type_name_helper(d_->message_type()->field(1)); -} -std::string MapFieldGenerator::get_key_type_name() const { - return get_kv_type_name_helper(d_->message_type()->field(0)); -} -std::string MapFieldGenerator::get_kv_type_name_helper( - const FieldDescriptor *f) const { - if (f->type() == FieldDescriptor::TYPE_MESSAGE) { - return qualified_class_name(f->message_type(), options_); - } - else if (f->type() == FieldDescriptor::TYPE_ENUM) { - return qualified_enum_name(f->enum_type(), options_); - } - else { - return get_type_name_help(f->type()); - } -} -void MapFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - generate_calculate_size_only(p, value); -} -void MapFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("for(const auto& e: $1$) {\n", value); - format.indent(); - format("std::size_t map_entry_sz = 0;\n"); - auto key_f = d_->message_type()->field(0); - auto value_f = d_->message_type()->field(1); - generate_calculate_kv_size(p, key_f, "e.first"); - generate_calculate_kv_size(p, value_f, "e.second"); - format("total += $1$ + calculate_varint_size(map_entry_sz) + map_entry_sz;", - calculate_tag_size(d_)); - format.outdent(); - format("}\n"); -} -void MapFieldGenerator::generate_calculate_kv_size( - google::protobuf::io::Printer *p, const FieldDescriptor *f, - const std::string &value) const { - Formatter format(p); - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, {"tag_sz", calculate_tag_size(f)}}, R"( -std::size_t sz = get_needed_size($value$); -map_entry_sz += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - format( - "map_entry_sz += $1$ + calculate_varint_size($2$.size()) + " - "$2$.size();\n", - calculate_tag_size(f), value); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - p->Print({{"tag_sz", calculate_tag_size(f)}}, - R"( -map_entry_sz += $tag_sz$ + )"); - EnumFieldGenerator(f, options_).generate_calculate_size_only(p, value); - format(";\n"); - break; - } - default: { - format("map_entry_sz += $1$ + ", calculate_tag_size(f)); - PrimitiveFieldGenerator(f, options_) - .generate_calculate_size_only(p, value); - format(";\n"); - } - } -} -void MapFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - generate_serialization_only(p, value); -} -void MapFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - auto key_f = d_->message_type()->field(0); - auto value_f = d_->message_type()->field(1); - std::unique_ptr kg; - kg.reset(FieldGeneratorMap::MakeGenerator(key_f, options_)); - std::unique_ptr vg; - kg.reset(FieldGeneratorMap::MakeGenerator(value_f, options_)); - Formatter format(p); - format("for(const auto& e: $1$) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_)); - format("std::size_t map_entry_sz = 0;\n"); - format("{\n"); - format.indent(); - generate_calculate_kv_size(p, key_f, "e.first"); - format.outdent(); - format("}\n"); - format("{\n"); - format.indent(); - generate_calculate_kv_size(p, value_f, "e.second"); - format.outdent(); - format("}\n"); - - format("serialize_varint(data, pos, size, map_entry_sz);\n"); - format("{\n"); - format.indent(); - generate_serialize_kv_only(p, key_f, "e.first"); - format.outdent(); - format("}\n"); - format("{\n"); - format.indent(); - generate_serialize_kv_only(p, value_f, "e.second"); - format.outdent(); - format("}\n"); - - format.outdent(); - format("}\n"); -} -void MapFieldGenerator::generate_serialize_kv_only( - google::protobuf::io::Printer *p, const FieldDescriptor *f, - const std::string &value) const { - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, {"tag", calculate_tag_str(f)}}, R"( -serialize_varint(data, pos, size, $tag$); -std::size_t sz = get_needed_size($value$); -serialize_varint(data, pos, size, sz); -serialize_to(data + pos, sz, $value$); -pos += sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - StringFieldGenerator(f, options_).generate_serialization_only(p, value); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - EnumFieldGenerator(f, options_).generate_serialization_only(p, value); - break; - } - default: { - p->Print({{"tag", calculate_tag_str(f)}}, - R"( -serialize_varint(data, pos, size, $tag$); -)"); - PrimitiveFieldGenerator(f, options_) - .generate_serialization_only(p, value); - } - } -} -void MapFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", calculate_tag_str(d_)}}, - R"( -case $tag$: { - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - std::size_t cur_max_size = pos + sz; -)"); - generate_deserialization_only(p, value); - p->Print(R"( -break; -} -)"); -} -void MapFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - auto key_f = d_->message_type()->field(0); - auto value_f = d_->message_type()->field(1); - Formatter format(p); - format("$1$ key_tmp_val{};\n", get_key_type_name()); - format("$1$ value_tmp_val{};\n", get_value_type_name()); - p->Print( - { - {"key_tag", calculate_tag_str(key_f)}, - }, - R"( -while (pos < cur_max_size) { - ok = read_tag(data, pos, size, tag); - if (!ok) { - return false; - } - switch(tag) { - case $key_tag$: { -)"); - generate_deserialize_kv_only(p, key_f, "key_tmp_val", "cur_max_size"); - p->Print( - { - {"value_tag", calculate_tag_str(value_f)}, - }, - R"( -break; -} -case $value_tag$: { -)"); - generate_deserialize_kv_only(p, value_f, "value_tmp_val", "cur_max_size"); - p->Print({{"value", value}}, R"( -break; - } - - default: { - return false; - } - } -} -$value$[key_tmp_val] = std::move(value_tmp_val); -)"); -} -void MapFieldGenerator::generate_deserialize_kv_only( - google::protobuf::io::Printer *p, const FieldDescriptor *f, - const std::string &value, const std::string &max_size) const { - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, - {"tag", calculate_tag_str(f)}, - {"max_size", max_size}}, - R"( -uint64_t msg_sz = 0; -ok = deserialize_varint(data, pos, $max_size$, msg_sz); -if (!ok) { - return false; -} -ok = deserialize_to($value$, data + pos, msg_sz); -if (!ok) { - return false; -} -pos += msg_sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - StringFieldGenerator(f, options_) - .generate_deserialization_only(p, value, "str_sz", max_size); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - EnumFieldGenerator(f, options_) - .generate_deserialization_only(p, value, max_size); - break; - } - default: { - PrimitiveFieldGenerator(f, options_) - .generate_deserialization_only(p, value); - } - } -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/MapFieldGenerator.h b/src/struct_pb/protoc-plugin/MapFieldGenerator.h deleted file mode 100644 index 04298364d..000000000 --- a/src/struct_pb/protoc-plugin/MapFieldGenerator.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class MapFieldGenerator : public FieldGenerator { - public: - MapFieldGenerator(const FieldDescriptor *field, const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - - private: - void generate_calculate_kv_size(google::protobuf::io::Printer *p, - const FieldDescriptor *f, - const std::string &value) const; - void generate_serialize_kv_only(google::protobuf::io::Printer *p, - const FieldDescriptor *f, - const std::string &value) const; - void generate_deserialize_kv_only(google::protobuf::io::Printer *p, - const FieldDescriptor *f, - const std::string &value, - const std::string &max_size) const; - - private: - std::string get_key_type_name() const; - std::string get_value_type_name() const; - std::string get_kv_type_name_helper(const FieldDescriptor *f) const; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp b/src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp deleted file mode 100644 index 4e61fd35f..000000000 --- a/src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "MessageFieldGenerator.h" - -namespace struct_pb { -namespace compiler { -MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor *field, - const Options &options) - : FieldGenerator(field, options) {} -void MessageFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - if (can_ignore_default_value) { - p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"( -if ($value$) { - auto sz = get_needed_size(*$value$); - total += $tag_sz$ + calculate_varint_size(sz) + sz; -} -)"); - } - else { - p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"( -auto sz = get_needed_size(*$value$); -total += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - } -} -void MessageFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - p->Print({{"value", value}, {"tag", calculate_tag_str(d_)}}, R"( -if ($value$) { - serialize_varint(data, pos, size, $tag$); - auto sz = get_needed_size(*$value$); - serialize_varint(data, pos, size, sz); - serialize_to(data + pos, sz, *$value$); - pos += sz; -} -)"); -} -void MessageFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"value", value}, - {"tag", calculate_tag_str(d_)}, - {"classname", qualified_class_name(d_->message_type(), options_)}}, - R"(case $tag$: { - if (!$value$) { - $value$ = std::make_unique<$classname$>(); - } - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - ok = deserialize_to(*$value$, data + pos, sz); - if (!ok) { - return false; - } - pos += sz; - break; -} -)"); -} -std::string MessageFieldGenerator::cpp_type_name() const { - return "std::unique_ptr<" + - qualified_class_name(d_->message_type(), options_) + ">"; -} - -RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( - const FieldDescriptor *field, const Options &options) - : FieldGenerator(field, options) {} -void RepeatedMessageFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_calculate_size_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_calculate_size_only(p, value); - } -} -void RepeatedMessageFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_serialization_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_serialization_only(p, value); - } -} -void RepeatedMessageFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", std::to_string(calculate_tag(d_))}, - {"value", value}, - {"classname", qualified_class_name(d_->message_type(), options_)}}, - R"(case $tag$: { - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - $value$.emplace_back(); - ok = deserialize_to($value$.back(), data + pos, sz); - if (!ok) { - $value$.pop_back(); - return false; - } - pos += sz; - break; -} -)"); -} -std::string RepeatedMessageFieldGenerator::cpp_type_name() const { - return "std::vector<" + qualified_class_name(d_->message_type(), options_) + - ">"; -} -void RepeatedMessageFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"( -for(const auto& e: $value$) { - std::size_t sz = get_needed_size(e); - total += $tag_sz$ + calculate_varint_size(sz) + sz; -} -)"); -} -void RepeatedMessageFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", std::to_string(calculate_tag(d_))}, {"value", value}}, R"( -for(const auto& e: $value$) { - serialize_varint(data, pos, size, $tag$); - std::size_t sz = get_needed_size(e); - serialize_varint(data, pos, size, sz); - serialize_to(data+pos, sz, e); - pos += sz; -} -)"); -} - -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/MessageFieldGenerator.h b/src/struct_pb/protoc-plugin/MessageFieldGenerator.h deleted file mode 100644 index 12937b3db..000000000 --- a/src/struct_pb/protoc-plugin/MessageFieldGenerator.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class MessageFieldGenerator : public FieldGenerator { - public: - MessageFieldGenerator(const FieldDescriptor *field, const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - std::string cpp_type_name() const override; -}; -class RepeatedMessageFieldGenerator : public FieldGenerator { - public: - RepeatedMessageFieldGenerator(const FieldDescriptor *field, - const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - std::string cpp_type_name() const override; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/MessageGenerator.cpp b/src/struct_pb/protoc-plugin/MessageGenerator.cpp deleted file mode 100644 index 0fd3a11ea..000000000 --- a/src/struct_pb/protoc-plugin/MessageGenerator.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "MessageGenerator.h" - -#include "EnumGenerator.h" -#include "FieldGenerator.h" -#include "helpers.hpp" -using namespace google::protobuf; -using namespace google::protobuf::internal; -namespace struct_pb { -namespace compiler { -std::unordered_map ClassVars( - const Descriptor *descriptor, Options options) { - std::unordered_map vars{}; - vars.emplace("classname", resolve_keyword(descriptor->name())); - vars.emplace("classtype", qualified_class_name(descriptor, options)); - return vars; -} -// copy from cpp compiler -static std::string UnderscoresToCamelCase(const std::string &input, - bool cap_next_letter) { - std::string result; - // Note: I distrust ctype.h due to locales. - for (int i = 0; i < input.size(); i++) { - if ('a' <= input[i] && input[i] <= 'z') { - if (cap_next_letter) { - result += input[i] + ('A' - 'a'); - } - else { - result += input[i]; - } - cap_next_letter = false; - } - else if ('A' <= input[i] && input[i] <= 'Z') { - // Capital letters are left as-is. - result += input[i]; - cap_next_letter = false; - } - else if ('0' <= input[i] && input[i] <= '9') { - result += input[i]; - cap_next_letter = true; - } - else { - cap_next_letter = true; - } - } - return result; -} - -void MessageGenerator::generate_struct_definition( - google::protobuf::io::Printer *p) { - // auto v = p->WithVars(ClassVars(d_, options_)); - Formatter format(p); - format("struct $1$ {\n", resolve_keyword(d_->name())); - format.indent(); - for (int i = 0; i < d_->enum_type_count(); ++i) { - auto e = d_->enum_type(i); - EnumGenerator(e, options_).generate_definition(p); - } - for (int i = 0; i < d_->oneof_decl_count(); ++i) { - auto oneof = d_->oneof_decl(i); - std::string enum_name = UnderscoresToCamelCase(oneof->name(), true); - format("enum class $1$Case {\n", enum_name); - format.indent(); - format("none = 0,\n"); - for (int j = 0; j < oneof->field_count(); ++j) { - auto f = oneof->field(j); - format("$1$ = $2$,\n", resolve_keyword(f->name()), f->number()); - } - format.outdent(); - format("};\n"); - format("$1$Case $2$_case() const {\n", enum_name, oneof->name()); - format.indent(); - format("switch ($1$.index()) {\n", resolve_keyword(oneof->name())); - format.indent(); - for (int j = 0; j < oneof->field_count(); ++j) { - format("case $1$:\n", j + 1); - format.indent(); - format("return $1$Case::$2$;\n", enum_name, - resolve_keyword(oneof->field(j)->name())); - format.outdent(); - } - format("default:\n"); - format.indent(); - format("return $1$Case::none;\n", enum_name); - format.outdent(); - - format.outdent(); - format("}\n"); - format.outdent(); - format("}\n"); - format("\n"); - } - for (int i = 0; i < d_->nested_type_count(); ++i) { - auto t = d_->nested_type(i); - auto name = t->name(); - if (is_map_entry(t)) { - continue; - } - MessageGenerator(t, options_).generate_struct_definition(p); - } - std::set oneof_set; - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - auto oneof = f->containing_oneof(); - if (oneof) { - if (oneof_set.find(oneof) == oneof_set.end()) { - OneofGenerator(oneof, options_).generate_definition(p); - oneof_set.insert(oneof); - } - else { - continue; - } - } - else { - fg_map_.get(f).generate_definition(p); - } - } - if (options_.generate_eq_op) { - format("bool operator==(const $1$&) const = default;\n", class_name(d_)); - } - // format("std::size_t get_needed_size() const;\n"); - // format("std::string SerializeAsString() const;\n"); - // format("bool ParseFromArray(const char* data, std::size_t size);\n"); - format.outdent(); - format("};\n"); -} -void MessageGenerator::generate_source(google::protobuf::io::Printer *p) { - generate_get_needed_size(p); - Formatter format(p); - format("std::string $1$::SerializeAsString() const {\n", d_->name()); - format.indent(); - format("std::string buffer;\n"); - format("// calculate buffer size\n"); - format("std::size_t total = get_needed_size();\n"); - format("std::size_t pos = 0;\n"); - format("buffer.resize(total);\n"); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - // FieldGenerator(f, options_).generate_calculate_size(p); - } - format("return buffer;\n"); - format.outdent(); - format("}\n"); -} -void MessageGenerator::generate_get_needed_size( - google::protobuf::io::Printer *p) { - Formatter format(p); - format("std::size_t total = unknown_fields.total_size();\n"); - std::set oneof_set; - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - fg_map_.get(f).generate_calculate_size(p, true); - } - format("return total;\n"); -} -void MessageGenerator::generate_serialize_to(google::protobuf::io::Printer *p) { - Formatter format(p); - format("std::size_t pos = 0;\n"); - std::vector fs; - fs.reserve(d_->field_count()); - for (int i = 0; i < d_->field_count(); ++i) { - fs.push_back(d_->field(i)); - } - std::sort(fs.begin(), fs.end(), - [](const FieldDescriptor *lhs, const FieldDescriptor *rhs) { - return lhs->number() < rhs->number(); - }); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = fs[i]; - format("{\n"); - format.indent(); - fg_map_.get(f).generate_serialization(p, true); - format.outdent(); - format("}\n"); - } - format("unknown_fields.serialize_to(data, pos, size);\n"); -} -void MessageGenerator::generate_deserialize_to( - google::protobuf::io::Printer *p) { - Formatter format(p); - format("std::size_t pos = 0;\n"); - format("bool ok = false;\n"); - format("while (pos < size) {\n"); - format.indent(); - p->Print(R"(uint64_t tag = 0; -ok = read_tag(data, pos, size, tag); -if (!ok) { - return false; -} -switch(tag) { -)"); - format.indent(); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - fg_map_.get(f).generate_deserialization(p); - } - format("default: {\n"); - format.indent(); - format("ok = deserialize_unknown(data, pos, size, tag, unknown_fields);\n"); - format("return ok;\n"); - format.outdent(); - format("}\n"); - format.outdent(); - format("}\n"); - - format.outdent(); - format("}\n"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/MessageGenerator.h b/src/struct_pb/protoc-plugin/MessageGenerator.h deleted file mode 100644 index 49e4b42b8..000000000 --- a/src/struct_pb/protoc-plugin/MessageGenerator.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -#include "GeneratorBase.h" -namespace struct_pb { -namespace compiler { -class FileGenerator; -class MessageGenerator : public GeneratorBase { - public: - MessageGenerator(const google::protobuf::Descriptor *d, Options options) - : GeneratorBase(options), d_(d), fg_map_(d, options) {} - - void generate(google::protobuf::io::Printer *p); - void generate_struct_definition(google::protobuf::io::Printer *p); - void generate_source(google::protobuf::io::Printer *p); - - private: - void generate_get_needed_size(google::protobuf::io::Printer *p); - void generate_serialize_to(google::protobuf::io::Printer *p); - void generate_deserialize_to(google::protobuf::io::Printer *p); - - private: - const google::protobuf::Descriptor *d_; - std::vector field_name_list; - std::vector unpack_index_list; - std::vector field_number_list; - std::map n2i_map; - std::map i2n_map; - FieldGeneratorMap fg_map_; - friend class FileGenerator; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp b/src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp deleted file mode 100644 index 89516f20d..000000000 --- a/src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "OneofFieldGenerator.h" - -#include "EnumFieldGenerator.h" -#include "PrimitiveFieldGenerator.h" -#include "StringFieldGenerator.h" -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -void OneofFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - format("if ($1$.index() == $2$) {\n", value, index()); - generate_calculate_size_only(p, value); - format("\n}\n"); -} -std::string OneofFieldGenerator::index() const { - auto oneof = d_->containing_oneof(); - assert(oneof); - int index = 0; - for (int i = 0; i < oneof->field_count(); ++i) { - if (oneof->field(i) == d_) { - index = i + 1; - break; - } - } - assert(index > 0); - return std::to_string(index); -} -void OneofFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - auto oneof_value = "std::get<" + index() + ">(" + value + ")"; - - switch (d_->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"tag_sz", calculate_tag_size(d_)}, - {"index", index()}, - {"oneof_value", oneof_value}, - {"value", value}}, - R"( -uint64_t sz = 0; -if ($oneof_value$) { - sz = get_needed_size(*$oneof_value$); -} -total += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -total += $tag_sz$ + calculate_varint_size()"); - StringFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - p->Print(") + "); - - StringFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - p->Print(";\n"); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - format("total += $1$ + ", calculate_tag_size(d_)); - EnumFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - format(";\n"); - break; - } - default: { - format("total += $1$ + ", calculate_tag_size(d_)); - PrimitiveFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - format(";\n"); - } - } -} -void OneofFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - format("if ($1$.index() == $2$) {\n", value, index()); - generate_serialization_only(p, value); - format("\n}\n"); -} -void OneofFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - auto oneof_value = "std::get<" + index() + ">(" + value + ")"; - - switch (d_->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, - {"tag", std::to_string(calculate_tag(d_))}, - {"index", index()}, - {"oneof_value", oneof_value} - - }, - R"( -serialize_varint(data, pos, size, $tag$); -if ($oneof_value$) { - std::size_t sz = get_needed_size(*$oneof_value$); - serialize_varint(data, pos, size, sz); - serialize_to(data + pos, sz, *$oneof_value$); - pos += sz; -} -else { - serialize_varint(data, pos, size, 0); -} -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - StringFieldGenerator(d_, options_) - .generate_serialization_only(p, oneof_value); - - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - EnumFieldGenerator(d_, options_) - .generate_serialization_only(p, oneof_value); - break; - } - default: { - p->Print({{"tag", calculate_tag_str(d_)}}, - R"( -serialize_varint(data, pos, size, $tag$); -)"); - PrimitiveFieldGenerator(d_, options_) - .generate_serialization_only(p, oneof_value); - } - } -} -void OneofFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - generate_deserialization_only(p, value); - format("break;\n"); - format("}\n"); -} -void OneofFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &max_size) const { - Formatter format(p); - std::string oneof_value = "std::get<" + index() + ">(" + value + ")"; - - switch (d_->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print( - {{"value", value}, - {"type_name", qualified_class_name(d_->message_type(), options_)}, - {"tag", std::to_string(calculate_tag(d_))}, - {"max_size", max_size}, - {"oneof_value", oneof_value}, - {"index", index()}}, - - R"( -if ($value$.index() != $index$) { - $value$.emplace<$index$>(new $type_name$()); -} -uint64_t msg_sz = 0; -ok = deserialize_varint(data, pos, $max_size$, msg_sz); -if (!ok) { - return false; -} -ok = deserialize_to(*$oneof_value$, data + pos, msg_sz); -if (!ok) { - return false; -} -pos += msg_sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - format("if ($1$.index() != $2$) {\n", value, index()); - format.indent(); - format("$1$.emplace<$2$>();\n", value, index()); - format.outdent(); - format("}\n"); - StringFieldGenerator(d_, options_) - .generate_deserialization_only(p, oneof_value, "str_sz", max_size); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - format("if ($1$.index() != $2$) {\n", value, index()); - format.indent(); - format("$1$.emplace<$2$>();\n", value, index()); - format.outdent(); - format("}\n"); - EnumFieldGenerator(d_, options_) - .generate_deserialization_only(p, oneof_value, max_size); - break; - } - default: { - format("if ($1$.index() != $2$) {\n", value, index()); - format.indent(); - format("$1$.emplace<$2$>();\n", value, index()); - format.outdent(); - format("}\n"); - PrimitiveFieldGenerator(d_, options_) - .generate_deserialization_only(p, oneof_value); - } - } -} -std::string OneofFieldGenerator::cpp_type_name() const { - return "std::variant"; -} -std::string OneofFieldGenerator::pb_type_name() const { - return d_->type_name(); -} -OneofFieldGenerator::OneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options) - : FieldGenerator(descriptor, options) {} - -MessageOneofFieldGenerator::MessageOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} - -void MessageOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - type_name = qualified_class_name(d_->message_type(), options_); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_allocated_$name$($type_name$* p) { - assert(p); - $field_name$.emplace<$index$>(p); -} -const std::unique_ptr<$type_name$>& $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} -void PrimitiveOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_$name$($type_name$ $name$) { - $field_name$.emplace<$index$>($name$); -} -$type_name$ $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -StringOneofFieldGenerator::StringOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} -void StringOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_$name$($type_name$ $name$) { - $field_name$.emplace<$index$>(std::move($name$)); -} -const $type_name$& $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -EnumOneofFieldGenerator::EnumOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} -void EnumOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - type_name = qualified_enum_name(d_->enum_type(), options_); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_allocated_$name$($type_name$ p) { - $field_name$.emplace<$index$>(p); -} -$type_name$ $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/OneofFieldGenerator.h b/src/struct_pb/protoc-plugin/OneofFieldGenerator.h deleted file mode 100644 index 8d936d94f..000000000 --- a/src/struct_pb/protoc-plugin/OneofFieldGenerator.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class OneofFieldGenerator : public FieldGenerator { - public: - OneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &max_size = "size") const; - std::string cpp_type_name() const override; - std::string pb_type_name() const override; - virtual void generate_setter_and_getter(google::protobuf::io::Printer *p){}; - - protected: - std::string index() const; -}; - -class MessageOneofFieldGenerator : public OneofFieldGenerator { - public: - MessageOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -class StringOneofFieldGenerator : public OneofFieldGenerator { - public: - StringOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -class EnumOneofFieldGenerator : public OneofFieldGenerator { - public: - EnumOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -class PrimitiveOneofFieldGenerator : public OneofFieldGenerator { - public: - PrimitiveOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/Options.hpp b/src/struct_pb/protoc-plugin/Options.hpp deleted file mode 100644 index 024e1f8c7..000000000 --- a/src/struct_pb/protoc-plugin/Options.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include - -#include "google/protobuf/descriptor.h" -struct Options { - Options(const google::protobuf::FileDescriptor* f) : f(f) {} - bool generate_eq_op = false; - std::string ns; - const google::protobuf::FileDescriptor* f; -}; \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp b/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp deleted file mode 100644 index 7966a7401..000000000 --- a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp +++ /dev/null @@ -1,453 +0,0 @@ -#include "PrimitiveFieldGenerator.h" - -namespace struct_pb { -namespace compiler { -std::string get_type_name_help(FieldDescriptor::Type type) { - switch (type) { - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - return "double"; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - return "float"; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - return "int64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - return "uint64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - return "uint32_t"; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - return "int32_t"; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - return "bool"; - default: { - // can't reach, dead path - return "not support"; - } - } -} -PrimitiveFieldGenerator::PrimitiveFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : FieldGenerator(descriptor, options) {} -void PrimitiveFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value + ".value()"); - format(";\n"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if ($1$ != 0) {\n", value); - format.indent(); - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value); - format(";\n"); - format.outdent(); - format("}\n"); - } - else { - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value); - format(";\n"); - } - } -} -void PrimitiveFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - if (is_varint(d_)) { - if (is_sint(d_)) { - format("calculate_varint_size(encode_zigzag($1$))", value); - } - else if (is_bool(d_)) { - format("calculate_varint_size(static_cast($1$))", value); - } - else { - format("calculate_varint_size($1$)", value); - } - } - else if (is_i64(d_)) { - format("8"); - } - else if (is_i32(d_)) { - format("4"); - } -} - -std::string PrimitiveFieldGenerator::cpp_type_name() const { - std::string type_name = get_type_name_help(d_->type()); - if (is_optional()) { - type_name = "std::optional<" + type_name + ">"; - } - return type_name; -} -void PrimitiveFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_)); - generate_serialization_only(p, value + ".value()"); - format("\n"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if ($1$ != 0) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_serialization_only(p, value); - format("\n"); - format.outdent(); - format("}\n"); - } - else { - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_serialization_only(p, value); - } - } -} -void PrimitiveFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - if (is_varint(d_)) { - if (is_sint(d_)) { - format("serialize_varint(data, pos, size, encode_zigzag($1$));", value); - } - else if (is_bool(d_)) { - format("serialize_varint(data, pos, size, static_cast($1$));", - value); - } - else { - if (d_->cpp_type() != FieldDescriptor::CPPTYPE_UINT64) { - format("serialize_varint(data, pos, size, static_cast($1$));", - value); - } - else { - format("serialize_varint(data, pos, size, $1$);", value); - } - } - } - else if (is_i64(d_) || is_i32(d_)) { - std::size_t sz = is_i64(d_) ? 8 : 4; - p->Print({{"value", value}, {"sz", std::to_string(sz)}}, R"( -std::memcpy(data + pos, &$value$, $sz$); -pos += $sz$; -)"); - } -} -void PrimitiveFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - format.indent(); - generate_deserialization_only(p, value); - format("break;\n"); - format.outdent(); - format("}\n"); -} -void PrimitiveFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size) const { - if (is_varint(d_)) { - p->Print({{"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -uint64_t varint_tmp = 0; -ok = deserialize_varint(data, pos, $max_size$, varint_tmp); -if (!ok) { - return false; -} -)"); - if (is_sint(d_)) { - if (is_sint32(d_)) { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = static_cast<$type_name$>(decode_zigzag(uint32_t(varint_tmp))); -)"); - } - else { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = static_cast<$type_name$>(decode_zigzag(varint_tmp)); -)"); - } - } - else if (is_bool(d_)) { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = static_cast<$type_name$>(varint_tmp); -)"); - } - else { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = varint_tmp; -)"); - } - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}, - {"sz", std::to_string(sz)}}, - R"( -if (pos + $sz$ > $max_size$) { - return false; -} -$type_name$ fixed_tmp = 0; -std::memcpy(&fixed_tmp, data + pos, $sz$); -pos += $sz$; -$output$ = fixed_tmp; -)"); - } -} -RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : FieldGenerator(descriptor, options) {} -void RepeatedPrimitiveFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - PrimitiveFieldGenerator g(d_, options_); - if (is_packed()) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_calculate_packed_size_only(p, value); - format( - "total += $1$ + calculate_varint_size(container_total) + " - "container_total;\n", - calculate_tag_size(d_)); - format.outdent(); - format("}\n"); - } - else { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_calculate_unpacked_size_only(p, value); - format("total += container_total;\n"); - format.outdent(); - format("}\n"); - } -} -bool RepeatedPrimitiveFieldGenerator::is_packed() const { - return d_->is_packable() && d_->is_packed(); -} -std::string RepeatedPrimitiveFieldGenerator::cpp_type_name() const { - return "std::vector<" + get_type_name_help(d_->type()) + ">"; -} -void RepeatedPrimitiveFieldGenerator::generate_calculate_packed_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - PrimitiveFieldGenerator g(d_, options_); - if (is_varint(d_)) { - p->Print({{"value", value}}, - R"( -std::size_t container_total = 0; -for(const auto& e: $value$) { - container_total += )"); - g.generate_calculate_size_only(p, "e"); - format(";\n"); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print({{"sz", std::to_string(sz)}, {"value", value}}, R"( -std::size_t container_total = $sz$ * $value$.size(); -)"); - } -} -void RepeatedPrimitiveFieldGenerator::generate_calculate_unpacked_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - PrimitiveFieldGenerator g(d_, options_); - Formatter format(p); - if (is_varint(d_)) { - p->Print({{"value", value}, {"tag_sz", calculate_tag_size(d_, true)}}, - R"( -std::size_t container_total = 0; -for(const auto& e: $value$) { - container_total += $tag_sz$; - container_total += )"); - g.generate_calculate_size_only(p, "e"); - format(";\n"); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print({{"sz", std::to_string(sz)}, - {"value", value}, - {"tag_sz", calculate_tag_size(d_, true)}}, - R"( -std::size_t container_total = ($tag_sz$ + $sz$) * $value$.size(); -)"); - } -} -void RepeatedPrimitiveFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - PrimitiveFieldGenerator g(d_, options_); - Formatter format(p); - if (is_packed()) { - if (is_varint(d_)) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_calculate_packed_size_only(p, value); - format("serialize_varint(data, pos, size, container_total);\n"); - format("for(const auto& v: $1$) {\n", value); - format.indent(); - g.generate_serialization_only(p, "v"); - format.outdent(); - format("}\n"); - format.outdent(); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_calculate_packed_size_only(p, value); - format("serialize_varint(data, pos, size, container_total);\n"); - format("std::memcpy(data + pos, $1$.data(), container_total);\n", value); - format.outdent(); - format("}\n"); - } - } - else { - format("for(const auto& v: $1$) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_, true)); - g.generate_serialization_only(p, "v"); - format.outdent(); - format("}\n"); - } -} -void RepeatedPrimitiveFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", unpacked_tag()); - format.indent(); - format("$1$ e{};\n", get_type_name_help(d_->type())); - generate_deserialization_unpacked_only(p, "e"); - format("$1$.push_back(e);\n", value); - format("break;\n"); - format.outdent(); - format("}\n"); - - format("case $1$: {\n", packed_tag()); - format.indent(); - format("uint64_t sz = 0;\n"); - format("ok = deserialize_varint(data, pos, size, sz);\n"); - format("if (!ok) {\n"); - format.indent(); - format("return false;\n"); - format.outdent(); - format("}\n"); - format("std::size_t cur_max_size = pos + sz;\n"); - generate_deserialization_packed_only(p, value, "cur_max_size"); - format("break;\n"); - format.outdent(); - format("}\n"); -} -void RepeatedPrimitiveFieldGenerator::generate_deserialization_packed_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &max_size) const { - if (is_varint(d_)) { - Formatter format(p); - format("while (pos < $1$) {\n", max_size); - format.indent(); - format("$1$ e{};\n", get_type_name_help(d_->type())); - PrimitiveFieldGenerator g(d_, options_); - g.generate_deserialization_only(p, "e"); - format("$1$.push_back(e);\n", value); - format.outdent(); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print({{"value", value}, {"sz", std::to_string(sz)}}, R"( -int count = sz / $sz$; -if ($sz$ * count != sz) { - return false; -} -if (pos + sz > size) { - return false; -} -$value$.resize(count); -std::memcpy($value$.data(), data + pos, sz); -pos += sz; -)"); - } -} -std::string RepeatedPrimitiveFieldGenerator::packed_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 2; - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -std::string RepeatedPrimitiveFieldGenerator::unpacked_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 0; - if (is_varint(d_)) { - wire_type = 0; - } - else if (is_i64(d_)) { - wire_type = 1; - } - else if (is_i32(d_)) { - wire_type = 5; - } - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -void RepeatedPrimitiveFieldGenerator::generate_deserialization_unpacked_only( - google::protobuf::io::Printer *p, const std::string &output) const { - PrimitiveFieldGenerator g(d_, options_); - g.generate_deserialization_only(p, output); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h b/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h deleted file mode 100644 index fa06991fd..000000000 --- a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -#include "google/protobuf/descriptor.h" -namespace struct_pb { -namespace compiler { -using namespace google::protobuf; -class PrimitiveFieldGenerator : public FieldGenerator { - public: - PrimitiveFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - PrimitiveFieldGenerator(const PrimitiveFieldGenerator &) = delete; - PrimitiveFieldGenerator &operator=(const PrimitiveFieldGenerator &) = delete; - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size = "size") const; -}; -class RepeatedPrimitiveFieldGenerator : public FieldGenerator { - public: - RepeatedPrimitiveFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value = {}, - bool can_ignore_default_value = true) const override; - void generate_calculate_packed_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_calculate_unpacked_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_packed_only(google::protobuf::io::Printer *p, - const std::string &value, - const std::string &max_size) const; - void generate_deserialization_unpacked_only(google::protobuf::io::Printer *p, - const std::string &output) const; - - private: - bool is_packed() const; - std::string packed_tag() const; - std::string unpacked_tag() const; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/StringFieldGenerator.cpp b/src/struct_pb/protoc-plugin/StringFieldGenerator.cpp deleted file mode 100644 index 5d7c5aee1..000000000 --- a/src/struct_pb/protoc-plugin/StringFieldGenerator.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "StringFieldGenerator.h" - -namespace struct_pb { -namespace compiler { -StringFieldGenerator::StringFieldGenerator(const FieldDescriptor *field, - const Options &options) - : FieldGenerator(field, options) {} -void StringFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("$1$.size()", value); -} -void StringFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - auto tag_sz = calculate_tag_size(d_); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("total += $1$ + calculate_varint_size($2$->size()) + $2$->size();\n", - tag_sz, value); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - format("total += $1$ + calculate_varint_size($2$.size()) + $2$.size();\n", - tag_sz, value); - format.outdent(); - format("}\n"); - } - else { - format("total += $1$ + calculate_varint_size($2$.size()) + $2$.size();\n", - tag_sz, value); - } - } -} -void StringFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - generate_serialization_only(p, value + ".value()"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_serialization_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_serialization_only(p, value); - } - } -} -void StringFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_)); - format("serialize_varint(data, pos, size, $1$.size());\n", value); - format("std::memcpy(data + pos, $1$.data(), $1$.size());\n", value); - format("pos += $1$.size();\n", value); -} -std::string StringFieldGenerator::cpp_type_name() const { - if (d_->has_presence()) { - return "std::optional"; - } - return "std::string"; -} -void StringFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &sz, const std::string &max_size) const { - p->Print({{"output", output}, {"sz", sz}, {"max_size", max_size}}, - R"(uint64_t $sz$ = 0; -ok = deserialize_varint(data, pos, $max_size$, $sz$); -if (!ok) { - return false; -} -$output$.resize($sz$); -if (pos + $sz$ > $max_size$) { - return false; -} -std::memcpy($output$.data(), data+pos, $sz$); -pos += $sz$; -)"); -} -void StringFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - format.indent(); - if (is_optional()) { - format("if (!$1$.has_value()) {\n", value); - format.indent(); - format("$1$ = std::string();\n", value); - format.outdent(); - format("}\n"); - generate_deserialization_only(p, value + ".value()"); - } - else { - generate_deserialization_only(p, value); - } - format("break;\n"); - format.outdent(); - format("}\n"); -} -RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( - const FieldDescriptor *field, const Options &options) - : FieldGenerator(field, options) {} -std::string RepeatedStringFieldGenerator::cpp_type_name() const { - return "std::vector"; -} -void RepeatedStringFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - format("for (const auto& s: $1$) {\n", value); - format.indent(); - format("total += $1$ + calculate_varint_size(s.size()) + s.size();\n", - calculate_tag_size(d_)); - format.outdent(); - format("}\n"); -} -void RepeatedStringFieldGenerator::generate_calculate_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &output) const { - p->Print({{"value", value}, - {"tag_sz", calculate_tag_size(d_)}, - {"output", output}}, - R"( -std::size_t $output$ = 0; -for (const auto& s: $value$) { - $output$ += $tag_sz$ + calculate_varint_size(s.size()) + s.size(); -} -)"); -} -void RepeatedStringFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_serialization_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_serialization_only(p, value); - } -} -void RepeatedStringFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("for(const auto& s: $1$) {\n", value); - format.indent(); - StringFieldGenerator g(d_, options_); - g.generate_serialization_only(p, "s"); - format.outdent(); - format("}\n"); -} -void RepeatedStringFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - StringFieldGenerator g(d_, options_); - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - format.indent(); - format("std::string tmp_str;\n"); - g.generate_deserialization_only(p, "tmp_str"); - format("$1$.push_back(std::move(tmp_str));\n", value); - format("break;\n"); - format.outdent(); - format("}\n"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/StringFieldGenerator.h b/src/struct_pb/protoc-plugin/StringFieldGenerator.h deleted file mode 100644 index 3d1fdc3e1..000000000 --- a/src/struct_pb/protoc-plugin/StringFieldGenerator.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class StringFieldGenerator : public FieldGenerator { - public: - StringFieldGenerator(const FieldDescriptor *field, const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value = {}) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &sz = "sz", const std::string &max_size = "size") const; -}; -class RepeatedStringFieldGenerator : public FieldGenerator { - public: - RepeatedStringFieldGenerator(const FieldDescriptor *field, - const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_only(google::protobuf::io::Printer *p, - const std::string &value, - const std::string &output) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - std::string cpp_type_name() const override; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/StructGenerator.cpp b/src/struct_pb/protoc-plugin/StructGenerator.cpp deleted file mode 100644 index 3eafc68c0..000000000 --- a/src/struct_pb/protoc-plugin/StructGenerator.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "StructGenerator.h" - -#include - -#include "FileGenerator.h" -#include "Options.hpp" -#include "google/protobuf/descriptor.pb.h" -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -bool StructGenerator::Generate( - const google::protobuf::FileDescriptor *file, const std::string ¶meter, - google::protobuf::compiler::GeneratorContext *generator_context, - std::string *error) const { - std::vector> options; - google::protobuf::compiler::ParseGeneratorParameter(parameter, &options); - Options struct_pb_options(file); - for (const auto &option : options) { - const auto &key = option.first; - const auto &value = option.second; - if (key == "generate_eq_op") { - struct_pb_options.generate_eq_op = true; - } - else if (key == "namespace") { - struct_pb_options.ns = value; - } - else { - *error = "Unknown generator option: " + key; - return false; - } - } - if (struct_pb_options.ns.empty()) { - struct_pb_options.ns = file->package(); - } - auto basename = strip_proto(file->name()); - FileGenerator file_generator(file, struct_pb_options); - // generate xxx.struct_pb.h - { - std::unique_ptr output( - generator_context->Open(basename + ".struct_pb.h")); - google::protobuf::io::Printer p(output.get(), '$'); - p.Print({{"parameter", parameter}}, R"(// protoc generate parameter -// clang-format off -// $parameter$ -// ========================= -#pragma once - -)"); - file_generator.generate_header(&p); - } - // generate xxx.struct_pb.cc - { - std::unique_ptr output( - generator_context->Open(basename + ".struct_pb.cc")); - google::protobuf::io::Printer p(output.get(), '$'); - p.Print( - {{"parameter", parameter}, {"header_file", basename + ".struct_pb.h"}}, - R"(// protoc generate parameter -// clang-format off -// $parameter$ -// ========================= -#include "$header_file$" -#include "ylt/struct_pb/struct_pb_impl.hpp" -)"); - Formatter format(&p); - file_generator.generate_source(&p); - } - return true; -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/StructGenerator.h b/src/struct_pb/protoc-plugin/StructGenerator.h deleted file mode 100644 index f8748d975..000000000 --- a/src/struct_pb/protoc-plugin/StructGenerator.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include -namespace struct_pb { -namespace compiler { - -class StructGenerator : public google::protobuf::compiler::CodeGenerator { - public: - bool Generate(const google::protobuf::FileDescriptor *file, - const std::string ¶meter, - google::protobuf::compiler::GeneratorContext *generator_context, - std::string *error) const override; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/helpers.cpp b/src/struct_pb/protoc-plugin/helpers.cpp deleted file mode 100644 index e67fd4c60..000000000 --- a/src/struct_pb/protoc-plugin/helpers.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "helpers.hpp" - -#include -#include - -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -// https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string -template -void split(const std::string &s, char delim, Out result) { - std::istringstream iss(s); - std::string item; - while (std::getline(iss, item, delim)) { - *result++ = item; - } -} - -static std::vector split(const std::string &s, char delim) { - std::vector elems; - split(s, delim, std::back_inserter(elems)); - return elems; -} -NamespaceOpener::NamespaceOpener(google::protobuf::io::Printer *p, - const std::string &package) - : p_(p) { - ns_ = split(package, '.'); -} -NamespaceOpener::~NamespaceOpener() {} -void NamespaceOpener::open() const { - for (const auto &ns : ns_) { - p_->Print({{"ns", ns}}, R"( -namespace $ns$ { -)"); - } -} -void NamespaceOpener::close() const { - for (int i = 0; i < ns_.size(); ++i) { - auto ns = ns_[ns_.size() - i - 1]; - p_->Print({{"ns", ns}}, R"( -} // namespace $ns$ -)"); - } -} -// from std::string_view ends_with -bool string_ends_with(std::string_view s, std::string_view suffix) { - return s.size() >= suffix.size() && - s.compare(s.size() - suffix.size(), std::string_view::npos, suffix) == - 0; -} -std::string_view string_strip_suffix(const std::string_view s, - const std::string_view suffix) { - if (string_ends_with(s, suffix)) { - return s.substr(0, s.size() - suffix.size()); - } - return s; -} -std::string strip_proto(const std::string &filename) { - if (string_ends_with(filename, ".protodevel")) { - return std::string(string_strip_suffix(filename, ".protodevel")); - } - else { - return std::string(string_strip_suffix(filename, ".proto")); - } -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/helpers.hpp b/src/struct_pb/protoc-plugin/helpers.hpp deleted file mode 100644 index ac3f1dee7..000000000 --- a/src/struct_pb/protoc-plugin/helpers.hpp +++ /dev/null @@ -1,279 +0,0 @@ -#pragma once -#include -#include -#include - -#include "Options.hpp" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -using namespace google::protobuf; -using namespace google::protobuf::compiler; - -inline bool is_map_entry(const google::protobuf::Descriptor *descriptor) { - return descriptor->options().map_entry(); -} - -void flatten_messages_in_file( - const google::protobuf::FileDescriptor *file, - std::vector *result); -inline std::vector -flatten_messages_in_file(const google::protobuf::FileDescriptor *file) { - std::vector ret; - flatten_messages_in_file(file, &ret); - return ret; -} -template -void for_each_message(const google::protobuf::Descriptor *descriptor, - F &&func) { - for (int i = 0; i < descriptor->nested_type_count(); ++i) { - for_each_message(descriptor->nested_type(i), std::forward(func)); - } - func(descriptor); -} - -template -void for_each_message(const google::protobuf::FileDescriptor *descriptor, - F &&func) { - for (int i = 0; i < descriptor->message_type_count(); ++i) { - for_each_message(descriptor->message_type(i), std::forward(func)); - } -} - -inline void flatten_messages_in_file( - const google::protobuf::FileDescriptor *file, - std::vector *result) { - for (int i = 0; i < file->message_type_count(); ++i) { - for_each_message(file->message_type(i), - [&](const google::protobuf::Descriptor *descriptor) { - if (is_map_entry(descriptor)) { - return; - } - result->push_back(descriptor); - }); - } -} -inline std::string resolve_keyword(const std::string &name) { - // clang-format off - static std::set keyword_set{ - // - "NULL", - "alignas", - "alignof", - "and", - "and_eq", - "asm", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "class", - "compl", - "const", - "constexpr", - "const_cast", - "continue", - "decltype", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "inline", - "int", - "long", - "mutable", - "namespace", - "new", - "noexcept", - "not", - "not_eq", - "nullptr", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "return", - "short", - "signed", - "sizeof", - "static", - "static_assert", - "static_cast", - "struct", - "switch", - "template", - "this", - "thread_local", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq", - "char8_t", - "char16_t", - "char32_t", - "concept", - "consteval", - "constinit", - "co_await", - "co_return", - "co_yield", - "requires", - // typedef - "uint32_t", - "int32_t", - "uint64_t", - "int64_t", - "size_t", - "memset" - }; - // clang-format on - auto it = keyword_set.find(name); - if (it == keyword_set.end()) { - return name; - } - return name + "_"; -} -inline std::string class_name(const google::protobuf::Descriptor *descriptor) { - // assert(descriptor); - auto parent = descriptor->containing_type(); - std::string ret; - if (parent) { - ret += class_name(parent) + "::"; - } - ret += resolve_keyword(descriptor->name()); - return resolve_keyword(ret); -} -inline std::string enum_name( - const google::protobuf::EnumDescriptor *descriptor) { - auto parent = descriptor->containing_type(); - std::string ret; - if (parent) { - ret += class_name(parent) + "::"; - } - ret += resolve_keyword(descriptor->name()); - return resolve_keyword(ret); -} -// https://stackoverflow.com/questions/2896600/how-to-replace-all-occurrences-of-a-character-in-string -inline std::string ReplaceAll(std::string str, const std::string &from, - const std::string &to) { - size_t start_pos = 0; - while ((start_pos = str.find(from, start_pos)) != std::string::npos) { - str.replace(start_pos, from.length(), to); - start_pos += - to.length(); // Handles case where 'to' is a substring of 'from' - } - return str; -} -inline std::string dots_to_colons(std::string name) { - return ReplaceAll(name, ".", "::"); -} -inline std::string get_namespace(const std::string &package) { - if (package.empty()) { - return ""; - } - return "::" + dots_to_colons(package); -} - -inline std::string get_namespace(const google::protobuf::FileDescriptor *file, - const Options &options) { - if (file == options.f) { - return get_namespace(options.ns); - } - else { - return get_namespace(file->package()); - } -} - -inline std::string qualified_file_level_symbol( - const google::protobuf::FileDescriptor *file, const std::string &name, - const Options &options) { - // if (options.ns.empty()) { - // return absl::StrCat("::", name); - // } - return get_namespace(file, options) + "::" + name; -} - -inline std::string qualified_class_name(const google::protobuf::Descriptor *d, - const Options &options) { - return qualified_file_level_symbol(d->file(), class_name(d), options); -} - -inline std::string qualified_enum_name( - const google::protobuf::EnumDescriptor *d, const Options &options) { - return qualified_file_level_symbol(d->file(), enum_name(d), options); -} - -class Formatter { - public: - Formatter(google::protobuf::io::Printer *printer) : printer_(printer) {} - void indent() const { printer_->Indent(); } - void outdent() const { printer_->Outdent(); } - template - void operator()(const char *format, const Args &...args) const { - printer_->FormatInternal({ToString(args)...}, vars_, format); - } - - private: - static std::string ToString(const std::string &s) { return s; } - template ::value>::type> - static std::string ToString(I x) { - return std::to_string(x); - } - - private: - google::protobuf::io::Printer *printer_; - std::map vars_; -}; - -class NamespaceOpener { - public: - NamespaceOpener(google::protobuf::io::Printer *p, - const std::string &package = {}); - ~NamespaceOpener(); - - public: - void open() const; - void close() const; - - private: - std::vector ns_; - google::protobuf::io::Printer *p_; -}; -std::string strip_proto(const std::string &filename); -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/main.cpp b/src/struct_pb/protoc-plugin/main.cpp deleted file mode 100644 index 3ef44008f..000000000 --- a/src/struct_pb/protoc-plugin/main.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -#include "StructGenerator.h" -using namespace struct_pb::compiler; -using namespace google::protobuf::compiler; -int main(int argc, char* argv[]) { - StructGenerator generator; - return PluginMain(argc, argv, &generator); -} \ No newline at end of file diff --git a/src/struct_pb/tests/CMakeLists.txt b/src/struct_pb/tests/CMakeLists.txt index 82985e7b0..a845733ca 100644 --- a/src/struct_pb/tests/CMakeLists.txt +++ b/src/struct_pb/tests/CMakeLists.txt @@ -1,55 +1,39 @@ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests) find_package(Protobuf QUIET) +if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + # If this is a subproject in ylt + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests) +else() + # else find installed yalantinglibs + cmake_minimum_required(VERSION 3.15) + project(struct_pb_test) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_INCLUDE_CURRENT_DIR ON) + # if you have install ylt + find_package(yalantinglibs REQUIRED) + link_libraries(yalantinglibs::yalantinglibs) + # else + # include_directories(include) + # include_directories(include/ylt/thirdparty) +endif() + +set(TEST_PROTO main.cpp) + if (Protobuf_FOUND) -add_executable(test_struct_pb - test_pb.cpp - test_pb_oneof.cpp - test_pb_benchmark_struct.cpp - test_pb_bad_identifiers.cpp - ) -target_sources(test_struct_pb PRIVATE - main.cpp - ) -add_test(NAME test_struct_pb COMMAND test_struct_pb) -target_include_directories(test_struct_pb PUBLIC ${yaLanTingLibs_SOURCE_DIR}/src/struct_pack/benchmark) - target_compile_definitions(test_struct_pb PRIVATE HAVE_PROTOBUF) - target_link_libraries(test_struct_pb PRIVATE protobuf::libprotobuf) - # generate .pb.cc .pb.h - protobuf_generate_cpp(PROTO_SRCS - PROTO_HDRS - test_pb.proto - data_def.proto - ) - target_include_directories(test_struct_pb PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) - target_sources(test_struct_pb PRIVATE - ${PROTO_SRCS} - ${PROTO_HDRS} - ) - protobuf_generate_struct_pb(STRUCT_PB_PROTO_SRCS - STRUCT_PB_PROTO_HDRS - test_pb.proto - OPTION "generate_eq_op=true,namespace=test_struct_pb" - ) - target_sources(test_struct_pb PRIVATE - ${STRUCT_PB_PROTO_SRCS} - ${STRUCT_PB_PROTO_HDRS} - ) - protobuf_generate_struct_pb(STRUCT_PB_TEST_BENCHMARK_PROTO_SRCS - STRUCT_PB_TEST_BENCHMARK_PROTO_HDRS - data_def.proto - OPTION "namespace=struct_pb_sample" - ) - target_sources(test_struct_pb PRIVATE - ${STRUCT_PB_TEST_BENCHMARK_PROTO_SRCS} - ${STRUCT_PB_TEST_BENCHMARK_PROTO_HDRS} - ) - protobuf_generate_struct_pb(STRUCT_PB_PROTO_SRCS2 - STRUCT_PB_PROTO_HDRS2 - test_bad_identifiers.proto - test_large_enum_value.proto - ) - target_sources(test_struct_pb PRIVATE - ${STRUCT_PB_PROTO_SRCS2} - ${STRUCT_PB_PROTO_HDRS2} - ) -endif () \ No newline at end of file + add_definitions(-DSTRUCT_PB_WITH_PROTO) + message(STATUS "Found Protobuf: ${Protobuf_VERSION}") + include_directories(${Protobuf_INCLUDE_DIRS}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + set(PROTO_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/) + file(GLOB PROTO_FILES ${PROTO_SRC_DIR}/*.proto) + + protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_FILES}) + # message(STATUS "Proto source files: ${PROTO_SRCS}") + # message(STATUS "Proto header files: ${PROTO_HDRS}") + add_executable(struct_pb_test ${PROTO_SRCS} ${TEST_PROTO}) + target_link_libraries(struct_pb_test PRIVATE protobuf::libprotobuf) + add_test(NAME struct_pb_test COMMAND struct_pb_test) +else() + add_executable(struct_pb_test ${TEST_PROTO}) + add_test(NAME struct_pb_test COMMAND struct_pb_test) +endif() \ No newline at end of file diff --git a/src/struct_pb/tests/data_def.proto b/src/struct_pb/tests/data_def.proto index 4083d7002..691c964fe 100644 --- a/src/struct_pb/tests/data_def.proto +++ b/src/struct_pb/tests/data_def.proto @@ -37,17 +37,6 @@ message Monsters { repeated Monster monsters = 1; } -message rect32 { - int32 x = 1; - int32 y = 2; - int32 width = 3; - int32 height = 4; -} - -message rect32s { - repeated rect32 rect32_list = 1; -} - message person { int32 id = 1; string name = 2; @@ -57,4 +46,11 @@ message person { message persons { repeated person person_list = 1; +} + +message bench_int32 { + int32 a = 1; + int32 b = 2; + int32 c = 3; + int32 d = 4; } \ No newline at end of file diff --git a/src/struct_pb/tests/helper.hpp b/src/struct_pb/tests/helper.hpp deleted file mode 100644 index bbb4477c2..000000000 --- a/src/struct_pb/tests/helper.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once -#include - -#include "data_def.struct_pb.h" -#include "hex_printer.hpp" -#include "test_pb.struct_pb.h" -#include "ylt/struct_pb.hpp" -#ifdef HAVE_PROTOBUF -#include "google/protobuf/repeated_field.h" -#endif - -template > -void check_self(const T& t, std::optional buf_opt = {}) { - auto size = struct_pb::internal::get_needed_size(t); - if (buf_opt.has_value()) { - REQUIRE(buf_opt.value().size() == size); - } - auto b = struct_pb::serialize(t); - if (buf_opt.has_value()) { - CHECK(hex_helper(buf_opt.value()) == hex_helper(b)); - } - T d_t{}; - auto ok = struct_pb::deserialize_to(d_t, b); - REQUIRE(ok); - CHECK(Pred()(t, d_t)); -} - -#ifdef HAVE_PROTOBUF -template -struct PB_equal { - constexpr bool operator()(const T& t, const PB_T& pb_t) const { - return t == pb_t; - } -}; -template > -void check_with_protobuf(const T& t, const PB_T& pb_t) { - auto pb_buf = pb_t.SerializeAsString(); - auto size = struct_pb::internal::get_needed_size(t); - REQUIRE(size == pb_buf.size()); - - std::string b = struct_pb::serialize(t); - CHECK(hex_helper(b) == hex_helper(pb_buf)); - - CHECK(Pred()(t, pb_t)); - T d_t{}; - auto ok = struct_pb::deserialize_to(d_t, b); - REQUIRE(ok); - CHECK(Pred()(d_t, pb_t)); -} -template -bool operator==(const std::vector& a, - const google::protobuf::RepeatedPtrField& b) { - if (a.size() != b.size()) { - return false; - } - auto sz = a.size(); - for (int i = 0; i < sz; ++i) { - if (!PB_equal()(a[i], b.at(i))) { - return false; - } - } - return true; -} -template -bool operator==(const std::vector& a, - const google::protobuf::RepeatedField& b) { - if (a.size() != b.size()) { - return false; - } - auto sz = a.size(); - for (int i = 0; i < sz; ++i) { - if (a[i] != b.at(i)) { - return false; - } - } - return true; -} -#endif \ No newline at end of file diff --git a/src/struct_pb/tests/hex_printer.hpp b/src/struct_pb/tests/hex_printer.hpp deleted file mode 100644 index 3e6cd4f8c..000000000 --- a/src/struct_pb/tests/hex_printer.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once -#include -#include -// useful for debugging -inline void print_hex(uint8_t v) { - static std::string hex = "0123456789abcedf"; - if (v < 16) { - std::cout << "0"; - std::cout << hex[v]; - } - else { - std::size_t first = v / 16; - std::size_t last = v % 16; - std::cout << hex[first] << hex[last]; - } -} -inline void print_hex(std::string_view sv) { - for (char ch : sv) { - uint8_t v = static_cast(ch); - print_hex(v); - std::cout << " "; - } - std::cout << std::endl; -} -struct hex_helper { - hex_helper(std::string_view sv) : sv(sv) {} - friend std::ostream& operator<<(std::ostream& os, const hex_helper& helper) { - static std::string hex = "0123456789abcedf"; - auto to_hex = [&os](std::string_view hex, uint8_t v) { - if (v < 16) { - os << "0"; - os << hex[v]; - } - else { - std::size_t first = v / 16; - std::size_t last = v % 16; - os << hex[first] << hex[last]; - } - }; - for (char ch : helper.sv) { - uint8_t v = static_cast(ch); - to_hex(hex, v); - os << " "; - } - return os; - } - bool operator==(const hex_helper&) const = default; - std::string_view sv; -}; \ No newline at end of file diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp index c5890983a..58098b3a2 100644 --- a/src/struct_pb/tests/main.cpp +++ b/src/struct_pb/tests/main.cpp @@ -1,24 +1,1163 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ #define DOCTEST_CONFIG_IMPLEMENT +#include #include "doctest.h" +#include "unittest_proto3.h" + +#if defined(STRUCT_PB_WITH_PROTO) +TEST_CASE("test BaseTypeMsg") { + { // normal test + stpb::BaseTypeMsg se_st{ + 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::ZERO}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } + + { // test min and empty str + stpb::BaseTypeMsg se_st{std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::lowest(), + std::numeric_limits::lowest(), + false, + "", + stpb::Enum::NEG}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } + { // test max and long str + stpb::BaseTypeMsg se_st{std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + true, + std::string(1000, 'x'), + stpb::Enum::BAZ}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test person and monster") { + stpb::simple_t2 t{-100, 2, stpb::Color::Blue, 4}; + std::string str; + iguana::to_pb(t, str); + + stpb::simple_t2 t2; + iguana::from_pb(t2, str); + CHECK(t.c == t2.c); + + pb::Simple2 s; + s.set_a(-100); + s.set_b(2); + s.set_c(pb::Color::Blue); + s.set_d(4); + + std::string pb_str; + s.SerializeToString(&pb_str); + + CHECK(str == pb_str); +} + +TEST_CASE("test person and monster") { + auto pb_monster = protobuf_sample::create_monster(); + auto sp_monster = create_sp_monster(); + + std::string pb_str; + std::string sp_str; + + pb_monster.SerializeToString(&pb_str); + iguana::to_pb(sp_monster, sp_str); + + CHECK(pb_str == sp_str); + + mygame::Monster m; + m.ParseFromString(pb_str); + CHECK(m.name() == pb_monster.name()); + + stpb::Monster spm; + iguana::from_pb(spm, sp_str); + CHECK(spm.name == sp_monster.name); + + auto pb_person = protobuf_sample::create_person(); + auto sp_person = create_person(); + pb_person.SerializePartialToString(&pb_str); + iguana::to_pb(sp_person, sp_str); + + CHECK(pb_str == sp_str); + + mygame::person pp; + pp.ParseFromString(pb_str); + CHECK(pp.name() == pb_person.name()); + + stpb::person p; + iguana::from_pb(p, sp_str); + CHECK(p.name == sp_person.name); +} + +TEST_CASE("test IguanaTypeMsg") { + { // test normal value + stpb::IguanaTypeMsg se_st{{100}, {200}, {300}, {400}, {31}, {32}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg{}; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + + { // test min value + stpb::IguanaTypeMsg se_st{{std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::lowest()}, + {std::numeric_limits::lowest()}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg{}; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + { // test max value + stpb::IguanaTypeMsg se_st{{std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + { // test empty + stpb::IguanaTypeMsg se_st{}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test RepeatBaseTypeMsg") { + { + stpb::RepeatBaseTypeMsg se_st{ + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + {10, 11, 12}, + {13.1, 14.2, 15.3}, + {16.4, 17.5, 18.6}, + {"a", "b", "c"}, + {stpb::Enum::BAZ, stpb::Enum::ZERO, stpb::Enum::NEG}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatBaseTypeMsg se_msg; + SetRepeatBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::RepeatBaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatBaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatBaseTypeMsg(dese_st, dese_msg); + } + { // max and min vlaue + stpb::RepeatBaseTypeMsg se_st{{std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {"", "", ""}, + {stpb::Enum::NEG, stpb::Enum::FOO}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatBaseTypeMsg se_msg; + SetRepeatBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::RepeatBaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatBaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatBaseTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test RepeatIguanaTypeMsg") { + { + stpb::RepeatIguanaTypeMsg se_st{ + {{0}, {1}, {3}}, {{4}, {5}, {6}}, {{7}, {8}, {9}}, + {{10}, {11}, {12}}, {{13}, {14}, {15}}, {}, + }; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatIguanaTypeMsg se_msg; + SetRepeatIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::RepeatIguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatIguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatIguanaTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test NestedMsg") { + { + stpb::NestedMsg se_st{ + /* base_msg */ stpb::BaseTypeMsg{100, 200, 300, 400, 31.4f, 62.8, false, + "World", stpb::Enum::BAZ}, + /* repeat_base_msg */ + std::vector{ + {1, 2, 3, 4, 5.5f, 6.6, true, "Hello", stpb::Enum::FOO}, + {7, 8, 9, 10, 11.11f, 12.12, false, "Hi", stpb::Enum::BAR}}, + /* iguana_type_msg */ + stpb::IguanaTypeMsg{{100}, {200}, {300}, {400}, {31}, {32}}, + /* repeat_iguna_msg */ + std::vector{stpb::IguanaTypeMsg{{1}, {2}, {3}}, + stpb::IguanaTypeMsg{{4}, {5}, {6}}, + stpb::IguanaTypeMsg{{7}, {8}, {9}}}, + /* repeat_repeat_base_msg */ + std::vector{ + {{1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + {10, 11, 12}, + {13.1, 14.2, 15.3}, + {16.4, 17.5, 18.6}, + {"a", "b", "c"}, + {stpb::Enum::FOO, stpb::Enum::BAR, stpb::Enum::BAZ}}, + {{19, 20, 21}, + {22, 23, 24}, + {25, 26, 27}, + {28, 29, 30}, + {31.1, 32.2, 33.3}, + {34.4, 35.5, 36.6}, + {"x", "y", "z"}, + {stpb::Enum::ZERO, stpb::Enum::NEG, stpb::Enum::FOO}}}}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestedMsg se_msg; + SetNestedMsg(se_st, se_msg); + + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + + CHECK(st_ss == pb_ss); + + stpb::NestedMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestedMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + + CheckNestedMsg(dese_st, dese_msg); + } + { // test empty values + stpb::NestedMsg se_st{ + /* base_msg */ {0, 0, 0, 0, 0.0f, 0.0, true, "", stpb::Enum::ZERO}, + /* repeat_base_msg */ {}, + /* iguana_type_msg */ {}, + /* repeat_iguna_msg */ {}, + /* repeat_repeat_base_msg */ {}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestedMsg se_msg; + SetNestedMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + + // CHECK(st_ss == pb_ss); + print_hex_str(st_ss); + print_hex_str(pb_ss); + stpb::NestedMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestedMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + + CheckNestedMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test MapMsg") { + { + stpb::MapMsg se_st{}; + + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{10}, "ten"); + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{20}, "twenty"); + + se_st.str_iguana_type_msg_map.emplace( + "first", stpb::IguanaTypeMsg{{10}, {20}, {30}, {40}, {50}, {60}}); + se_st.str_iguana_type_msg_map.emplace( + "second", stpb::IguanaTypeMsg{{11}, {21}, {31}, {41}, {51}, {61}}); + + se_st.int_repeat_base_msg_map.emplace( + 1, stpb::RepeatBaseTypeMsg{{1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, + {9.0f, 10.0f}, + {11.0, 12.0}, + {"one", "two"}, + {stpb::Enum::FOO, stpb::Enum::BAR}}); + se_st.int_repeat_base_msg_map.emplace( + 2, stpb::RepeatBaseTypeMsg{{2, 3}, + {4, 5}, + {6, 7}, + {8, 9}, + {10.0f, 11.0f}, + {12.0, 13.0}, + {"three", "four"}, + {stpb::Enum::BAZ, stpb::Enum::NEG}}); + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::MapMsg se_msg{}; + SetMapMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + // It's okay not to satisfy this. + // CHECK(st_ss == pb_ss); + CHECK(st_ss.size() == pb_ss.size()); + stpb::MapMsg dese_st{}; + iguana::from_pb(dese_st, pb_ss); + pb::MapMsg dese_msg; + dese_msg.ParseFromString(st_ss); + CheckMapMsg(dese_st, dese_msg); + } + { + // key empty + stpb::MapMsg se_st{}; + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{30}, ""); + se_st.str_iguana_type_msg_map.emplace( + "", stpb::IguanaTypeMsg{{0}, {0}, {0}, {0}, {0}, {0}}); + se_st.int_repeat_base_msg_map.emplace( + 3, stpb::RepeatBaseTypeMsg{{}, {}, {}, {}, {}, {}, {}, {}}); + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::MapMsg se_msg{}; + SetMapMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::MapMsg dese_st{}; + iguana::from_pb(dese_st, pb_ss); + pb::MapMsg dese_msg; + dese_msg.ParseFromString(st_ss); + CheckMapMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test BaseOneofMsg") { + { // test double + stpb::BaseOneofMsg se_st{123, 3.14159, 456.78}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + // print_hex_str(st_ss); + // print_hex_str(pb_ss); + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test string + stpb::BaseOneofMsg se_st{123, std::string("Hello"), 456.78}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test BaseTypeMsg + stpb::BaseTypeMsg baseTypeMsg{ + 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::BAZ}; + stpb::BaseOneofMsg se_st{123, baseTypeMsg, 456.78}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test empty variant + stpb::BaseOneofMsg se_st{123, {}, 456.78}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + print_hex_str(st_ss); + print_hex_str(pb_ss); + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test NestOneofMsg ") { + { // Test BaseOneofMsg + stpb::BaseOneofMsg baseOneof{123, std::string("Hello"), 456.78}; + stpb::NestOneofMsg se_st{{baseOneof}}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestOneofMsg se_msg; + SetNestOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::NestOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckNestOneofMsg(dese_st, dese_msg); + } +} +#endif + +struct point_t PUBLIC(point_t) { + point_t() = default; + point_t(int a, double b) : x(a), y(b) {} + int x; + double y; +}; +REFLECTION(point_t, x, y); + +namespace my_space { +struct inner_struct PUBLIC(inner_struct) { + inner_struct() = default; + inner_struct(int a, int b, int c) : x(a), y(b), z(c) {} + int x; + int y; + int z; +}; + +constexpr inline auto get_members_impl(inner_struct *) { + return std::make_tuple(struct_pb::field_t{&inner_struct::x, 7, "a"}, + struct_pb::field_t{&inner_struct::y, 9, "b"}, + struct_pb::field_t{&inner_struct::z, 12, "c"}); +} +} // namespace my_space + +struct test_pb_st1 PUBLIC(test_pb_st1) { + test_pb_st1() = default; + test_pb_st1(int a, iguana::sint32_t b, iguana::sint64_t c) + : x(a), y(b), z(c) {} + int x; + iguana::sint32_t y; + iguana::sint64_t z; +}; +REFLECTION(test_pb_st1, x, y, z); + +struct test_pb_st2 { + test_pb_st2() = default; + test_pb_st2(int a, iguana::fixed32_t b, iguana::fixed64_t c) + : x(a), y(b), z(c) {} + int x; + iguana::fixed32_t y; + iguana::fixed64_t z; +}; +REFLECTION(test_pb_st2, x, y, z); + +struct test_pb_st3 PUBLIC(test_pb_st3) { + test_pb_st3() = default; + test_pb_st3(int a, iguana::sfixed32_t b, iguana::sfixed64_t c) + : x(a), y(b), z(c) {} + int x; + iguana::sfixed32_t y; + iguana::sfixed64_t z; +}; +REFLECTION(test_pb_st3, x, y, z); + +struct test_pb_st4 PUBLIC(test_pb_st3) { + test_pb_st4() = default; + test_pb_st4(int a, std::string b) : x(a), y(std::move(b)) {} + int x; + std::string y; +}; +REFLECTION(test_pb_st4, x, y); + +struct test_pb_st5 PUBLIC(test_pb_st5) { + test_pb_st5() = default; + test_pb_st5(int a, std::string_view b) : x(a), y(b) {} + int x; + std::string_view y; +}; +REFLECTION(test_pb_st5, x, y); + +struct test_pb_st6 PUBLIC(test_pb_st6) { + test_pb_st6() = default; + test_pb_st6(std::optional a, std::optional b) + : x(std::move(a)), y(std::move(b)) {} + std::optional x; + std::optional y; +}; +REFLECTION(test_pb_st6, x, y); + +struct pair_t PUBLIC(pair_t) { + pair_t() = default; + pair_t(int a, int b) : x(a), y(b) {} + int x; + int y; +}; +REFLECTION(pair_t, x, y); + +struct message_t PUBLIC(message_t) { + message_t() = default; + message_t(int a, pair_t b) : id(a), t(b) {} + int id; + pair_t t; +}; +REFLECTION(message_t, id, t); + +struct test_pb_st8 PUBLIC(test_pb_st8) { + test_pb_st8() = default; + test_pb_st8(int a, pair_t b, message_t c) : x(a), y(b), z(c) {} + + int x; + pair_t y; + message_t z; +}; +REFLECTION(test_pb_st8, x, y, z); + +struct test_pb_st9 PUBLIC(test_pb_st9) { + test_pb_st9() = default; + test_pb_st9(int a, std::vector b, std::string c) + : x(a), y(std::move(b)), z(std::move(c)) {} + int x; + std::vector y; + std::string z; +}; +REFLECTION(test_pb_st9, x, y, z); + +struct test_pb_st10 PUBLIC(test_pb_st10) { + test_pb_st10() = default; + test_pb_st10(int a, std::vector b, std::string c) + : x(a), y(std::move(b)), z(std::move(c)) {} + int x; + std::vector y; + std::string z; +}; +REFLECTION(test_pb_st10, x, y, z); + +struct test_pb_st11 PUBLIC(test_pb_st11) { + test_pb_st11() = default; + test_pb_st11(int a, std::vector> b, + std::vector c) + : x(a), y(std::move(b)), z(std::move(c)) {} + int x; + std::vector> y; + std::vector z; +}; +REFLECTION(test_pb_st11, x, y, z); + +struct test_pb_st12 PUBLIC(test_pb_st12) { + test_pb_st12() = default; + test_pb_st12(int a, std::map b, + std::map c) + : x(a), y(std::move(b)), z(std::move(c)) {} + + int x; + std::map y; + std::map z; +}; +REFLECTION(test_pb_st12, x, y, z); + +struct test_pb_st13 PUBLIC(test_pb_st13) { + test_pb_st13() = default; + test_pb_st13(int a, std::map b, std::string c) + : x(a), y(std::move(b)), z(std::move(c)) {} + + int x; + std::map y; + std::string z; +}; +REFLECTION(test_pb_st13, x, y, z); + +enum class colors_t { red, black }; + +enum level_t { debug, info }; + +struct test_pb_st14 PUBLIC(test_pb_st14) { + test_pb_st14() = default; + test_pb_st14(int a, colors_t b, level_t c) : x(a), y(b), z(c) {} + int x; + colors_t y; + level_t z; +}; +REFLECTION(test_pb_st14, x, y, z); + +namespace client { +struct person PUBLIC(person) { + person() = default; + person(std::string s, int d) : name(s), age(d) {} + std::string name; + int64_t age; +}; + +REFLECTION(person, name, age); +} // namespace client + +struct my_struct PUBLIC(my_struct) { + my_struct() = default; + my_struct(int a, bool b, iguana::fixed64_t c) : x(a), y(b), z(c) {} + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 PUBLIC(nest1) { + nest1() = default; + nest1(std::string s, my_struct t, int d) + : name(std::move(s)), value(t), var(d) {} + std::string name; + my_struct value; + int var; +}; + +REFLECTION(nest1, name, value, var); + +struct numer_st PUBLIC(numer_st) { + numer_st() = default; + numer_st(bool x, double y, float z) : a(x), b(y), c(z) {} + bool a; + double b; + float c; +}; +REFLECTION(numer_st, a, b, c); + +TEST_CASE("test reflection") { + { + auto t = iguana::create_instance("nest1"); + std::vector fields_name = t->get_fields_name(); + CHECK(fields_name == std::vector{"name", "value", "var"}); + + my_struct mt{2, true, {42}}; + t->set_field_value("value", mt); + t->set_field_value("name", std::string("test")); + t->set_field_value("var", 41); + nest1 *st = dynamic_cast(t.get()); + auto p = *st; + std::cout << p.name << "\n"; + auto &r0 = t->get_field_value("name"); + CHECK(r0 == "test"); + auto &r = t->get_field_value("var"); + CHECK(r == 41); + auto &r1 = t->get_field_value("value"); + CHECK(r1.x == 2); + + t->set_field_value("name", "hello"); + auto &s = t->get_field_value("name"); + CHECK(s == "hello"); + CHECK_THROWS_AS(t->set_field_value("name", 42), std::invalid_argument); + } + { + auto t = iguana::create_instance("pair_t"); + t->set_field_value("x", 12); + t->set_field_value("y", 24); + auto &r0 = t->get_field_value("x"); + CHECK(r0 == 12); + auto &r = t->get_field_value("y"); + CHECK(r == 24); + + std::string str; + t->to_pb(str); + + pair_t t1; + t1.from_pb(str); + + pair_t *st = dynamic_cast(t.get()); + CHECK(st->x == t1.x); + CHECK(st->y == t1.y); + } + auto t = iguana::create_instance("numer_st"); + t->set_field_value("a", true); + t->set_field_value("b", double(25)); + t->set_field_value("c", float(42)); + auto &r0 = t->get_field_value("a"); + CHECK(r0); + auto &r = t->get_field_value("b"); + CHECK(r == 25); + auto &r1 = t->get_field_value("c"); + CHECK(r1 == 42); + + numer_st *st = dynamic_cast(t.get()); + CHECK(st->a == true); + CHECK(st->b == 25); + CHECK(st->c == 42); + + std::string str; + t->to_pb(str); + + numer_st t1; + t1.from_pb(str); + + CHECK(st->a == t1.a); + CHECK(st->b == t1.b); + CHECK(st->c == t1.c); +} + +TEST_CASE("test struct_pb") { + { + my_space::inner_struct inner{41, 42, 43}; + + std::string str; + iguana::to_pb(inner, str); + + my_space::inner_struct inner1; + iguana::from_pb(inner1, str); + CHECK(inner.x == inner1.x); + CHECK(inner.y == inner1.y); + CHECK(inner.z == inner1.z); + } + + { + test_pb_st1 st1{41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st1 st2; + iguana::from_pb(st2, str); + CHECK(st1.x == st2.x); + CHECK(st1.y.val == st2.y.val); + CHECK(st1.z.val == st2.z.val); + } + + { + test_pb_st2 st1{41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st2 st2; + iguana::from_pb(st2, str); + CHECK(st1.y.val == st2.y.val); + } + { + test_pb_st3 st1{41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st3 st2; + iguana::from_pb(st2, str); + CHECK(st1.y.val == st2.y.val); + } + { + test_pb_st4 st1{41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st4 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + + { + test_pb_st5 st1{41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st5 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + { + // optional + test_pb_st6 st1{41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st6 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + { + // sub nested objects + nest1 v{"Hi", {1, false, {3}}, 5}, v2{}; + std::string s; + iguana::to_pb(v, s); + iguana::from_pb(v2, s); + CHECK(v.var == v2.var); + CHECK(v.value.y == v2.value.y); + CHECK(v.value.z == v2.value.z); + + test_pb_st8 st1{1, {3, 4}, {5, {7, 8}}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st8 st2; + iguana::from_pb(st2, str); + CHECK(st1.z.t.y == st2.z.t.y); + } + + { + // repeated messages + test_pb_st9 st1{1, {2, 4, 6}, "test"}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st9 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + test_pb_st10 st1{1, {{5, {7, 8}}, {9, {11, 12}}}, "test"}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st10 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + message_t m{1, {3, 4}}; + test_pb_st11 st1{1, {m}, {}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st11 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + auto m = std::make_shared(); + m->id = 10; + m->t.x = 11; + m->t.y = 12; + std::string s; + m->to_pb(s); + + std::shared_ptr t = m; + std::string str; + t->to_pb(str); + + CHECK(s == str); + + t->from_pb(str); + } + { + message_t st1{}; + std::string str; + iguana::to_pb(st1, str); + + message_t st2{}; + iguana::from_pb(st2, str); + CHECK(st1.id == st2.id); + } + { + test_pb_st11 st1{ + 1, {message_t{5, {7, 8}}, message_t{9, {11, 12}}}, {"test"}}; + std::string str; + iguana::to_pb(st1, str); + + std::string str1; + st1.to_pb(str1); + + test_pb_st11 st3; + st3.from_pb(str1); + + CHECK(str == str1); + + test_pb_st11 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + CHECK(st3.z == st2.z); + } + { + // map messages + test_pb_st12 st1{1, {{1, "test"}, {2, "ok"}}, {{"test", 4}, {"ok", 6}}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st12 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st12 st1{1, {{1, ""}, {0, "ok"}}, {{"", 4}, {"ok", 0}}}; + std::string str; + iguana::to_pb(st1, str); // error + print_hex_str(str); + test_pb_st12 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st13 st1; + st1.x = 1; + st1.y.emplace(1, message_t{2, {3, 4}}); + st1.y.emplace(2, message_t{4, {6, 8}}); + st1.z = "test"; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st13 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st13 st1; + st1.x = 1; + st1.y.emplace(2, message_t{}); + st1.y.emplace(3, message_t{}); + st1.z = "test"; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st13 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // enum + test_pb_st14 st1{1, colors_t::black, level_t::info}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st14 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // bool float double + numer_st n{true, 10.25, 4.578}, n1; + std::string str; + iguana::to_pb(n, str); + + iguana::from_pb(n1, str); + CHECK(n1.a == n.a); + CHECK(n1.b == n.b); + CHECK(n1.c == n.c); + } +} + +TEST_CASE("test members") { + using namespace iguana; + using namespace iguana::detail; + + my_space::inner_struct inner{41, 42, 43}; + const auto &map = iguana::get_members(); + std::visit( + [&inner](auto &member) mutable { + CHECK(member.field_no == 9); + CHECK(member.field_name == "b"); + CHECK(member.value(inner) == 42); + }, + map.at(9)); + + point_t pt{2, 3}; + const auto &arr1 = iguana::get_members(); + auto &val = arr1.at(1); + std::visit( + [&pt](auto &member) mutable { + CHECK(member.field_no == 1); + CHECK(member.field_name == "x"); + CHECK(member.value(pt) == 2); + }, + val); +} + +struct test_variant PUBLIC(test_variant) { + test_variant() = default; + test_variant(int a, std::variant b, double c) + : x(a), y(std::move(b)), z(c) {} + int x; + std::variant y; + double z; +}; +REFLECTION(test_variant, x, y, z); + +TEST_CASE("test variant") { + { + constexpr auto tp = iguana::get_members_tuple(); + static_assert(std::get<0>(tp).field_no == 1); + static_assert(std::get<1>(tp).field_no == 2); + static_assert(std::get<2>(tp).field_no == 3); + static_assert(std::get<3>(tp).field_no == 4); + static_assert(std::get<4>(tp).field_no == 5); + } + { + constexpr static auto map = iguana::get_members(); + static_assert(map.find(1) != map.end()); + static_assert(map.find(2) != map.end()); + static_assert(map.find(3) != map.end()); + static_assert(map.find(4) != map.end()); + auto val1 = map.find(2); + auto val2 = map.find(3); + std::visit( + [](auto &member) mutable { + CHECK(member.field_no == 2); + CHECK(member.field_name == "y"); + }, + val1->second); + std::visit( + [](auto &member) mutable { + CHECK(member.field_no == 3); + CHECK(member.field_name == "y"); + }, + val2->second); + } + { + test_variant st1 = {5, "Hello, variant!", 3.14}; + std::string str; + iguana::to_pb(st1, str); + test_variant st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + CHECK(std::get(st2.y) == "Hello, variant!"); + } + { + test_variant st1 = {5, 3.88, 3.14}; + std::string str; + iguana::to_pb(st1, str); + test_variant st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + CHECK(std::get(st2.y) == 3.88); + } +} // doctest comments // 'function' : must be 'attribute' - see issue #182 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) -int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } +int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); } DOCTEST_MSVC_SUPPRESS_WARNING_POP \ No newline at end of file diff --git a/src/struct_pb/tests/test_bad_identifiers.proto b/src/struct_pb/tests/test_bad_identifiers.proto deleted file mode 100644 index ead67b6c6..000000000 --- a/src/struct_pb/tests/test_bad_identifiers.proto +++ /dev/null @@ -1,191 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// This file tests that various identifiers work as field and type names even -// though the same identifiers are used internally by the C++ code generator. - -// LINT: LEGACY_NAMES - -syntax = "proto2"; - -// Some generic_services option(s) added automatically. -// See: http://go/proto2-generic-services-default -option cc_generic_services = true; // auto-added - -// We don't put this in a package within proto2 because we need to make sure -// that the generated code doesn't depend on being in the proto2 namespace. -package protobuf_unittest; - -// Test that fields can have names like "input" and "i" which are also used -// internally by the code generator for local variables. -message TestConflictingSymbolNames { - message BuildDescriptors {} - message TypeTraits {} - - optional int32 input = 1; - optional int32 output = 2; - optional string length = 3; - repeated int32 i = 4; - repeated string new_element = 5 [ctype = STRING_PIECE]; - optional int32 total_size = 6; - optional int32 tag = 7; - - enum TestEnum { - FOO = 0; - } - message Data1 { - repeated int32 data = 1; - } - message Data2 { - repeated TestEnum data = 1; - } - message Data3 { - repeated string data = 1; - } - message Data4 { - repeated Data4 data = 1; - } - message Data5 { - repeated string data = 1 [ctype = STRING_PIECE]; - } - message Data6 { - repeated string data = 1 [ctype = CORD]; - } - - optional int32 source = 8; - optional int32 value = 9; - optional int32 file = 10; - optional int32 from = 11; - optional int32 handle_uninterpreted = 12; - repeated int32 index = 13; - optional int32 controller = 14; - optional int32 already_here = 15; - - optional uint32 uint32 = 16; - optional uint32 uint32_t = 41; - optional uint64 uint64 = 17; - optional uint32 uint64_t = 42; - optional string string = 18; - optional int32 memset = 19; - optional int32 int32 = 20; - optional int32 int32_t = 43; - optional int64 int64 = 21; - optional int64 int64_t = 44; - optional int64 size_t = 45; - - optional uint32 cached_size = 22; - optional uint32 extensions = 23; - optional uint32 bit = 24; - optional uint32 bits = 25; - optional uint32 offsets = 26; - optional uint32 reflection = 27; - - message Cord {} - optional string some_cord = 28 [ctype = CORD]; - - message StringPiece {} - optional string some_string_piece = 29 [ctype = STRING_PIECE]; - - // Some keywords. - optional uint32 int = 30; - optional uint32 friend = 31; - optional uint32 class = 37; - optional uint32 typedecl = 39; - optional uint32 auto = 40; - - // The generator used to #define a macro called "DO" inside the .cc file. - message DO {} - optional DO do = 32; - - // Some template parameter names for extensions. - optional int32 field_type = 33; - optional bool is_packed = 34; - - // test conflicting release_$name$. "length" and "do" field in this message - // must remain string or message fields to make the test valid. - optional string release_length = 35; - // A more extreme case, the field name "do" here is a keyword, which will be - // escaped to "do_" already. Test there is no conflict even with escaped field - // names. - optional DO release_do = 36; - - // For clashing local variables in Serialize and ByteSize calculation. - optional string target = 38; - - extensions 1000 to max; // NO_PROTO3 -} - -message TestConflictingSymbolNamesExtension { // NO_PROTO3 - extend TestConflictingSymbolNames { // NO_PROTO3 - repeated int32 repeated_int32_ext = 20423638 [packed = true]; // NO_PROTO3 - } // NO_PROTO3 -} // NO_PROTO3 - -message TestConflictingEnumNames { // NO_PROTO3 - enum while { // NO_PROTO3 - default = 0; // NO_PROTO3 - and = 1; // NO_PROTO3 - class = 2; // NO_PROTO3 - int = 3; // NO_PROTO3 - typedef = 4; // NO_PROTO3 - XOR = 5; // NO_PROTO3 - } // NO_PROTO3 - - optional while conflicting_enum = 1; // NO_PROTO3 -} // NO_PROTO3 - -enum bool { // NO_PROTO3 - default = 0; // NO_PROTO3 - NOT_EQ = 1; // NO_PROTO3 - volatile = 2; // NO_PROTO3 - return = 3; // NO_PROTO3 -} // NO_PROTO3 - -message DummyMessage {} - -message NULL { - optional int32 int = 1; -} - -extend TestConflictingSymbolNames { // NO_PROTO3 - optional int32 void = 314253; // NO_PROTO3 -} // NO_PROTO3 - -// Message names that could conflict. -message Shutdown {} -message TableStruct {} - -service TestConflictingMethodNames { - rpc Closure(DummyMessage) returns (DummyMessage); -} diff --git a/src/struct_pb/tests/test_large_enum_value.proto b/src/struct_pb/tests/test_large_enum_value.proto deleted file mode 100644 index cb6ca1b15..000000000 --- a/src/struct_pb/tests/test_large_enum_value.proto +++ /dev/null @@ -1,43 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Test that proto2 compiler can generate valid code when the enum value -// is INT_MAX. Note that this is a compile-only test and this proto is not -// referenced in any C++ code. -syntax = "proto2"; - -package protobuf_unittest; - -message TestLargeEnumValue { - enum EnumWithLargeValue { - VALUE_1 = 1; - VALUE_MAX = 0x7fffffff; - } -} diff --git a/src/struct_pb/tests/test_pb.cpp b/src/struct_pb/tests/test_pb.cpp deleted file mode 100644 index 06aae7f98..000000000 --- a/src/struct_pb/tests/test_pb.cpp +++ /dev/null @@ -1,851 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "doctest.h" -#include "helper.hpp" -#ifdef HAVE_PROTOBUF -#include "test_pb.pb.h" -#endif -using namespace doctest; -using namespace struct_pb; - -TEST_SUITE_BEGIN("test pb"); -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test1& t, const Test1& pb_t) const { - return t.a == pb_t.a(); - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test1") { - test_struct_pb::Test1 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("has value") { - std::string buf{0x08, (char)0x96, 0x01}; - t.a = 150; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test1 pb_t; - pb_t.set_a(150); - auto pb_buf = pb_t.SerializeAsString(); - REQUIRE(pb_buf == buf); - check_with_protobuf(t, pb_t); -#endif - } - - SUBCASE("negative") { - { - // an example for check arm char - std::string buf{0x08, (char)0xff, (char)0xff, (char)0xff, - (char)0xff, (char)0xff, (char)0xff, (char)0xff, - (char)0xff, (char)0xff, 0x01}; - test_struct_pb::Test1 t{.a = -1}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - // for debug - Test1 pb_t; - pb_t.set_a(-1); - auto s = pb_t.SerializeAsString(); - check_with_protobuf(t, pb_t); -#endif - } - for (int32_t i = -1; i > INT16_MIN + 1; i *= 2) { - test_struct_pb::Test1 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - Test1 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test2& t, const Test2& pb_t) const { - return t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test2") { - test_struct_pb::Test2 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("has value") { - std::string buf{0x12, 0x07}; - std::string s = "testing"; - buf += s; - t.b = s; - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - Test2 pb_t; - pb_t.set_b(s); - check_with_protobuf(t, pb_t); -#endif - } -} -namespace std { -template <> -struct equal_to { - bool operator()(const test_struct_pb::Test3& lhs, - const test_struct_pb::Test3& rhs) const { - if (lhs.c && rhs.c) { - return equal_to()(*lhs.c, *rhs.c); - } - if (!lhs.c && !rhs.c) { - return true; - } - return false; - } -}; -} // namespace std -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test3& t, const Test3& pb_t) const { - if (t.c && pb_t.has_c()) { - return PB_equal()(*t.c, pb_t.c()); - } - if (!t.c && !pb_t.has_c()) { - return true; - } - return false; - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test3") { - test_struct_pb::Test3 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("has value") { - std::string buf{0x1a, 0x03, 0x08, (char)0x96, 0x01}; - t.c = std::make_unique( - test_struct_pb::Test1{.a = 150}); - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - Test3 pb_t; - auto pb_c = new Test1; - pb_c->set_a(150); - pb_t.set_allocated_c(pb_c); - - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test4& t, const Test4& pb_t) const { - return t.e == pb_t.e(); - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test4") { - test_struct_pb::Test4 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("string empty") { - std::string buf{0x2a, 0x01, 0x01}; - t.e = {1}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test4 pb_t; - pb_t.add_e(1); - auto pb_buf = pb_t.SerializeAsString(); - REQUIRE(pb_buf == buf); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("repeated empty") { - // [4] 22 2 68 69 - std::string buf{0x22, 0x02, 0x68, 0x69}; - std::string s = "hi"; - t.d = s; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test4 pb_t; - pb_t.set_d(s); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("has value") { - std::string buf{0x22, 0x05, 0x68, 0x65, 0x6c, 0x6c, - 0x6f, 0x2a, 0x03, 0x01, 0x02, 0x03}; - // why document write - // 220568656c6c6f280128022803 - // while my pb c++ code generated - // 34 5 'h' 'e' 'l' 'l' 'o' 42 3 1 2 3 - // 22 5 68 65 6c 6c 6f 2a 3 1 2 3 - t.d = "hello"; - t.e = {1, 2, 3}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test4 pb_t; - pb_t.set_d("hello"); - pb_t.add_e(1); - pb_t.add_e(2); - pb_t.add_e(3); - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestDouble& t, - const MyTestDouble& pb_t) const { - std::valarray ts{t.a, t.b, t.c}; - std::valarray pb_ts{pb_t.a(), pb_t.b(), pb_t.c()}; - return (std::abs(ts - pb_ts) < 0.00005f).min(); - } -}; -#endif -TEST_CASE("testing double") { - test_struct_pb::MyTestDouble t{.a = 123.456, .b = 0, .c = -678.123}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestDouble pb_t; - pb_t.set_a(t.a); - pb_t.set_b(t.b); - pb_t.set_c(t.c); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFloat& t, - const MyTestFloat& pb_t) const { - std::valarray ts{t.a, t.b, t.c, t.d, t.e}; - std::valarray pb_ts{pb_t.a(), pb_t.b(), pb_t.c(), pb_t.d(), - pb_t.e()}; - return (std::abs(ts - pb_ts) < 0.00005f).min(); - } -}; -#endif -TEST_CASE("testing float") { - // [20] 15 00 00 80 3f 1d 00 00 80 bf 25 b6 f3 9d 3f 2d 00 04 f1 47 - std::string buf{0x15, 0x00, 0x00, (char)0x80, 0x3f, - 0x1d, 0x00, 0x00, (char)0x80, (char)0xbf, - 0x25, (char)0xb6, (char)0xf3, (char)0x9d, 0x3f, - 0x2d, 0x00, 0x04, (char)0xf1, 0x47}; - test_struct_pb::MyTestFloat t{ - .a = 0, .b = 1, .c = -1, .d = 1.234, .e = 1.234e5}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestFloat pb_t; - pb_t.set_a(0); - pb_t.set_b(1); - pb_t.set_c(-1); - pb_t.set_d(1.234); - pb_t.set_e(1.234e5); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestInt32& t, - const MyTestInt32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing int32") { - std::string buf{0x08, (char)0x80, 0x01}; - test_struct_pb::MyTestInt32 t; - t.a = 128; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestInt32 pb_t; - pb_t.set_a(128); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestInt64& t, - const MyTestInt64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing int64") { - int64_t max_val = 4; - max_val *= INT32_MAX; - for (int64_t i = 1; i < max_val; i *= -2) { - test_struct_pb::MyTestInt64 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestInt64 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestUint32& t, - const MyTestUint32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing uint32") { - int32_t max_val = 4; - max_val *= INT16_MAX; - for (uint32_t i = 1; i < max_val; i *= 2) { - test_struct_pb::MyTestUint32 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestUint32 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestUint64& t, - const MyTestUint64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing uint64") { - int64_t max_val = 4; - max_val *= INT32_MAX; - for (uint64_t i = 1; i < max_val; i *= 2) { - test_struct_pb::MyTestUint64 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestUint64 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestEnum& t, - const MyTestEnum& pb_t) const { - return static_cast(t.color) == - static_cast(pb_t.color()); - } -}; -#endif -TEST_CASE("testing enum") { - SUBCASE("Red") { - std::string buf; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Red; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Red); - auto pb_buf = pb_t.SerializeAsString(); - REQUIRE(hex_helper(pb_buf) == hex_helper(buf)); - MyTestEnum pb_d_t; - auto ok = pb_d_t.ParseFromArray(pb_buf.data(), pb_buf.size()); - REQUIRE(ok); - CHECK(pb_d_t.IsInitialized()); - CHECK(pb_d_t.color() == pb_t.color()); - auto c = pb_d_t.color(); - CHECK(c == MyTestEnum_Color::MyTestEnum_Color_Red); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Green") { - std::string buf{0x30, 0x01}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Green; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Green); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Blue") { - std::string buf{0x30, 0x02}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Blue; - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Blue); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Enum127") { - std::string buf{0x30, (char)0x7f}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Enum127; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Enum127); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Enum128") { - std::string buf{0x30, (char)0x80, 0x01}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Enum128; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Enum128); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestRepeatedMessage& t, - const MyTestRepeatedMessage& pb_t) const { - return t.fs == pb_t.fs(); - } -}; -#endif -TEST_CASE("testing nested repeated message") { - SUBCASE("one") { - test_struct_pb::MyTestRepeatedMessage t{}; - t.fs = {{1, 2, 3}}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestRepeatedMessage pb_t; - { - auto f1 = pb_t.add_fs(); - f1->set_a(1); - f1->set_b(2); - f1->set_c(3); - } - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("two") { - test_struct_pb::MyTestRepeatedMessage t{}; - t.fs = {{1, 2, 3}, {4, 5, 6}}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestRepeatedMessage pb_t; - { - auto f1 = pb_t.add_fs(); - f1->set_a(1); - f1->set_b(2); - f1->set_c(3); - } - { - auto f1 = pb_t.add_fs(); - f1->set_a(4); - f1->set_b(5); - f1->set_c(6); - } - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSint32& t, - const MyTestSint32& pb_t) const { - return t.a == pb_t.a(); - } -}; -#endif -TEST_CASE("testing sint32") { - SUBCASE("-1") { - std::string buf{0x08, 0x01}; - test_struct_pb::MyTestSint32 t{}; - t.a = -1; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(-1); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("1") { - test_struct_pb::MyTestSint32 t{}; - t.a = 1; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(1); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("128") { - std::string buf{0x08, (char)0x80, 0x02}; - test_struct_pb::MyTestSint32 t{}; - t.a = 128; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(128); - check_with_protobuf(t, pb_t); -#endif - } - - SUBCASE("range") { - for (int32_t i = INT16_MAX; i > INT16_MIN + 1; --i) { - test_struct_pb::MyTestSint32 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSint64& t, - const MyTestSint64& pb_t) const { - return t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing sint64") { - SUBCASE("-1") { - std::string buf{0x10, 0x01}; - test_struct_pb::MyTestSint64 t{}; - t.b = -1; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestSint64 pb_t; - pb_t.set_b(-1); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("128") { - std::string buf{0x10, (char)0x80, 0x02}; - test_struct_pb::MyTestSint64 t{}; - t.b = 128; - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - MyTestSint64 pb_t; - pb_t.set_b(128); - check_with_protobuf(t, pb_t); - -#endif - } - - SUBCASE("range") { - for (int64_t i = -1; i > INT32_MIN + 1; i *= -2) { - test_struct_pb::MyTestSint64 t{.b = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestSint64 pb_t; - pb_t.set_b(i); - check_with_protobuf(t, pb_t); -#endif - } - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestMap& t, - const MyTestMap& pb_t) const { - if (t.e.size() != pb_t.e_size()) { - return false; - } - for (const auto& [k, v] : pb_t.e()) { - auto it = t.e.find(k); - if (it == t.e.end()) { - return false; - } - if (it->second != v) { - return false; - } - } - return true; - } -}; -#endif -TEST_CASE("testing map") { - SUBCASE("one entry") { - std::string buf{0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01}; - test_struct_pb::MyTestMap t; - t.e["a"] = 1; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestMap pb_t; - auto& pb_m = *pb_t.mutable_e(); - pb_m["a"] = 1; - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("two entry") { - std::string buf{ - 0x1a, 0x0a, 0x0a, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x10, - (char)0x9a, 0x05, 0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01, - }; - std::string buf2{ - 0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01, 0x1a, 0x0a, 0x0a, - 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x10, (char)0x9a, 0x05, - }; - test_struct_pb::MyTestMap t; - t.e["a"] = 1; - t.e["hello"] = 666; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestMap pb_t; - auto& pb_m = *pb_t.mutable_e(); - pb_m["a"] = 1; - pb_m["hello"] = 666; - auto pb_buf = pb_t.SerializeAsString(); - - CHECK(buf.size() == pb_buf.size()); - REQUIRE((buf == pb_buf || buf2 == pb_buf)); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFixed32& t, - const MyTestFixed32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing fixed32") { - test_struct_pb::MyTestFixed32 t{}; - SUBCASE("single fixed") { - t.a = 888; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestFixed32 pb_t; - pb_t.set_a(888); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("only repeated") { - t.b = {5, 4, 3, 2, 1}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestFixed32 pb_t; - pb_t.add_b(5); - pb_t.add_b(4); - pb_t.add_b(3); - pb_t.add_b(2); - pb_t.add_b(1); - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFixed64& t, - const MyTestFixed64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing fixed64") { - using T = uint64_t; - T max_val = 4; - max_val *= INT32_MAX; - for (T i = 1; i < max_val; i *= 2) { - test_struct_pb::MyTestFixed64 t{.a = i}; -#ifdef HAVE_PROTOBUF - MyTestFixed64 pb_t; - pb_t.set_a(i); -#endif - for (T j = 1; j <= i; j *= 2) { -#ifdef HAVE_PROTOBUF - pb_t.add_b(j * 3); -#endif - t.b.push_back(j * 3); - } - check_self(t); -#ifdef HAVE_PROTOBUF - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSfixed32& t, - const MyTestSfixed32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing sfixed32") { - using T = int32_t; - T max_val = 4; - max_val *= INT16_MAX; - for (T i = 1; i < max_val; i *= -2) { - test_struct_pb::MyTestSfixed32 t{.a = i}; -#ifdef HAVE_PROTOBUF - MyTestSfixed32 pb_t; - pb_t.set_a(i); -#endif - for (T j = 1; j <= i; j *= -2) { -#ifdef HAVE_PROTOBUF - pb_t.add_b(j * -3); -#endif - t.b.push_back(j * -3); - } - check_self(t); -#ifdef HAVE_PROTOBUF - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSfixed64& t, - const MyTestSfixed64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing sfixed64") { - using T = int64_t; - T max_val = 4; - max_val *= INT32_MAX; - for (T i = 1; i < max_val; i *= -2) { - test_struct_pb::MyTestSfixed64 t{.a = i}; -#ifdef HAVE_PROTOBUF - MyTestSfixed64 pb_t; - pb_t.set_a(i); -#endif - for (T j = 1; j <= i; j *= -2) { -#ifdef HAVE_PROTOBUF - pb_t.add_b(j * -3); -#endif - t.b.push_back(j * -3); - } - check_self(t); -#ifdef HAVE_PROTOBUF - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFieldNumberRandom& t, - const MyTestFieldNumberRandom& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b() && t.c == pb_t.c() && - t.f == pb_t.f() && std::abs(t.d - pb_t.d()) < 0.00005f && - std::abs(t.e - pb_t.e()) < 0.00005f; - } -}; -#endif -TEST_CASE("testing random field number") { - test_struct_pb::MyTestFieldNumberRandom t{.a = 666, - .b = 999, - .c = "random", - .d = 3.14, - .e = 3344.123, - .f = {5, 4, 3, 2, 1}}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestFieldNumberRandom pb_t; - pb_t.set_a(666); - pb_t.set_b(999); - pb_t.set_c("random"); - pb_t.set_d(3.14); - pb_t.set_e(3344.123); - pb_t.add_f(5); - pb_t.add_f(4); - pb_t.add_f(3); - pb_t.add_f(2); - pb_t.add_f(1); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestAll& t, - const MyTestAll& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b() && t.c == pb_t.c() && - t.d == pb_t.d() && t.e == pb_t.e() && t.f == pb_t.f() && - t.g == pb_t.g() && t.h == pb_t.h() && t.i == pb_t.i() && - t.j == pb_t.j() && t.k == pb_t.k() && t.l == pb_t.l() && - t.m == pb_t.m() && t.n == pb_t.n() && t.o == pb_t.o(); - } -}; -#endif -TEST_CASE("testing all") { - test_struct_pb::MyTestAll t{}; - - t.a = -100; - t.b = -200; - t.c = -300; - t.d = -2378; - t.e = 2323; - t.f = 255; - t.g = -890; - t.h = -2369723; - t.i = -23234; - t.j = -239223423; - t.k = 9232983; - t.l = 237982374432; - t.m = true; - t.n = "testing all types"; - t.o = "\1\2\3\4\5\t\n666"; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestAll pb_t; - pb_t.set_a(t.a); - pb_t.set_b(t.b); - pb_t.set_c(t.c); - pb_t.set_d(t.d); - pb_t.set_e(t.e); - pb_t.set_f(t.f); - pb_t.set_g(t.g); - pb_t.set_h(t.h); - pb_t.set_i(t.i); - pb_t.set_j(t.j); - pb_t.set_k(t.k); - pb_t.set_l(t.l); - pb_t.set_m(t.m); - pb_t.set_n(t.n); - pb_t.set_o(t.o); - - check_with_protobuf(t, pb_t); -#endif -} -TEST_SUITE_END; \ No newline at end of file diff --git a/src/struct_pb/tests/test_pb.proto b/src/struct_pb/tests/test_pb.proto deleted file mode 100644 index 820f3498d..000000000 --- a/src/struct_pb/tests/test_pb.proto +++ /dev/null @@ -1,127 +0,0 @@ -syntax = "proto3"; - - -message Test1 { - int32 a = 1; -} -message Test2 { - string b = 2; -} -message Test3 { - Test1 c = 3; -} - -message Test4 { - string d = 4; - repeated int32 e = 5; -} - -message MyTestDouble { - double a = 1; - double b = 2; - double c = 3; -} - -message MyTestFloat { - float a = 1; - float b = 2; - float c = 3; - float d = 4; - float e = 5; -} - -message MyTestInt32 { - int32 a = 1; - repeated int32 b = 2; -} -message MyTestInt64 { - int64 a = 1; - repeated int64 b = 2; -} -message MyTestUint32 { - uint32 a = 1; - repeated uint32 b = 2; -} -message MyTestUint64 { - uint64 a = 1; - repeated uint64 b = 2; -} -message MyTestEnum { - enum Color { - Red = 0; - Green = 1; - Blue = 2; - Enum127 = 127; - Enum128 = 128; - } - Color color = 6; -} - -message MyTestRepeatedMessage { - repeated MyTestFloat fs = 1; -} - -message MyTestSint32 { - sint32 a = 1; -} -message MyTestSint64 { - sint64 b = 2; -} -message MyTestMap { - map e = 3; -} -message MyTestFixed32 { - fixed32 a = 1; - repeated fixed32 b = 2; -} -message MyTestFixed64 { - fixed64 a = 1; - repeated fixed64 b = 2; -} -message MyTestSfixed32 { - sfixed32 a = 1; - repeated sfixed32 b = 2; -} -message MyTestSfixed64 { - sfixed64 a = 1; - repeated sfixed64 b = 2; -} - -message MyTestFieldNumberRandom { - int32 a = 6; - sint64 b = 3; - string c = 4; - double d = 5; - float e = 1; - repeated fixed32 f = 128; -} - -message MyTestAll { - double a = 1; - float b = 2; - int32 c = 3; - int64 d = 4; - uint32 e = 5; - uint64 f = 6; - sint32 g = 7; - sint64 h = 8; - fixed32 i = 9; - fixed64 j = 10; - sfixed32 k = 11; - sfixed64 l = 12; - bool m = 13; - string n = 14; - bytes o = 15; -} -message SubMessageForOneof { - bool ok = 1; -} -message SampleMessageOneof { - oneof test_oneof { - int32 b = 10; - int32 a = 8; - - string name = 4; - SubMessageForOneof sub_message = 9; - } -} \ No newline at end of file diff --git a/src/struct_pb/tests/test_pb_bad_identifiers.cpp b/src/struct_pb/tests/test_pb_bad_identifiers.cpp deleted file mode 100644 index 0089ac502..000000000 --- a/src/struct_pb/tests/test_pb_bad_identifiers.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "doctest.h" -#include "test_bad_identifiers.struct_pb.h" -using namespace doctest; - -TEST_SUITE_BEGIN("test bad identifiers"); -TEST_CASE("testing conflicting symbol names") { - protobuf_unittest::TestConflictingSymbolNames message; - message.uint32 = 1; - auto sz = struct_pb::internal::get_needed_size(message); - CHECK(sz == 3); - // Due to different API, the code is useless - message.friend_ = 5; - CHECK(message.friend_ == 5); - message.class_ = 6; - CHECK(message.class_ == 6); - // NO PROTO3 - typedef protobuf_unittest::TestConflictingSymbolNamesExtension - ExtensionMessage; -} -TEST_CASE("testing conflicting enum names") { - protobuf_unittest::TestConflictingEnumNames message; - message.conflicting_enum = - protobuf_unittest::TestConflictingEnumNames::while_::and_; - CHECK(1 == static_cast(message.conflicting_enum.value())); - - message.conflicting_enum = - protobuf_unittest::TestConflictingEnumNames::while_::XOR; - CHECK(5 == static_cast(message.conflicting_enum.value())); - - protobuf_unittest::bool_ conflicting_enum; - conflicting_enum = protobuf_unittest::bool_::NOT_EQ; - CHECK(1 == static_cast(conflicting_enum)); - - conflicting_enum = protobuf_unittest::bool_::return_; - CHECK(3 == static_cast(conflicting_enum)); -} -TEST_CASE("testing conflicting message names") { - protobuf_unittest::NULL_ message; - message.int_ = 123; - CHECK(message.int_ == 123); -} -TEST_CASE("testing conflicting extension") { - protobuf_unittest::TestConflictingSymbolNames message; - // NO_PROTO3 -} -TEST_SUITE_END(); \ No newline at end of file diff --git a/src/struct_pb/tests/test_pb_benchmark_struct.cpp b/src/struct_pb/tests/test_pb_benchmark_struct.cpp deleted file mode 100644 index 7895e7a4a..000000000 --- a/src/struct_pb/tests/test_pb_benchmark_struct.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifdef HAVE_PROTOBUF -#include "protobuf_sample.hpp" -#endif -#include "data_def.struct_pb.h" -#include "doctest.h" -#include "helper.hpp" -#include "struct_pb_sample.hpp" -using namespace doctest; - -namespace struct_pb_sample { -template -bool check_unique_ptr(const T& lhs, const T& rhs) { - if (lhs && rhs) { - return *lhs == *rhs; - } - return !lhs && !rhs; -} -bool operator==(const Vec3& lhs, const Vec3& rhs) { - std::valarray lh({lhs.x, lhs.y, lhs.z}); - std::valarray rh({rhs.x, rhs.y, rhs.z}); - return (std::abs(lh - rh) < 0.05f).min(); -} -bool operator==(const Weapon& lhs, const Weapon& rhs) { - return lhs.name == rhs.name && lhs.damage == rhs.damage; -}; -bool operator==(const rect32& lhs, const rect32& rhs) { - return lhs.x == rhs.x && lhs.y == rhs.y && lhs.width == rhs.width && - lhs.height == rhs.height; -} -bool operator==(const rect32s& lhs, const rect32s& rhs) { - return lhs.rect32_list == rhs.rect32_list; -} -bool operator==(const person& lhs, const person& rhs) { - return lhs.id == rhs.id && lhs.name == rhs.name && lhs.age == rhs.age && - lhs.salary == rhs.salary; -} -bool operator==(const persons& lhs, const persons& rhs) { - return lhs.person_list == rhs.person_list; -} -bool operator==(const Monster& lhs, const Monster& rhs) { - bool ok = check_unique_ptr(lhs.pos, rhs.pos); - if (!ok) { - return false; - } - ok = check_unique_ptr(lhs.equipped, rhs.equipped); - if (!ok) { - return false; - } - return lhs.mana == rhs.mana && lhs.hp == rhs.hp && lhs.name == rhs.name && - lhs.inventory == rhs.inventory && lhs.color == rhs.color && - lhs.weapons == rhs.weapons && lhs.path == rhs.path; -}; -bool operator==(const Monsters& lhs, const Monsters& rhs) { - return lhs.monsters == rhs.monsters; -} - -bool verify(const struct_pb_sample::Weapon& a, - const struct_pb_sample::Weapon& b) { - assert(a.name == b.name); - assert(a.damage == b.damage); - return true; -} -bool verify(const struct_pb_sample::Monster& a, - const struct_pb_sample::Monster& b) { - assert(a.pos && b.pos); - assert(*a.pos == *b.pos); - assert(a.mana == b.mana); - assert(a.hp == b.hp); - assert(a.name == b.name); - assert(a.inventory == b.inventory); - assert(a.color == b.color); - assert(a.weapons.size() == b.weapons.size()); - for (int i = 0; i < a.weapons.size(); ++i) { - auto ok = verify(a.weapons[i], b.weapons[i]); - if (!ok) { - return ok; - } - } - assert(a.weapons == b.weapons); - assert(a.equipped && b.equipped); - assert(*a.equipped == *b.equipped); - assert(a.path == b.path); - return true; -} -bool verify(const struct_pb_sample::Monsters& a, - const struct_pb_sample::Monsters& b) { - assert(a.monsters.size() == b.monsters.size()); - for (int i = 0; i < a.monsters.size(); ++i) { - auto ok = verify(a.monsters[i], b.monsters[i]); - if (!ok) { - return ok; - } - } - return true; -} -template -T copy(const T& t) { - return t; -} -template <> -struct_pb_sample::Monster copy(const struct_pb_sample::Monster& t) { - struct_pb_sample::Monster m; - m.pos = std::make_unique(); - *m.pos = *t.pos; - m.mana = t.mana; - m.hp = t.hp; - m.name = t.name; - m.inventory = t.inventory; - m.color = t.color; - m.weapons = t.weapons; - m.equipped = std::make_unique(); - *m.equipped = *t.equipped; - m.path = t.path; - return m; -} -template <> -struct_pb_sample::Monsters copy(const struct_pb_sample::Monsters& t) { - struct_pb_sample::Monsters m; - m.monsters.reserve(t.monsters.size()); - for (const auto& e : t.monsters) { - m.monsters.push_back(std::move(copy(e))); - } - return m; -} -} // namespace struct_pb_sample - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::rect32s& t, - const mygame::rect32s& pb_t) const { - return t.rect32_list == pb_t.rect32_list(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::rect32& lhs, - const mygame::rect32& rhs) const { - return lhs.x == rhs.x() && lhs.y == rhs.y() && lhs.width == rhs.width() && - lhs.height == rhs.height(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Vec3& lhs, - const mygame::Vec3& rhs) const { - return lhs.x == rhs.x() && lhs.y == rhs.y() && lhs.z == rhs.z(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::person& lhs, - const mygame::person& rhs) const { - return lhs.id == rhs.id() && lhs.name == rhs.name() && - lhs.age == rhs.age() && - std::abs(lhs.salary - rhs.salary()) < 0.0005f; - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::persons& lhs, - const mygame::persons& rhs) const { - return lhs.person_list == rhs.person_list(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Weapon& lhs, - const mygame::Weapon& rhs) const { - return lhs.name == rhs.name() && lhs.damage == rhs.damage(); - } -}; -bool operator==(const struct_pb_sample::Monster::Color& a, - const mygame::Monster::Color& b) { - return int(a) == int(b); -} -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Monster& lhs, - const mygame::Monster& rhs) const { - auto ok = (lhs.name == rhs.name() && lhs.mana == rhs.mana() && - lhs.hp == rhs.hp() && lhs.inventory == rhs.inventory() && - lhs.color == rhs.color() && lhs.weapons == rhs.weapons() && - lhs.path == rhs.path()); - if (!ok) { - return false; - } - if (lhs.pos && rhs.has_pos()) { - ok = - PB_equal()(*lhs.pos, rhs.pos()); - if (!ok) { - return false; - } - } - else if (lhs.pos || rhs.has_pos()) { - return false; - } - if (lhs.equipped && rhs.has_equipped()) { - ok = PB_equal()(*lhs.equipped, - rhs.equipped()); - if (!ok) { - return false; - } - } - else if (lhs.equipped || rhs.has_equipped()) { - return false; - } - return true; - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Monsters& lhs, - const mygame::Monsters& rhs) const { - return lhs.monsters == rhs.monsters(); - } -}; -template -void check_repeated(const std::vector& a, - const google::protobuf::RepeatedPtrField& b) { - bool ret = (a == b); - REQUIRE(ret); -} -#endif - -TEST_SUITE_BEGIN("test pb benchmark struct"); -TEST_CASE("testing rect") { - auto my_rects = struct_pb_sample::create_rects(OBJECT_COUNT); -#ifdef HAVE_PROTOBUF - auto pb_rects = protobuf_sample::create_rects(OBJECT_COUNT); -#endif - for (int i = 0; i < OBJECT_COUNT; ++i) { - auto my_rect = my_rects.rect32_list[i]; - check_self(my_rect); -#ifdef HAVE_PROTOBUF - auto pb_rect = *(pb_rects.rect32_list().begin() + i); - REQUIRE(my_rect.x == pb_rect.x()); - REQUIRE(my_rect.y == pb_rect.y()); - REQUIRE(my_rect.width == pb_rect.width()); - REQUIRE(my_rect.height == pb_rect.height()); - check_with_protobuf(my_rect, pb_rect); -#endif - } - check_self(my_rects); -#ifdef HAVE_PROTOBUF - check_with_protobuf(my_rects, pb_rects); -#endif -} - -TEST_CASE("testing person") { - auto my_persons = struct_pb_sample::create_persons(OBJECT_COUNT); -#ifdef HAVE_PROTOBUF - auto pb_persons = protobuf_sample::create_persons(OBJECT_COUNT); -#endif - for (int i = 0; i < OBJECT_COUNT; ++i) { - auto my_person = my_persons.person_list[i]; - check_self(my_person); -#ifdef HAVE_PROTOBUF - auto pb_person = *(pb_persons.person_list().begin() + i); - REQUIRE(my_person.id == pb_person.id()); - REQUIRE(my_person.name == pb_person.name()); - REQUIRE(my_person.age == pb_person.age()); - REQUIRE(my_person.salary == pb_person.salary()); - check_with_protobuf(my_person, pb_person); -#endif - } - check_self(my_persons); -#ifdef HAVE_PROTOBUF - check_with_protobuf(my_persons, pb_persons); -#endif -} - -TEST_CASE("testing monsters") { - using namespace struct_pb_sample; - auto my_ms = struct_pb_sample::create_monsters(OBJECT_COUNT); -#ifdef HAVE_PROTOBUF - auto pb_ms = protobuf_sample::create_monsters(OBJECT_COUNT); -#endif - for (int i = 0; i < OBJECT_COUNT; ++i) { - auto& my_m = my_ms.monsters[i]; - check_self(my_m); - -#ifdef HAVE_PROTOBUF - auto pb_m = *(pb_ms.monsters().begin() + i); - REQUIRE(my_m.pos); - REQUIRE(my_m.mana == pb_m.mana()); - REQUIRE(my_m.hp == pb_m.hp()); - REQUIRE(my_m.name == pb_m.name()); - REQUIRE(my_m.inventory == pb_m.inventory()); - REQUIRE(my_m.color == pb_m.color()); - check_repeated(my_m.weapons, pb_m.weapons()); - check_repeated(my_m.path, pb_m.path()); - - check_with_protobuf(my_m, pb_m); -#endif - - std::string my_buf = struct_pb::serialize(my_m); - struct_pb_sample::Monster d_t{}; - auto ok = struct_pb::deserialize_to(d_t, my_buf); - REQUIRE(ok); - CHECK(struct_pb_sample::verify(d_t, my_m)); - REQUIRE(d_t.pos); - REQUIRE(my_m.pos); - CHECK(*d_t.pos == *my_m.pos); - CHECK(d_t.mana == my_m.mana); - CHECK(d_t.hp == my_m.hp); - CHECK(d_t.name == my_m.name); - CHECK(d_t.inventory == my_m.inventory); - CHECK(d_t.color == my_m.color); - REQUIRE(d_t.equipped); - REQUIRE(my_m.equipped); - CHECK(*d_t.equipped == *my_m.equipped); - CHECK(d_t.path == my_m.path); - } - check_self(my_ms); -#ifdef HAVE_PROTOBUF - check_with_protobuf(my_ms, pb_ms); -#endif -} -TEST_SUITE_END; diff --git a/src/struct_pb/tests/test_pb_oneof.cpp b/src/struct_pb/tests/test_pb_oneof.cpp deleted file mode 100644 index 59ceaefc8..000000000 --- a/src/struct_pb/tests/test_pb_oneof.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "doctest.h" -#include "helper.hpp" -#ifdef HAVE_PROTOBUF -#include "test_pb.pb.h" -#endif -using namespace doctest; -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::SubMessageForOneof& t, - const SubMessageForOneof& pb_t) const { - return t.ok == pb_t.ok(); - } -}; -template <> -struct PB_equal { - bool operator()(const test_struct_pb::SampleMessageOneof& t, - const SampleMessageOneof& pb_t) const { - if (int(t.test_oneof_case()) != int(pb_t.test_oneof_case())) { - return false; - } - switch (pb_t.test_oneof_case()) { - case SampleMessageOneof::kB: { - return t.b() == pb_t.b(); - } break; - case SampleMessageOneof::kA: { - return t.a() == pb_t.a(); - } break; - case SampleMessageOneof::kName: { - return t.name() == pb_t.name(); - } break; - case SampleMessageOneof::kSubMessage: { - return PB_equal()(*t.sub_message(), - pb_t.sub_message()); - } break; - case SampleMessageOneof::TEST_ONEOF_NOT_SET: - break; - } - return true; - } -}; -#endif - -namespace std { -template <> -struct equal_to { - bool operator()(const test_struct_pb::SampleMessageOneof& lhs, - const test_struct_pb::SampleMessageOneof& rhs) const { - if (lhs.test_oneof_case() != rhs.test_oneof_case()) { - return false; - } - if (lhs.has_sub_message() && rhs.has_sub_message()) { - return equal_to()(*lhs.sub_message(), - *rhs.sub_message()); - } - return lhs.test_oneof == rhs.test_oneof; - } -}; -} // namespace std - -TEST_CASE("testing oneof, b") { - test_struct_pb::SampleMessageOneof t; - int b = 13298; - t.set_b(b); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - pb_t.set_b(b); - check_with_protobuf(t, pb_t); -#endif -} -TEST_CASE("testing oneof, a") { - test_struct_pb::SampleMessageOneof t; - int a = 66613298; - t.set_a(a); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - pb_t.set_a(a); - check_with_protobuf(t, pb_t); -#endif -} -TEST_CASE("testing oneof, name") { - std::string name = "oneof, name"; - test_struct_pb::SampleMessageOneof t; - t.set_name(name); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - pb_t.set_name(name); - check_with_protobuf(t, pb_t); -#endif -} - -TEST_CASE("testing oneof, submessage") { - test_struct_pb::SampleMessageOneof t; - auto sub = new test_struct_pb::SubMessageForOneof{true}; - t.set_allocated_sub_message(sub); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - auto m = new SubMessageForOneof(); - m->set_ok(true); - pb_t.set_allocated_sub_message(m); - check_with_protobuf(t, pb_t); -#endif -} diff --git a/src/struct_pb/tests/unittest_proto3.h b/src/struct_pb/tests/unittest_proto3.h new file mode 100644 index 000000000..82db6416d --- /dev/null +++ b/src/struct_pb/tests/unittest_proto3.h @@ -0,0 +1,688 @@ +#pragma once + +#include +#if defined(STRUCT_PB_WITH_PROTO) +#include "data_def.pb.h" +#include "unittest_proto3.pb.h" +#endif + +#define PUBLIC(T) : public iguana::base_impl + +// define the struct as msg in proto +namespace stpb { +enum class Enum { + ZERO = 0, + FOO = 1, + BAR = 2, + BAZ = 123456, + NEG = -1, // Intentionally negative. +}; + +struct BaseTypeMsg PUBLIC(BaseTypeMsg) { + BaseTypeMsg() = default; + BaseTypeMsg(int32_t a, int64_t b, uint32_t c, uint64_t d, float e, double f, + bool g, std::string h, Enum i) + : optional_int32(a), + optional_int64(b), + optional_uint32(c), + optional_uint64(d), + optional_float(e), + optional_double(f), + optional_bool(g), + optional_string(std::move(h)), + optional_enum(i) {} + int32_t optional_int32; + int64_t optional_int64; + uint32_t optional_uint32; + uint64_t optional_uint64; + float optional_float; + double optional_double; + bool optional_bool; + std::string optional_string; + Enum optional_enum; + bool operator==(const BaseTypeMsg& other) const { + return optional_int32 == other.optional_int32 && + optional_int64 == other.optional_int64 && + optional_uint32 == other.optional_uint32 && + optional_uint64 == other.optional_uint64 && + optional_float == other.optional_float && + optional_double == other.optional_double && + optional_bool == other.optional_bool && + optional_string == other.optional_string && + optional_enum == other.optional_enum; + } +}; +REFLECTION(BaseTypeMsg, optional_int32, optional_int64, optional_uint32, + optional_uint64, optional_float, optional_double, optional_bool, + optional_string, optional_enum); + +struct IguanaTypeMsg PUBLIC(IguanaTypeMsg) { + IguanaTypeMsg() = default; + IguanaTypeMsg(iguana::sint32_t a, iguana::sint64_t b, iguana::fixed32_t c, + iguana::fixed64_t d = {}, iguana::sfixed32_t e = {}, + iguana::sfixed64_t f = {}) + : optional_sint32(a), + optional_sint64(b), + optional_fixed32(c), + optional_fixed64(d), + optional_sfixed32(e), + optional_sfixed64(f) {} + iguana::sint32_t optional_sint32; + iguana::sint64_t optional_sint64; + iguana::fixed32_t optional_fixed32; + iguana::fixed64_t optional_fixed64; + iguana::sfixed32_t optional_sfixed32; + iguana::sfixed64_t optional_sfixed64; + + bool operator==(const IguanaTypeMsg& other) const { + return optional_sint32 == other.optional_sint32 && + optional_sint64 == other.optional_sint64 && + optional_fixed32 == other.optional_fixed32 && + optional_fixed64 == other.optional_fixed64 && + optional_sfixed32 == other.optional_sfixed32 && + optional_sfixed64 == other.optional_sfixed64; + } +}; +REFLECTION(IguanaTypeMsg, optional_sint32, optional_sint64, optional_fixed32, + optional_fixed64, optional_sfixed32, optional_sfixed64); + +struct RepeatBaseTypeMsg PUBLIC(RepeatBaseTypeMsg) { + RepeatBaseTypeMsg() = default; + RepeatBaseTypeMsg(std::vector a, std::vector b, + std::vector c, std::vector d, + std::vector e, std::vector f, + std::vector g, std::vector h) + : repeated_uint32(std::move(a)), + repeated_uint64(std::move(b)), + repeated_int32(std::move(c)), + repeated_int64(std::move(d)), + repeated_float(std::move(e)), + repeated_double(std::move(f)), + repeated_string(std::move(g)), + repeated_enum(std::move(h)) {} + std::vector repeated_uint32; + std::vector repeated_uint64; + std::vector repeated_int32; + std::vector repeated_int64; + std::vector repeated_float; + std::vector repeated_double; + std::vector repeated_string; + std::vector repeated_enum; +}; + +REFLECTION(RepeatBaseTypeMsg, repeated_uint32, repeated_uint64, repeated_int32, + repeated_int64, repeated_float, repeated_double, repeated_string, + repeated_enum); + +struct RepeatIguanaTypeMsg PUBLIC(RepeatIguanaTypeMsg) { + RepeatIguanaTypeMsg() = default; + RepeatIguanaTypeMsg(std::vector a, + std::vector b, + std::vector c, + std::vector d, + std::vector e, + std::vector f) + : repeated_sint32(std::move(a)), + repeated_sint64(std::move(b)), + repeated_fixed32(std::move(c)), + repeated_fixed64(std::move(d)), + repeated_sfixed32(std::move(e)), + repeated_sfixed64(std::move(f)) {} + std::vector repeated_sint32; + std::vector repeated_sint64; + std::vector repeated_fixed32; + std::vector repeated_fixed64; + std::vector repeated_sfixed32; + std::vector repeated_sfixed64; +}; + +REFLECTION(RepeatIguanaTypeMsg, repeated_sint32, repeated_sint64, + repeated_fixed32, repeated_fixed64, repeated_sfixed32, + repeated_sfixed64); + +struct NestedMsg PUBLIC(NestedMsg) { + NestedMsg() = default; + NestedMsg(BaseTypeMsg a, std::vector b, IguanaTypeMsg c, + std::vector d, std::vector e) + : base_msg(std::move(a)), + repeat_base_msg(std::move(b)), + iguana_type_msg(std::move(c)), + repeat_iguna_msg(std::move(d)), + repeat_repeat_base_msg(std::move(e)) {} + BaseTypeMsg base_msg; + std::vector repeat_base_msg; + IguanaTypeMsg iguana_type_msg; + std::vector repeat_iguna_msg; + std::vector repeat_repeat_base_msg; +}; +REFLECTION(NestedMsg, base_msg, repeat_base_msg, iguana_type_msg, + repeat_iguna_msg, repeat_repeat_base_msg); + +struct MapMsg PUBLIC(MapMsg) { + MapMsg() = default; + MapMsg(std::unordered_map a, + std::unordered_map b, + std::map c) + : sfix64_str_map(std::move(a)), + str_iguana_type_msg_map(std::move(b)), + int_repeat_base_msg_map(std::move(c)) {} + std::unordered_map sfix64_str_map{}; + std::unordered_map str_iguana_type_msg_map{}; + std::map int_repeat_base_msg_map{}; +}; +REFLECTION(MapMsg, sfix64_str_map, str_iguana_type_msg_map, + int_repeat_base_msg_map); + +struct BaseOneofMsg PUBLIC(BaseOneofMsg) { + BaseOneofMsg() = default; + BaseOneofMsg(int32_t a, std::variant b, + double c) + : optional_int32(a), one_of(std::move(b)), optional_double(c) {} + int32_t optional_int32; + std::variant one_of; + double optional_double; +}; +REFLECTION(BaseOneofMsg, optional_int32, one_of, optional_double); + +struct NestOneofMsg PUBLIC(NestOneofMsg) { + NestOneofMsg() = default; + NestOneofMsg(std::variant a) + : nest_one_of_msg(std::move(a)) {} + std::variant nest_one_of_msg; +}; +REFLECTION(NestOneofMsg, nest_one_of_msg); + +struct simple_t PUBLIC(simple_t) { + simple_t() = default; + simple_t(int32_t x, int32_t y, int64_t z, int64_t w, std::string s) + : a(x), b(y), c(z), d(w), str(std::move(s)) {} + int32_t a; + int32_t b; + int64_t c; + int64_t d; + std::string str; +}; +REFLECTION(simple_t, a, b, c, d, str); + +struct simple_t1 PUBLIC(simple_t1) { + simple_t1() = default; + simple_t1(int32_t x, int32_t y, int64_t z, int64_t w, std::string_view s) + : a(x), b(y), c(z), d(w), str(s) {} + int32_t a; + int32_t b; + int64_t c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t1, a, b, c, d, str); + +enum Color : uint8_t { Red, Green, Blue }; + +struct simple_t2 PUBLIC(simple_t2) { + simple_t2() = default; + simple_t2(int16_t x, uint8_t y, Color z, int64_t w, std::string_view s = "") + : a(x), b(y), c(z), d(w), str(s) {} + int16_t a; + uint8_t b; + Color c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t2, a, b, c, d, str); + +struct person { + person() = default; + person(int32_t a, std::string b, int c, double d) + : id(a), name(std::move(b)), age(c), salary(d) {} + int32_t id; + std::string name; + int age; + double salary; +}; +REFLECTION(person, id, name, age, salary); + +struct rect PUBLIC(rect) { + rect() = default; + rect(int32_t a, int32_t b, int32_t c, int32_t d) + : x(a), y(b), width(c), height(d) {} + int32_t x = 1; + int32_t y = 0; + int32_t width = 11; + int32_t height = 1; +}; +REFLECTION(rect, x, y, width, height); + +struct Vec3 PUBLIC(Vec3) { + Vec3() = default; + Vec3(float a, float b, float c) : x(a), y(b), z(c) {} + float x; + float y; + float z; + + REFLECTION(Vec3, x, y, z); +}; + +struct Weapon PUBLIC(Weapon) { + Weapon() = default; + Weapon(std::string a, int32_t b) : name(std::move(a)), damage(b) {} + std::string name; + int32_t damage; +}; +REFLECTION(Weapon, name, damage); + +struct Monster PUBLIC(Monster) { + Monster() = default; + Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, int32_t f, + std::vector g, Weapon h, std::vector i) + : pos(a), + mana(b), + hp(c), + name(std::move(d)), + inventory(std::move(e)), + color(f), + weapons(std::move(g)), + equipped(std::move(h)), + path(std::move(i)) {} + Vec3 pos; + int32_t mana; + int32_t hp; + std::string name; + std::string inventory; + int32_t color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, + path); + +struct bench_int32 PUBLIC(bench_int32) { + bench_int32() = default; + bench_int32(int32_t x, int32_t y, int32_t z, int32_t u) + : a(x), b(y), c(z), d(u) {} + int32_t a; + int32_t b; + int32_t c; + int32_t d; +}; +REFLECTION(bench_int32, a, b, c, d); + +} // namespace stpb + +inline auto create_person() { + stpb::person p{432798, std::string(1024, 'A'), 24, 65536.42}; + return p; +} + +inline stpb::Monster create_sp_monster() { + stpb::Monster m = { + {1, 2, 3}, + 16, + 24, + "it is a test", + "\1\2\3\4", + stpb::Color::Red, + {{"gun", 42}, {"shotgun", 56}}, + {"air craft", 67}, + {{7, 8, 9}, {71, 81, 91}}, + }; + return m; +} + +#if defined(STRUCT_PB_WITH_PROTO) +namespace protobuf_sample { +inline mygame::person create_person() { + mygame::person p; + p.set_id(432798); + p.set_name(std::string(1024, 'A')); + p.set_age(24); + p.set_salary(65536.42); + return p; +} + +inline mygame::Monster create_monster() { + mygame::Monster m; + + auto vec = new mygame::Vec3; + vec->set_x(1); + vec->set_y(2); + vec->set_z(3); + m.set_allocated_pos(vec); + m.set_mana(16); + m.set_hp(24); + m.set_name("it is a test"); + m.set_inventory("\1\2\3\4"); + m.set_color(::mygame::Monster_Color::Monster_Color_Red); + auto w1 = m.add_weapons(); + w1->set_name("gun"); + w1->set_damage(42); + auto w2 = m.add_weapons(); + w2->set_name("shotgun"); + w2->set_damage(56); + auto w3 = new mygame::Weapon; + w3->set_name("air craft"); + w3->set_damage(67); + m.set_allocated_equipped(w3); + auto p1 = m.add_path(); + p1->set_x(7); + p1->set_y(8); + p1->set_z(9); + auto p2 = m.add_path(); + p2->set_x(71); + p2->set_y(81); + p2->set_z(91); + + return m; +} +} // namespace protobuf_sample + +void SetBaseTypeMsg(const stpb::BaseTypeMsg& st, pb::BaseTypeMsg& msg) { + msg.set_optional_int32(st.optional_int32); + msg.set_optional_int64(st.optional_int64); + msg.set_optional_uint32(st.optional_uint32); + msg.set_optional_uint64(st.optional_uint64); + msg.set_optional_float(st.optional_float); + msg.set_optional_double(st.optional_double); + msg.set_optional_bool(st.optional_bool); + msg.set_optional_string(st.optional_string); + msg.set_optional_enum(static_cast(st.optional_enum)); +} + +void CheckBaseTypeMsg(const stpb::BaseTypeMsg& st, const pb::BaseTypeMsg& msg) { + CHECK(st.optional_int32 == msg.optional_int32()); + CHECK(st.optional_int64 == msg.optional_int64()); + CHECK(st.optional_uint32 == msg.optional_uint32()); + CHECK(st.optional_uint64 == msg.optional_uint64()); + CHECK(st.optional_float == msg.optional_float()); + CHECK(st.optional_double == msg.optional_double()); + CHECK(st.optional_bool == msg.optional_bool()); + CHECK(st.optional_string == msg.optional_string()); + CHECK(static_cast(st.optional_enum) == + static_cast(msg.optional_enum())); +} + +void SetIguanaTypeMsg(const stpb::IguanaTypeMsg& st, pb::IguanaTypeMsg& msg) { + msg.set_optional_sint32(st.optional_sint32.val); + msg.set_optional_sint64(st.optional_sint64.val); + msg.set_optional_fixed32(st.optional_fixed32.val); + msg.set_optional_fixed64(st.optional_fixed64.val); + msg.set_optional_sfixed32(st.optional_sfixed32.val); + msg.set_optional_sfixed64(st.optional_sfixed64.val); +} + +void CheckIguanaTypeMsg(const stpb::IguanaTypeMsg& st, + const pb::IguanaTypeMsg& msg) { + CHECK(st.optional_sint32.val == msg.optional_sint32()); + CHECK(st.optional_sint64.val == msg.optional_sint64()); + CHECK(st.optional_fixed32.val == msg.optional_fixed32()); + CHECK(st.optional_fixed64.val == msg.optional_fixed64()); + CHECK(st.optional_sfixed32.val == msg.optional_sfixed32()); + CHECK(st.optional_sfixed64.val == msg.optional_sfixed64()); +} + +void SetRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st, + pb::RepeatBaseTypeMsg& msg) { + for (auto v : st.repeated_uint32) { + msg.add_repeated_uint32(v); + } + for (auto v : st.repeated_uint64) { + msg.add_repeated_uint64(v); + } + for (auto v : st.repeated_int32) { + msg.add_repeated_int32(v); + } + for (auto v : st.repeated_int64) { + msg.add_repeated_int64(v); + } + for (auto v : st.repeated_float) { + msg.add_repeated_float(v); + } + for (auto v : st.repeated_double) { + msg.add_repeated_double(v); + } + for (auto v : st.repeated_string) { + msg.add_repeated_string(v); + } + for (auto v : st.repeated_enum) { + msg.add_repeated_enum(static_cast(v)); + } +} + +void CheckRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st, + const pb::RepeatBaseTypeMsg& msg) { + for (size_t i = 0; i < st.repeated_uint32.size(); ++i) { + CHECK(st.repeated_uint32[i] == msg.repeated_uint32(i)); + } + for (size_t i = 0; i < st.repeated_uint64.size(); ++i) { + CHECK(st.repeated_uint64[i] == msg.repeated_uint64(i)); + } + for (size_t i = 0; i < st.repeated_int32.size(); ++i) { + CHECK(st.repeated_int32[i] == msg.repeated_int32(i)); + } + for (size_t i = 0; i < st.repeated_int64.size(); ++i) { + CHECK(st.repeated_int64[i] == msg.repeated_int64(i)); + } + for (size_t i = 0; i < st.repeated_float.size(); ++i) { + CHECK(st.repeated_float[i] == msg.repeated_float(i)); + } + for (size_t i = 0; i < st.repeated_double.size(); ++i) { + CHECK(st.repeated_double[i] == msg.repeated_double(i)); + } + for (size_t i = 0; i < st.repeated_string.size(); ++i) { + CHECK(st.repeated_string[i] == msg.repeated_string(i)); + } + for (size_t i = 0; i < st.repeated_enum.size(); ++i) { + CHECK(static_cast(st.repeated_enum[i]) == + static_cast(msg.repeated_enum(i))); + } +} + +void SetRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st, + pb::RepeatIguanaTypeMsg& msg) { + for (auto v : st.repeated_sint32) { + msg.add_repeated_sint32(v.val); + } + for (auto v : st.repeated_sint64) { + msg.add_repeated_sint64(v.val); + } + for (auto v : st.repeated_fixed32) { + msg.add_repeated_fixed32(v.val); + } + for (auto v : st.repeated_fixed64) { + msg.add_repeated_fixed64(v.val); + } + for (auto v : st.repeated_sfixed32) { + msg.add_repeated_sfixed32(v.val); + } + for (auto v : st.repeated_sfixed64) { + msg.add_repeated_sfixed64(v.val); + } +} + +void CheckRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st, + const pb::RepeatIguanaTypeMsg& msg) { + for (size_t i = 0; i < st.repeated_sint32.size(); ++i) { + CHECK(st.repeated_sint32[i].val == msg.repeated_sint32(i)); + } + for (size_t i = 0; i < st.repeated_sint64.size(); ++i) { + CHECK(st.repeated_sint64[i].val == msg.repeated_sint64(i)); + } + for (size_t i = 0; i < st.repeated_fixed32.size(); ++i) { + CHECK(st.repeated_fixed32[i].val == msg.repeated_fixed32(i)); + } + for (size_t i = 0; i < st.repeated_fixed64.size(); ++i) { + CHECK(st.repeated_fixed64[i].val == msg.repeated_fixed64(i)); + } + for (size_t i = 0; i < st.repeated_sfixed32.size(); ++i) { + CHECK(st.repeated_sfixed32[i].val == msg.repeated_sfixed32(i)); + } + for (size_t i = 0; i < st.repeated_sfixed64.size(); ++i) { + CHECK(st.repeated_sfixed64[i].val == msg.repeated_sfixed64(i)); + } +} + +void SetNestedMsg(const stpb::NestedMsg& st, pb::NestedMsg& msg) { + SetBaseTypeMsg(st.base_msg, *msg.mutable_base_msg()); + + for (const auto& base_msg : st.repeat_base_msg) { + auto* base_msg_ptr = msg.add_repeat_base_msg(); + SetBaseTypeMsg(base_msg, *base_msg_ptr); + } + + SetIguanaTypeMsg(st.iguana_type_msg, *msg.mutable_iguana_type_msg()); + + for (const auto& iguana_type_msg : st.repeat_iguna_msg) { + auto* iguana_type_msg_ptr = msg.add_repeat_iguna_msg(); + SetIguanaTypeMsg(iguana_type_msg, *iguana_type_msg_ptr); + } + + for (const auto& repeat_base_msg : st.repeat_repeat_base_msg) { + auto* repeat_base_msg_ptr = msg.add_repeat_repeat_base_msg(); + SetRepeatBaseTypeMsg(repeat_base_msg, *repeat_base_msg_ptr); + } +} + +void CheckNestedMsg(const stpb::NestedMsg& st, const pb::NestedMsg& msg) { + CheckBaseTypeMsg(st.base_msg, msg.base_msg()); + + CHECK(st.repeat_base_msg.size() == msg.repeat_base_msg_size()); + for (size_t i = 0; i < st.repeat_base_msg.size(); ++i) { + CheckBaseTypeMsg(st.repeat_base_msg[i], msg.repeat_base_msg(i)); + } + + CheckIguanaTypeMsg(st.iguana_type_msg, msg.iguana_type_msg()); + + CHECK(st.repeat_iguna_msg.size() == msg.repeat_iguna_msg_size()); + for (size_t i = 0; i < st.repeat_iguna_msg.size(); ++i) { + CheckIguanaTypeMsg(st.repeat_iguna_msg[i], msg.repeat_iguna_msg(i)); + } + + CHECK(st.repeat_repeat_base_msg.size() == msg.repeat_repeat_base_msg_size()); + for (size_t i = 0; i < st.repeat_repeat_base_msg.size(); ++i) { + CheckRepeatBaseTypeMsg(st.repeat_repeat_base_msg[i], + msg.repeat_repeat_base_msg(i)); + } +} + +void SetMapMsg(const stpb::MapMsg& st, pb::MapMsg& msg) { + msg.Clear(); + for (const auto& pair : st.sfix64_str_map) { + (*msg.mutable_sfix64_str_map())[pair.first.val] = pair.second; + } + for (const auto& pair : st.str_iguana_type_msg_map) { + pb::IguanaTypeMsg* it_msg = + &((*msg.mutable_str_iguana_type_msg_map())[pair.first]); + SetIguanaTypeMsg(pair.second, *it_msg); + } + for (const auto& pair : st.int_repeat_base_msg_map) { + pb::RepeatBaseTypeMsg* rb_msg = + &((*msg.mutable_int_repeat_base_msg_map())[pair.first]); + SetRepeatBaseTypeMsg(pair.second, *rb_msg); + } +} + +void CheckMapMsg(const stpb::MapMsg& st, const pb::MapMsg& msg) { + CHECK(msg.sfix64_str_map_size() == st.sfix64_str_map.size()); + for (const auto& pair : st.sfix64_str_map) { + auto it = msg.sfix64_str_map().find(pair.first.val); + CHECK(it != msg.sfix64_str_map().end()); + CHECK(it->second == pair.second); + } + CHECK(msg.str_iguana_type_msg_map_size() == + st.str_iguana_type_msg_map.size()); + for (const auto& pair : st.str_iguana_type_msg_map) { + auto it = msg.str_iguana_type_msg_map().find(pair.first); + CHECK(it != msg.str_iguana_type_msg_map().end()); + CheckIguanaTypeMsg(pair.second, it->second); + } + + CHECK(msg.int_repeat_base_msg_map_size() == + st.int_repeat_base_msg_map.size()); + for (const auto& pair : st.int_repeat_base_msg_map) { + auto it = msg.int_repeat_base_msg_map().find(pair.first); + CHECK(it != msg.int_repeat_base_msg_map().end()); + CheckRepeatBaseTypeMsg(pair.second, it->second); + } +} + +void SetBaseOneofMsg(const stpb::BaseOneofMsg& st, pb::BaseOneofMsg& msg) { + msg.set_optional_int32(st.optional_int32); + msg.set_optional_double(st.optional_double); + + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + msg.set_one_of_double(value); + } + else if constexpr (std::is_same_v) { + msg.set_one_of_string(value); + } + else if constexpr (std::is_same_v) { + auto* submsg = msg.mutable_one_of_base_type_msg(); + SetBaseTypeMsg(value, *submsg); + } + }, + st.one_of); +} + +void CheckBaseOneofMsg(const stpb::BaseOneofMsg& st, + const pb::BaseOneofMsg& msg) { + CHECK(st.optional_int32 == msg.optional_int32()); + CHECK(st.optional_double == msg.optional_double()); + + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + CHECK(value == msg.one_of_double()); + } + else if constexpr (std::is_same_v) { + CHECK(value == msg.one_of_string()); + } + else if constexpr (std::is_same_v) { + CheckBaseTypeMsg(value, msg.one_of_base_type_msg()); + } + }, + st.one_of); +} + +void SetNestOneofMsg(const stpb::NestOneofMsg& st, pb::NestOneofMsg& msg) { + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + msg.set_base_one_of_string(value); + } + else if constexpr (std::is_same_v) { + auto* submsg = msg.mutable_base_one_of_msg(); + SetBaseOneofMsg(value, *submsg); + } + }, + st.nest_one_of_msg); +} + +void CheckNestOneofMsg(const stpb::NestOneofMsg& st, + const pb::NestOneofMsg& msg) { + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + CHECK(value == msg.base_one_of_string()); + } + else if constexpr (std::is_same_v) { + CheckBaseOneofMsg(value, msg.base_one_of_msg()); + } + }, + st.nest_one_of_msg); +} +#endif + +inline void print_hex_str(const std::string& str) { + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (unsigned char c : str) { + oss << std::setw(2) << static_cast(c); + } + std::cout << oss.str() << std::endl; +} diff --git a/src/struct_pb/tests/unittest_proto3.proto b/src/struct_pb/tests/unittest_proto3.proto new file mode 100644 index 000000000..c736d6ef3 --- /dev/null +++ b/src/struct_pb/tests/unittest_proto3.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +package pb; + +option optimize_for = SPEED; + +enum Enum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 123456; + NEG = -1; // Intentionally negative. +} + +message BaseTypeMsg { + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + float optional_float = 5; + double optional_double = 6; + bool optional_bool = 7; + string optional_string = 8; + Enum optional_enum = 9; +} + +message RepeatBaseTypeMsg { + repeated uint32 repeated_uint32 = 1; + repeated uint64 repeated_uint64 = 2; + repeated int32 repeated_int32 = 3; + repeated int64 repeated_int64 = 4; + repeated float repeated_float = 5; + repeated double repeated_double = 6; + repeated string repeated_string = 7; + repeated Enum repeated_enum = 8; +} + +message IguanaTypeMsg { + sint32 optional_sint32 = 1; + sint64 optional_sint64 = 2; + fixed32 optional_fixed32 = 3; + fixed64 optional_fixed64 = 4; + sfixed32 optional_sfixed32 = 5; + sfixed64 optional_sfixed64 = 6; +} + +message RepeatIguanaTypeMsg { + repeated sfixed32 repeated_sint32 = 1; + repeated sfixed64 repeated_sint64 = 2; + repeated fixed32 repeated_fixed32 = 3; + repeated fixed64 repeated_fixed64 = 4; + repeated sfixed32 repeated_sfixed32 = 5; + repeated sfixed64 repeated_sfixed64 = 6; +} + +message NestedMsg { + BaseTypeMsg base_msg = 1; + repeated BaseTypeMsg repeat_base_msg = 2; + IguanaTypeMsg iguana_type_msg = 3; + repeated IguanaTypeMsg repeat_iguna_msg = 4; + repeated RepeatBaseTypeMsg repeat_repeat_base_msg = 5; +} + +message MapMsg { + map sfix64_str_map = 1; + map str_iguana_type_msg_map = 2; + map int_repeat_base_msg_map = 3; + // Key in map fields cannot be float/double, bytes or message types. +} + +message BaseOneofMsg { + int32 optional_int32 = 1; + oneof one_of { + double one_of_double = 2; + string one_of_string = 3; + BaseTypeMsg one_of_base_type_msg = 4; + } + double optional_double = 5; +} + +message NestOneofMsg { + oneof nest_one_of_msg { + string base_one_of_string = 1; + BaseOneofMsg base_one_of_msg = 2; + } +} + +message Simple { + int32 a = 1; + int32 b = 2; + int64 c = 3; + int64 d = 4; + string str = 5; +} + +enum Color { + Red = 0; + Green = 1; + Blue = 2; +} + +message Simple2 { + int32 a = 1; + int32 b = 2; + Color c = 3; + int64 d = 4; + string str = 5; +} \ No newline at end of file diff --git a/website/.vitepress/config/en_data.ts b/website/.vitepress/config/en_data.ts index 76b640ecb..b6857637d 100644 --- a/website/.vitepress/config/en_data.ts +++ b/website/.vitepress/config/en_data.ts @@ -1,36 +1,31 @@ export const guidLinks = [ - {text: 'Introduce YalantingLibs', link: '/en/guide/what_is_yalantinglibs'}, - {text: 'Use as Git Submodule', link: '/en/guide/how_to_use_as_git_submodule'}, - {text: 'Use by CMake find_package', link: '/en/guide/how_to_use_by_cmake_find_package'}, + { text: 'Introduce YalantingLibs', link: '/en/guide/what_is_yalantinglibs' }, + { text: 'Use as Git Submodule', link: '/en/guide/how_to_use_as_git_submodule' }, + { text: 'Use by CMake find_package', link: '/en/guide/how_to_use_by_cmake_find_package' }, ]; //构建系统相关语法 export const struct_pb_Links = [ - {text: 'What is struct_pb?', link: '/en/struct_pb/struct_pb_intro'}, - {text: 'Quick Start', link: '/en/struct_pb/struct_pb_quick_start'}, - {text: 'Supported Features', link: '/en/struct_pb/struct_pb_supported_features'}, - {text: 'Guide (proto3)', link: '/en/struct_pb/struct_pb_guide_proto3'}, - {text: 'Generating your struct', link: '/en/struct_pb/struct_pb_generating_your_struct'}, - {text: 'struct_pb API', link: '/en/struct_pb/struct_pb_api'}, + { text: 'What is struct_pb?', link: '/en/struct_pb/struct_pb_intro' } ]; export const struct_pack_Links = [ - {text: 'What is struct_pack?', link: '/en/struct_pack/struct_pack_intro'}, - {text: 'struct_pack tips', link: '/en/struct_pack/struct_pack_tips'}, - {text: 'struct_pack layout', link: '/en/struct_pack/struct_pack_layout'}, - {text: 'struct_pack type system', link: '/en/struct_pack/struct_pack_type_system'}, - {text: 'API Reference', link: "https://alibaba.github.io/yalantinglibs/doxygen_en/html/group__struct__pack.html"} + { text: 'What is struct_pack?', link: '/en/struct_pack/struct_pack_intro' }, + { text: 'struct_pack tips', link: '/en/struct_pack/struct_pack_tips' }, + { text: 'struct_pack layout', link: '/en/struct_pack/struct_pack_layout' }, + { text: 'struct_pack type system', link: '/en/struct_pack/struct_pack_type_system' }, + { text: 'API Reference', link: "https://alibaba.github.io/yalantinglibs/doxygen_en/html/group__struct__pack.html" } ]; export const coro_rpc_Links = [ - {text: 'coro_rpc introduction', link: '/en/coro_rpc/coro_rpc_introduction'}, - {text: 'coro_rpc client', link: '/en/coro_rpc/coro_rpc_client'}, - {text: 'coro_rpc server', link: '/en/coro_rpc/coro_rpc_server'}, + { text: 'coro_rpc introduction', link: '/en/coro_rpc/coro_rpc_introduction' }, + { text: 'coro_rpc client', link: '/en/coro_rpc/coro_rpc_client' }, + { text: 'coro_rpc server', link: '/en/coro_rpc/coro_rpc_server' }, ]; export const aboutLinks = [ - {text: 'purecpp', link: '/en/about/community'}, - {text: 'contribute', link: '/en/about/contribute'}, - {text: 'community', link: '/en/about/teams'}, - {text: 'team', link: '/en/about/yalantingUser'}, + { text: 'purecpp', link: '/en/about/community' }, + { text: 'contribute', link: '/en/about/contribute' }, + { text: 'community', link: '/en/about/teams' }, + { text: 'team', link: '/en/about/yalantingUser' }, ]; diff --git a/website/.vitepress/config/zh_data.ts b/website/.vitepress/config/zh_data.ts index 5ef2088f0..72c6b13cb 100644 --- a/website/.vitepress/config/zh_data.ts +++ b/website/.vitepress/config/zh_data.ts @@ -6,12 +6,7 @@ export const guidLinks = [ //构建系统相关语法 export const struct_pb_Links = [ - { text: 'struct_pb简介', link: '/zh/struct_pb/struct_pb_intro' }, - { text: '快速开始', link: '/zh/struct_pb/struct_pb_quick_start' }, - { text: '特性支持', link: '/zh/struct_pb/struct_pb_supported_features' }, - { text: '使用proto3', link: '/zh/struct_pb/struct_pb_guide_proto3' }, - { text: '生成结构体', link: '/zh/struct_pb/struct_pb_generating_your_struct' }, - { text: 'struct_pb API', link: '/zh/struct_pb/struct_pb_api' }, + { text: 'struct_pb简介', link: '/zh/struct_pb/struct_pb_intro' } ]; export const struct_pack_Links = [ diff --git a/website/docs/en/guide/what_is_yalantinglibs.md b/website/docs/en/guide/what_is_yalantinglibs.md index 3c253e96f..7b99e6274 100644 --- a/website/docs/en/guide/what_is_yalantinglibs.md +++ b/website/docs/en/guide/what_is_yalantinglibs.md @@ -504,11 +504,9 @@ No dependency. No dependency. -### struct_pb (optional) +### struct_pb -In default, struct_pb wont be installed. You need install protobuf manually. - -- [protobuf](https://protobuf.dev/) +No dependency. ## Standalone sublibraries diff --git a/website/docs/en/struct_pb/images/struct_pb_overview.jpeg b/website/docs/en/struct_pb/images/struct_pb_overview.jpeg deleted file mode 100644 index be0978d4051936fc9c949bfc36ead2482daf4fa8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68961 zcmeFZ2VB$1wm2SpMHi7G#X^OZQfP^9jDG3k+ zDH4hW>CF&A=qSB~UIYYw*?aG<-uL$IyZi3G_j&LCf0Ob(-!n7koSE;OneUuAGrQfp z9|7O#YUyYJ_Ur)w_OL#H-Qm3#bu=`rZWF9(160w&DzzX}n2LN2%ywS$m*Uy`p znV*w&Z z#K-O2;851pl=b5Wcma$7+JNgU_)iUA>(iY804S^i0Q(+&#aSl-0A=?90G{5jIN@{v z;N(vLKxw$CU=Wj)Wz!_O+G zJL}^BZ~@o>&I5D+ZU7sAGz+>6_#SWxAh+8G&;T6Vf8gMO{Ra;oIC$vL!NW(tJ9_lU zk)x+ioIL&=_h}v;?$cacyaFQUc=?3*xwy_to);1o69bE{b3LnaG|) zhYlS*e3awpQI3neT)Y?maM*nVU_ZP+?10?9J%WI}?0fdH@7aCND!?9AtKRqX-!I|N z!F~G=?Ad#m6>Ie!V9&mNtS{TK!-x0pJ9uy(V9#Dw>_PTJr!HK&)^V8QG#9s^5!~dq zXWZk$7!xDTSJ3t+|BzKtWI zvpPd3Z_Tz2FzGa;Jhx%5|Mnnvj+5T6?l5$s=Ui6qJnyZ4z%*=CGxXL- zNQ4^g*q#4-Q2(Hk{!7sRe|}IZE!b_BIwtv*<#dmZ7DI>&K_HO?trGYT=z zaWJc+dshBZ@%z`dWZhfnR|0Pf5cZlv8vGbRz;3^ft^lF!isS4THxGkrR zjccw57JRT#E*{bxIT;rbd%)9Ox-0Gif;WVK3!QG$YgveM}QfPc9NsII8i;y`T0QgAD^ zz@`&ZTE(+6jL(QMGVY9n)0c)(79t`G$07?Js_n$T1Qn{iaPhn;vSSQ` zqdDPtp+{x6a*6o~o7m}%ufz3}4qpD_-~J z8}CgAfCXXg^#&3RoqMxm-xf=lv`k6l%m>HE8Hw3;)pozg1)gb|#D~9M7jMX?A_>bR zrxB!2hD9RO#w0b>pj#%C)_Yz!W~7KB8lciY&2#!9j7qy zuApKCT%dKWtE6_ngb*%PX7vZuL;D>^S2Ho zLl9|5x$;7~NPsXyN{TlTfrFV_+(^`Ve~vE&(??o$4Cpwv;U>9c5^c(n~t@ z`dW;=shqDv(fB%#j8AgkX04RV%~CP2TuwM$Q*#3Lk+PL<H;DqprPlrc{_`XM7ZlcXin^Y!lA>GPYNcJ;zg z2Y<3u!RJD;XT>$kR=2L)2;>}-Q#py>ScSnl=UnM8yO%0u zE}Q#{mGqJX1l%nkV-W==1ZBg)kxx{`55v7{9iDyFhu{wN5+fBzx5-{q0LnghU`P=J zhbVZA8X(~cd&X9^^*pLv=I(C0R)Ag&=zA|o?IZS82@R6QUx&uaf;9)0`NRebl$Cnu z?-mmWdP0(tQ^UKbk_-vu?D;rfDAu_ak*EokD%p~PKP5H|xu#aoK3t9|;j1(vL)iO+ z_?n*$_PVU}X?2%qEQ)wU~lALdS7)QMwlZb;pmeXjFxUE#CsVC1o}U2 z?JK2)Wu0Mb3w-R7Yo{bJ$*!I?6F%gDTUh{)E1(I94A~qaF4AzY*sD#^alV z|Knd1YMJ+V3VRoT)47-|EdE(R#HkyfP>Sr9_{ntRJcg1*EjjIzdmP!gQ$9F~3JrS} zG~rP{8}@OyakFfD1oz|5%JAoeQ*OV$`eCKT=gr%f6++%|kbeWYXZrUzhRtq$>JwU_ z2ao98IoY#bQ>r~h+Nw)rWl>t^J*t<=|2Pq79zfBN9eUu`p`{F_gHQy*qNY_k7_7&( z&(S*T&SOY)zFcY{LF*w6(&;XW_nb!;fZ!Y`K#C<(6Usy?TQ!U5|$k5U8R=2l?p2Rp$O(H@ z0&$vjgU|ck#2u?0dnM)lg!zn)Wv(W5dgjItWs*~>y@vksq`#fG{6XWv4?bfHo>rR; zA&Xg`-!Pj$4!>S~v^{cl-sRUOd?&i+W8=t>96PcU5Tg}@ATnU@Kp!6Ha^Jmk4hu7hd_G*D5bqHcm_SJXWUyX;qon`Mi zI{UU4Zc}(mpJnO!I!FHP)PINN5hxGhN9+`xt8}XVUK#yapE?($%(u$fp*=LFmizR2zQaa}`t2i(e~$yOtn>dk zd~2-xrnCIh27F)wg}; ziq74O6q_DekCOYltpD1L4ke>%#zHOdOVq_z*;UT!EuXdy8~g_DP|ol0`BvZlOKpJ% zzfm{$hbQ{0Pe|+n%uWu=>;Z#>(NzVMr=o9qHAJzxBe)PFE)FN7{IZ{D*!H0lYi zRh=>0aX8t19rN#TS5>e64(0DubjQG`K6`DbSMJ>ew#|gq#xxwnM3btp98Vs+6nd^N zIMDDEvna)F%8OJ$a&@pG#&k4R$VF7K0@A-iyl#Kv zt?kb9I+|HsmF4iNOJWl=_ZO}&Nol`|bK+O%{{;J5 zW7cvb{-uL%ueO-*6*?}OEYx*|y^ln;$4@m_HMRr_)Fug8b}>+Nu;CQzsTuwFI}PV= zQUBX})c?4I|2W0*Zxnv$YehH;FuzgwOIzQJE&q_#zGc~m55$_U^zrMX%G=SCIL%>F zZp)7$cWSiZh8FrwSjFL->`*Q}4l2`EKmq7sDfT^!)`_YE!2<8N^{&AU;T*T}5N`!l zb4JG?M*eJe_FyW|8-dfYX^ z8}(iuXbN$y?6f}jDn`4|t@REX6tr}; z6P;D$$n0c*VZ*suSPIIx=;SnCVr%9WP>+&8%pvr|8tQiW!06~Ty%=TYD3TXjZ9n;1 z_w&`kAN(_)$`@0r8zu2t%*OPjoSxghcN$4Mop8f$Yld5QXN>B_{B;VYu2on<`@j{X z^g|kgB($PMUJIwpy!8_}E_iWr^Z6C?KpWm(@ryS2XL%6b9!9>5ywbcXqK%}KIQ4^@ zVhp`hR75{9$=Vz5+f-MG?PR>cu7`Y(J5${;`{dpvamLIHfzGp51M(`w>XZcm@dPpE z2w{pGHgTZWHBP47(B&?02GhkguN3v^6j&%O)jT|xoOZ(MQglzACyY7c2$w&YLH-_7 z3Z2g)b(eEO-@X;v&Yp1ftTil=N-{ALl$#Q%$*XEH*jQL?pc*xQ)b!c~_`mTtbL&J+ z`p}%QyectLFwgb_kZPrn%|hl(zK)RnTC`h5ZY9OTt+Li+E3GGw2Pb;Xe-^J4kadY_ z+FLi-FdxIZQ(xG7tdvVlvR zA&clZHmB;3W#{A0h*{#;oARAMmvd+aETFRwjP8?&aJA3u({C^#4?TwUp_FLij;E6S zSDfE+TDCHIBAaWBqZ61GXKT^Ck)WRVMmXmc6uV6X*`=aQQ|n4K-IB88loej7KiJN_ z3uqr8h^bp-Z%HX^ojOV;X;%|OZ%hXQA*aeg10gvB(DsbPwL4jfC=*JM^*|80WKjGE za)Dluhu%I53CkQ(loz})!`lD`x4M+yI1lR{S4aAhZQHXlaCR{-2oiLTH`pBfws14) zw$YP8*>!20>sl%t5u@D5X3%%Gdkq?!+m8chnoL)7!Zde)hjK;j9PS;xC!U|wnLs4= z7}JwDLbVAJ76jn*7z4tNh=@q*wT-%D!GZC8vqz;Y+cE^Br0ea7OMApSh&D>0mVkIB&I+%0vG5D@f`gp^Mgn3jl zMLK12e>O>7Ij^vX=qTw%=`hj#OfnwP9}w>X4H=X%*n>MJBePQQp5m`ejJObP_@ZNW zUH#perU}aNO4rw=!z&uXb4i{wtE1xIPscxqdTNuPd9QhXPo$`6h$}& zB0EA#SU41yU`6x{@+n>RuR^5{!e zr*yL@Kq7eVlR?a7v+>L<=On|*PM?u}vgRPf8wQ4f84)=ZR{1@0%`);9s@Dy*Rf{ss znX)h#t|1>b4zsjbEbP_gku!_Z2J;8on~SQ!G$8^)$$9wCh(P}%Q7uoJf}qYT-cl&@ z^Er9C$U%rwe+0q5%!22foK=a1^p%&+0tGL~iMrE%w!!*7n<1|rGtJV7)ufz=n&^+F z3lAwYycwTYVar5KWnQczhtG}FO=$xq8K%aWPAWwEL}PwO2Pi^isbxA*P!L!p>;<)2 z$q2dE(&KGp#H@ELE-k%OO21*bV(o}agurDD=ap_slqoeZyLu@-)Midu!=%ag^rkKX zX=>u5-d4p3^d_{^!gam*r=m+8dWH~vMs-rom>X+6;6T!0RK(pZ3hJhpy8rsn6T@}4 z?*;U|J3VHzuqcy4pjes%tegW|bv7sb^`zF$2f1#!+m5X+L^Mlw&8YrZ@xRIrL3{>2 zlj-IhetND)RKq9Vwje9xRcEV^wI(9hD26oobBn&{Q|fx!J20r1Q>yTxT{%@lIK1s} z91w&E`&Bq=2<{-Qx&N*f71Z;rXSc`av@lhKmHy7RqLr&e5g|CR6 zlDMztuat6SqL0o$aSO<8bsW|0y9?Oidvi0Ec2y1uv`L!5JT#z2F6p+#tEf?w90BB9VoDdN<;z179b*f;Cyo^i=nN z+%^03a&Yvexq&+kj81pSW?s_twrW@IT)Fz~8jrp-`5RR}%E3#deuj|nt82QE2K6#* z^6`!2$eJ)JQT6H8Sz1U*=+1JaW@+yYA03gZN0-F;>`gZZBeGH*wl`K6?qnACJ4vrK zS=^`Cw`)Ur^-kkPz2FJ~sz-eq%b>|A%&2bPcmy~{lkt`@Dt`Xk*On8!3<<{xFSt=7 zUp%McEB^Wep*tf+n`NOd&b3ttzO?JpeBTvVYUlr~l&1grnYn-e%eEba;u3H=A2O8U;x$ZYx{?$|=;cJcBX3HgF5KYPpKjgz%<-&yPs0b6`|JW#v`mzf05mZ`9`&WK4(1*7BJqwEzM=r9Pv0GQ?thBF>S_V;=(H+$Cj zq~d50bm@nZffx>6qL^tY+bC*r)QcL#n=MC5^ZBrrs8M{&w?vW)UrL$4c)P?{ovQ2g zqc%)P#0MY7vfgEK3x1NdfV7b@TrIkcF!e&R8PxPM3E2!emBDRg5Y2Mbunazt8q&U; zVhs#T5P5=>!7Mh=(;iI76⪚AQO&hILv}{PS^?BrO31^*Y4VKnfu;ShT$H;HF%}J z6bhNr(IGP>3+~PhSRXQ<$MXuX9{A;!D|~Rvc&+3-p8Haae5z$m<)9r^5$?CgIy-Rm zu6#3Ztq>kNNjLIE7>JWRkSBXS-y>t5Z0<~04nVeBeSM2ZvMTFme^HP>$2j&2wg1fZ zk5AV0xQ2;RRaG{}a=Kbd#4L+s5>2&)|g8^C1Knw)V@t~Rw1g6Rk*Z5d( z*&CFLLW7fjc{qj&g)J1QE6os_6KCfnU-Fbt2guNnTV_#%f6V^-K6D<8c@B+`h8$wI)A@1YL>y ze4Aqe-bc1YlwYCIs1%L|#D>TkjUNE9P?y*-ukxFQDdU_;2Lz5sNXqK%1@on(V0Sh! z+xU&o@hRf^N+RTY!auF4{Qj|T!!%LNQhdah47>_+X;gsHFvgZN->~Zu@Jpj zE0WCm+{-RO{Eb+y>$MD+Gdscnz97c=>3#Z-qQ2Wt;GGUdW2WPJP`f;$GarKE2OW#c zAYOdna~ceVCM*sI7TykaM{(E-JT17DK7024j7sW~^xDpPa-8oJ=;QJ651zdIeP_~I zJp+er`eU_aL#D+!Vj5Duknnz-I;%bnGK^deW|C+y(t}_l?=(CMvoUJGgO+?Z8?&Xc zl@w3OACE(7988)^+b&*`sOTanDfta!i4Xe&g>8I|wX$*vOAB;A;IkN?`gvakab}O2 zzh`;(GcUx8juWL*MwQ_c^S}aH!3Q(I8U2YvWp=N8or}s>ys4|z^+6XSyWlB&1R0=H zjp5#;2ZJOZBb(E4nyrpZzConRx3W#}GbfQ~Z7tTL&&>dw<` zjmCDlFpVUadZ{cz@nDYC0U==of+iIXV;+;6OYp<}+ zqW!6U7r&b|v_~|)2)t65*Zaw#?3UyCoScjqB!+kWJw2d~Ich>6ktWm58snlra?OSU za%-7}-Y%rOremZ)-?R;3>k?bE2P64GWq7!=(qXVXpyJ3Gf+ zL9t5>`z>jO$<>N3QOT#Mb{%Zp5xoa6&YCe~nE~9lPJNq1e@9nfRA^^#(Yv-og^4 z4$!TfF>1;*e%k%bxfU)ITP&jkh7i>YDEiQ_u12VrGPE!_Hs@90cZpd))EXlJm;_WJt)zlo<-0LjbEWf6D_Q-|}q~6`f*LrCeU{JIRs2N(G znycKg!AKR5ZQP4jnes%gMDpA&z{@uf5|Rp1J%7;Ifv3#r3Fbi9OJ(^&6Y$KobN;;h zjft&P1Vp}gY+N?|@5Ty+X&W=AF&rtpz`BGpXc7&$#3xuY{i6RYpGdE+c~XyTtm231 zaiAi`&^!F~n?8agUW~OX0xc9{)PRj_!UE3m)D`A*fp|MdH6h<^5=oAgKLRwVvIZJU z4c)bH8(zAl1i^{82{_rzQ|J7utIQvRgy8sLG`cB6#ojZzt4-2 zUOy})*Nfe(+Nr-&u_VDuHYrQ>Hn2627{4m2`tLnXge%YuuH5~)y<6aS_*~s$bgBG$ zE2JJ>7O(bL-bAvlR@?DK-+<=>)W#2YxoB^yJh!I1vaq;yb%P&W|DN-oclYhoX#kc- zGz8KzOl(neLK~dD9*kDvfp)oM?bzG&(j?}pECLjRFNB|cZ&Jkx4ZJ(^*8j)sZ`^r~ zy<1C#plWBk_%Nk}Qsyq;0DIHJ=-_sw!XkXkz%ob1t?VJ3Q3b3ahx*r4U zptZdZx?E@zh=^&0QK4)6Kb{=XkEM%5?EckB^=-vegfBLSoVE`z7(mV{6;;YD$hT{m_1|R-6?Em2Ho|Kj=%5q}I zOs14p*UJKw{Ne(%vom5i+DPGO2Ss58vLY0n#Jj;ac+%-dvY(BZ&@lQbV~I}X>z;z#myzDCVKQOR`3=M%pOwzut1z(%e^oB3+HgZhZg+oy@UfM-3WuH@7b$lYCl9q}0> ze(`mvp;Czvx1m;M(6Y>$gzL`zl```iBq20Vu$)-gu8eGooZOez?oFud8_6$)T_z+L zqSr!;2#erl@&5DQXNEL*nG#~1fR~yk0<*;={7@7zwl!2r3h^W3{*w3^N&Q$c&|(#P zs}}+WvjksNzxoH8%-7_H*j#U&mW`#G=r%YFqpFrvy|oBl#FpzE~Sd?GeY}Ngrj`TonODhOC(NdDjg}&Cut5w zo{TrGjO-e-8lf03-ZG{>G`f5YDZwWw8l4j$*etl5o4O0gzA$%(XD%aQLqMLCydcnt z9umr0g@znR+4DaOt5l{+uw7Tiz}YPMuB7MSsH&&LS>_ust!hmA{NYr&jwL+GFa6%} z_($*G+weYW%`lH3h+Sy@Q+429*P?$w0noJc)6FY}?{pO!w#h#W!(ZuozbP1S2Pm{yQVlr2fw>Y`i5{`;j2x8MhAL0tOiA2d?eNeMZ zcL7A#U4VS_Y`VaQe}cg;N!Wucwx-{Qn!a|upB~8^8Zr^utle_?M+Z#UtW_;|25wuZ zEoL9ARXaYr3s|n+m{9wZYx(4FRNL(rZQG-^=f+mg`HY{s&?|9`qA!LKRxIZx-k^AAouaN zN&FL76_xoxt!q10M(b{uwhhx3MmI*E+C8ZGjoSR@8sWEIPIl3o2}8?%J53yFIlpXx z#r}%iGw@G{_e+vJ++X$laP`3UsA6B-&@ufa7uYWOluYPV&2 z_I1B6fHV{)yMB6<$CiKR<#S!;m_4zvKyl`~;|If>5V$mR)U15dF_3^NP+MDT+NWvy zCu^rFp?>tCrLDxa-i-nZconC}GFYl3`v5Lj}G^tait< zT@b`?xeG99uXK7_Xn0Rq{mXo{e|yRNy~v^Io^_mpocMx+!!96oy?vkCFYWXXU-#Ag zRv+bZ<+cBrLmR=`1Fz~=)dFkcCSrpV_UQkGdK2@qWK4IaX15)>V_@oamTj<8tcZq@ zLVZRr1(+?GG8xf!Fz36i2VFCl_3hufzYFNQa;!4d-jtp*`mBE!5WX%H12sHIoWoec zKCG7}dpCQKltnh9MnpPj;BwCKB&T6*{glYdKoDmxX-SYEIJZE%3A`FxAzyA^akb3+ zdx=QvBBS?B75RaJw#lt%!BVby0s)wP@+h!ilEhy&TeSKUQz=a)wp^^n{T#KU<@1yG z&yrVetr1W|%H@g3Kn9BQroN9?td&<#Dbqijgi+(vAIl`%%X?{F&T+T7l2}#I{uUa~ zkyNX&XCsCgC9gV@!HXTU+I!(d{rpCChje0N;Vk~%x#wkcr8HiVOxunsj+iBPL6YES ze-K^vBg(0#_*iMXvp9JfYKrC&@d}hy7)eulVx-z357)|ll`V*NCO8ug4hg)rxU6jB z#-&>dr{Jy)c5rOu+1s!o zxx^H@RSwgaq8BW1AgC}usF+&5>6~G0V?^=Lgd=3mZYbQ@1{_H}3l5BSeK7(DO-YrM znsn;$YQ7&#;s%GTCHDvMPK_(d<;EfN6x9ytphz>P*OfDzNIhNMbLG4gSsFr+@dqCHFMC~R?@HCg$x+NUNfCmGO_(?ew zrv`@C@>$}SA$;%UGR!s8^hnW&#G_A8B4u=+)2PQDQQc^hJBLvowPLEytF1@zCGEAhE@+r$96}>zZLrZlyi!SnMczh8(#mJTKzY<>{r*0`67yCryKx zCe2)wxf^toa*kFKD$VYyn(H}9dk!qja_l+A=0f0^F8p>aaze=8+v*76c@og+LMk66 zwy=QqmW0v|$Wl8zXGOj@|J{OwGO<3)hYATQqt+Y{gkNsyHF`&re$*~g$?xC=1u+i^eFbKT+B zjSOFrSC!NM(l`8be}Y@S>-6xQ!jQgW*S;B7|B^Yzl`{B)#(6ZQzyQJ3Ne zn#L16Ex{8vFDM&4&+R*ChPYj?)O6G4QNxskWhX3w*hsj}@Dk0ZBI52A2=LxqL!=oG zEtI3ABRLPeYokAyI2Px5-b8Sksff>^BNbWhM7Y!}s_V+fuDFv>`$*X?`^@krCf8(8{qK z(@fYon1IJ7Bt$&+?);#kRfj2k%kS9TJ4DsW-fwuRIvYkCN_IoY)$+11-BzWDIXMlr%6Q0ZWi=kqz0IsJ^peh7Z7I$XmUE zIN8IE`D9e7cM_3M$d`RzmJwI;Y^cvt0{O^gP)`~J<`{Q*u}bn$i~;4LmPAS6;SnuP z!ZnMVJsSX(FV$SgB&l(3nJXxty{*~H{X93Y`mNOaZN0`XFN<gF5;+sNfDz6p z=NJV-cE{7=jM6kNnuzjkoH#W(;uJ{U*P8}Wl%+kHzGheQ)(JyC=6c$v9%MePb+z-p zk-w2y7G5U(_*(tWvBKyl+B*8FRxD-rmJ4utKQOTTWG3h?e$geXUD4 z15HhX!(nVi4EN$1VL1w~`Nih}O>5BW-MtfJe7R8$o-~;f^v3sRjryNC{aL)CpAg1g zHzOl2AF5$6xEfxyQecIy+n|S@wdqqrID<pq)EQOQUbfA@g)ic`#;rQedt0~!o`j2-5))1f5kVeDCbeoW=4$(~9h_W++J4^8^G+szo@wdKfTuyOZHe#kIB)E{GbNCLW?s9W37?ouIn zE?%k=Q+2y<(MO*xF2Ca4z$lVC40z6w$<+(&#WyJj3#i%|&!{Y3@6ur%Wf9zfubA5F z^rB*=xOml1U`~NpkZ{1Xw@VNNJkNl|RG;(47bq#_Hj!Kw^9Gw^Eep7EVM{t@s2H0Z z=M0mq91?v1&f1J}b9KO>RBg67gW2g;URZ(4Gv$2=q5vJEY5pwz=UskEQAQr%gu@}6 zY*MOVXxX#~RLUeR<6X({T(^Es;4D zO9hQgDRcE94-~$X>(kKF>UnNvr|W0Idt-IXt5}nccvpEfYK&oi%aA16<5R8EUD`CG zOOqo`R=E~v%N($JM)@os2W{+qVB^pz7ypu^%w{2x@w`HFWBS5;hPKj;b@QlEIF*!} z{e&{W-#)yBkR@1ymkNO$jr4&=+S;gC}>1N9rHq_X>`JejX=%STpL;apu$Qz(r!yMXOdnVqDX*iYs6>w@;`#lz(B&F}$WE@|Y(N3B{0 z&nV12kQ`1Qh4}4RcH%RwmGHrMJ)okaD3qxio2KG|sJxshzKS7vgLMdIuu+!hZevQFNq7pJGQufc!8H4x+M50Q|<2538AQK-d{4=9xw!I0z-@Vbl(RkuawY` zL0_^%rku+Lh<%2bXPNnT3Up2>J+Y85YHVQgWATfY=MARUs1fzydY%|BKF=F)uHJEy zK~FI)KR2lDQ^AD^mjuUBufoI9Ny-kHILqnm`d8!t;b^Tw_G<3|q+-cP_9+}Zd?emi zy$NK(cZWdxI(C*GFSe91B_hcZYn`y`}rrS!g>i82sxS4ZJSv|4Do5f4?br;eN-y*BRIM5DaLbzal%F+-*0zZ zR^9<={B*M@D_J$+nd|CHPt;rf0C&U66xKwT_z|5wK7Eb~h-V6&ZOG>dCXZkT=V<-2 zY&xP*=1J!^uFDSZyc!5x_kgozKVoueY-&iWlDxFmYmxANDIeg)Bs1Tf?D!821!#|K zZF%rQ_8q^1@pSI<9CyFVf7Uey5A;s2FU+NbtAWin0mJj<)OQ0DxuZ8$2ZpE=!Ks4N z!znr3(31)FARpIf)_z}3uPi|=mFAH#oAWO{L68B~v8o0|z5H>uP>Uj^Ai_-WOUkns zx5T9{Qw&ZRdJn+8M=e!yDCn$g=|KUnkd7Do>qVlJQyOKxmsRDHd0%5HHoYdXx$TV& z>6UvAv=*kkbSO>hlQPR3WQuTfZ}zg>>8bj)Xu-(=IJ-jj30t}m^m@IPhk*mHU~2+5Po0DHRTGgOI0RXnJ9x0n;9}KWB_}7` z9G}gxctRlMHlq(|sT^|)t!y)9e5FRPhlSLbS zTR4-qrh5#d1nYNpq8lToaWH4NEN!4fmacd!my8$K;*v?ey%Ahq%uVT!<{{GKAHLF$ zl#;pAijdB2E(mPF;?Wm5e_(Y3|3l4LtZi53_SH7@(oOTtT#SB82asfjp%r@0*?pc|Kp$hmna{F>G-Ak25U>g2x7i>GFrziXJ1^S#>Q zd!Z5%W6n{;g@8AVk$owFXR%dF(y22DOUNMRGBKrpt-vC>yU=OI_4tjBq78(>y5?tD zBo~*etfd4wO~B$KdQaf~3}>g{_cQta@z~N&My_RZwO%Fp8bkb#mN4&8H#D-aOMgU+4AvGVxX;X}*J>18>?l3RD{ zW5zMBGOGvkqaLK;pNUsoKrAPKKUOvqmgYrMu!mOI)7}@&xIsne3GY({TuB(=ZA|#! zwxX{enfRt<*st2SS!BB1zv(%-6y~&Xc?zN&TPg>fu4tn{{AH126XVoV{x9?m{FnG2 z6ke9-bS3n0`d* zm)ugtX3>yvjhiKlm+Z3QsTCNb-mH8WQbBCra>;Des;JKGw~OY_)5|T{?eHb4o!^xq zeSF-iGbrsh(;@RA^d_)W`cDpBpSJf8NW*XS9KyeP3~FQl$WPN_i#--p2As(lMgZvu9fn8<89qE045F$u1iWDtDE8+9 zDe5LeSgXK>_V3#&AQBlN(-|cY^BjtYMgzHL&DFDr^7+f~%!wP5TO!3Cs??54z3##n zJ1q@dy;lf#z`d3lM%W+LEe7~6L5yzHDaJIDr>ED-qOg%|0Z&@r>6OZ(UbWN}nK#`a zo$W${EZ?IE{;y)1*DU0mI-9*IT_9Y3zYFK#HgKS*wYyU*$&uoP@*MU%0gwB*mYZtg z>Rr;QhLwJk`7AKwE>BE&%)B5_BHn^PT3VdgyL6=O{pH*Q?I?z^Eg!kEXL>-xNC>eb zJuj5l-jo(R;NNcLe8zbp?<{3;KO})j>L#+hRnSF>-e9ZCo=C-&4{UxHRs!W)NsDWi z!tDi@MvH109jPL)ENvhvMgl`K&}2Y3-ehOv$9oK9ike-@lrBDNkr>xKSn~4$t>m@X zEG&^6o}wt9+DO=g+;5z1pHxesZWz$hkkdc+nN(Nfggf-=x!Z zJ&r&h?zrAQ3zO*-%XPl=)X78zFy>u{9vDXW>T}GN! zH$9=5_S8bBXb{93ELN{HGLTdsK#*dXqj<5CPE0BD9H+i2F*C%CD72W`TnaF?;lGs6Tumv%cz%V{ln%&o4Cbt9H5SZC#Bxl6b5 zoXyEdgeDEHe)XzcWC`&22w&Xk8gYr~d3l7~A#LGf=S5A3cva%IPR?`Nw= z#hN$E*!Zx$eIZ&9q0I7+H$22uaL;6tgnu>=?Y#Zcis_U8)FQK7$;rqWg}NOmm=*aT zw88c^$;fi&m)nAWW2MTE&x4iz zKNrrP^_>?wzYCDb*(&4N$!_;U2Q3*E)!a_qYG_bzo>pVlsS}q6`Jbx9&AvGL1B=H= z3E*oZ8=h^~;VIEEDGB+3Y>C7e-ZTtc(@^Kjx=6G{Z~`Ma8Fe z{?MBGfpfI;M?x%0%oXG?*Zk^VFLLWKcFqpyWi5BueH=xHdLqCJjzl-BE{a$)d<<{*;$skT@7$;mhSlU>e;fP3{qj$xa6q!Y)TRc7at z4Q~*KR1sUPj7di7&BXr zqrJA>D2tg>1SRjB*-ZBpRC3OIPdy|^<@gEDMC&WIjALq@p0Es;qxpnaO7f7NODKwj zWnD&c>swAEZW!Z^yP7I4&^yqGb+laP;ZSHTe~cA6Ao8^DVUHyK&a$GHu%XZiMf@^) zae_`+1Sliwo(T=sHFF#9-}s&6#p0~82ta(`|g0Ivb1mPV;@97 zDLMm432i8$BhElTz<>}!XaS{@P^5&8SVpRZ0SriJ8X%Aaf|O7~v(cNB5D5@OI-yA~ zf?wQScV^$6ot<~z_ua2e{<$Zo+dS4zF%*5JKP z760+s*i-Na&VtdJ;1arGale!_(*nDS5H4Hw3Zm$M1Cy^DS&?BX#k;pJZ3ka-22imo zNa18+@sgU#7@RKbKpP^%QLBoB^NHxu_^ETuH?HF2u^J>gA4O^s{oA#wQu=aZqkph>njp z+;98qt__izPaGd)W!5WJ?~KmoZ_0Xgjeg>A$q4SKx^7)yoLy8tbhGV!d;xW6ns@Iq z7FpX|2pt>keLUwBB3@(j>{#qURZVC=(Q0}&5x1x?+|TGIN}51|g4QHi{M^%P4$zqw z0)z&Rz1vymNDXSq3wU_!1nv&4C>=lQpnnbqZjG5S!aY%G?nx3(!UWd;h#_QB!Q6HwrJ-dB0w z+6tuK(Q)-(am#B=J>+z#LH@D*Rk){xAZbdcHzk$(_9J?Nkw=c@a!s{Uc}UIrCZWU{ zW$0=6{V{d;Yi4(T40UmaIKwzE?>(hHtfnZA7|)@**6X5xgDN@i@QXPR9d zaQ8a}9|#n}RjHcr+8Rmb3Hh2AZ+UVJh&$J6b8EI<#coI0L(Lo4z)%9QNK8y(SXb^s zkuF7`=1;Qsvpo9u@2fvQ^*{U$YavID@Yd5x7x`|vL*8|Eed17G%=G;=@%nu5&VMNU z`~NPj{E8u;|HQ9gZti?`cJohvKa;>oBx}uDhj)zah+o_OLJaqF+!3~0o!|XCXy>`N zU3{@$cJQX_FKmNXe*FgjY$GWeBFFHMzBk}e0-q6yc~B5sUPvwCHCTh1uT-GZRX#Jh z99j}kL|uoOHbC?geS2GnC-wO&u;VKd?Z5uSe;#`z^4C61Z(VLL%b#A}j<5EPpAFrJ z6zdY%k=p6Do7Qvq*#q*RlhW@vxu#Gu*bJ=?#{2)p~>TJ^Kcpy(;Aib(C9LE z0zTa3Z9|dRz@^OO#cT08tkxFmmsjaUTCwns>2U~wcIY-*5(tdQXx^q)@rxu>#9|wZ zPF)Ca%X?~Y_@o;uo|9so3%(R_kQMzdc%##pK|JV>AHmFJQr668c*bsoP=Wz~Qsc#n z6~W!{(Y*%iqaE|A9!hH`Y7xbRf=4Ap;lU~69%HpIHNJr261nz}&*!@f&1l>j$F8n; zJR%{&rEbbgpA0pud(`ef1`U;~UV(MAOz)>2Jyqie;^>@)S_qp=Xp= zV4dlj0=fRmC07}nL-gWiG!jc?k0*fm#V5boApb1#Kdf^opcj{PY$dFPWEY-29Tp$( zE;lzZptAMoqds}^s>Im6@qil@b}h>M<gUEY*p_B7UA@3yE?a&T%WBqr+ff8xkB_Z|*eeOEt< zK-49UaPgmYkBiQ>it1ba=08OygR?arfm#t=?SKAMyWAD+s4+DU_~-&Go@w^2#JD-}8Q2*>>EC_n>==sgO)bP7v_lhJ3q>(oY z?1#KJ>hIx+U8_ZV)-`P}LOI+tY|FzUyI? zJSFT=C28$R1qP4U_;@x6S1H27UQs4(FU}p(`5hDR@3LS#95{%T{Y?oDd`BW{e}5zTXn$4*aE(;d#5LSKd&_qZHFYy(%nEpVniqXW4; zXK72)QjEO0o4DFBf8=cVJkmoNlAx%6;q{2ll5kSY?cV3`2ih=(`(L&iwB`cc{acz>Ux^qx{I1X%@C%8L^qF ziT8Z`*TBUuQ*YmwX?8Ir`DUG{v0EBm{Y&6T=l|}PIxp2pFBO2IouI`4$+AVaZ-^MX zJ@O|G-MqZ`yJufmepik5xHT86iR0JIgP+l>)05+BCqrRH**dHH5P#PWp|MUD_wDTs zU6JFuIMt3!XIzmQ&WoH?w)_8$toU70RqKq0-AM;-Ykyz*s|npEL7;*#BzqPflOUI+W~UQc`uP0=^oUN}87 zz^AC^$<1=`9q`F4Jb8X6Qtij;M-%Z4SJ>rCINNJn7H5cC3 zG;uPn8)K3un>w@A@-cMs&AvmF@hzox(ip{Yb=iDitw(~dnjsdUTm%S51!*+kUW8US z@~oRP5UD1|tNd)YV&D1r;I3fAZ*h*LsFW3w2n~f8x+UASzEbh>aHUhGp%LntHBZ z`PXasx#WQ&J8Q64P9mO)0|W>5!t{j`3XOC1MU5#{EW{^{OYi!8pnbIg)~3@m#@5@; zaKri=XNTg2DGra2CIJQL!$nmtlFYip6cxg^Ra2?DDA=WnV>oPLLf~aTxJd8Isbz&} zc<7Wb{{RTZER?C5@ar`e3oYwN3Tm4S*-C03VLS*P^va=hmn08^xq<4M?cPAX%q-*d zqn+nVBvHll1YAMB15 zhpTGEKj0YnCw2J8$&RHOdo3}=?Zm8-KS@V3*e4EBDq&{q9q547gf0cz`q}Uw6pcqx zNYK=-oDv*dhHqgbc9)B{b9}>a(raE@V5ZcA&|DZ@pEw7ofkE97nW%|`@W>}Qqt|W&tPaO04)!24p{g=(+7SZ}HCrT-3K| zlnc>S(C?Q%`!E`+7)lz^7u(EetwU=w{&6k-n^U-fVBVjSUDCw!Dh*hfGV6n6j{qAB zEb%RK@wnf{snuJnKA7(gI-FsIp|Dj_scRa~IvaE^K~l4^>4Vehgx&Eyja+mxj*l8R zm7A>kBtbb<#FOn4Vics^&{k|{4*j8Q<0>Z`ev0^P9Y)%mTp58 zQmDoEvE-?X$9x(WwS=~|IO-25M>w0OmnV^}@x%G{LTzBNqr%&&y`2%CPZj*Eu`*#`#pQsuYXi#ZbuRU(8Xdd&M~tR2ozBy2l7|2>2m{c&t!}?00d+T#suRrzT--SWX1X+QVe3J3^n)a5GxW`Cu7 zr_`^6I#@LVA0mK-Y>pvC9qs?F1L=Qmx_ysckyACp#=eOZDShGf1fM@t0p?$`idqZc zeqYl}qw8!~xxD~?-irmPhV@vBN(51Rixa^hJ)q&a-2j_OIh!b|?=7`7&AP6noBnAX zHYVDdj&Sd}Sa?5~m<}9kKg{;-D**K=P%Jg*1DVTp>e$I69R2l@q0W_1&B?m2B&HHA zh0V3ev%+wk4>6zrI}Q$e{}(B=(R0W}p6x(@nEQu@s>{`E>>lhMZiWBqa6P|G4KeD; z?K__#Z(8!?#rqc^u|^5Dl(Yu)D3g`&3?_)IWoeazD-53E2khj zc*>r#Qxm@BIr)j>*wU(xz*}8f0!=GX;cEZAQT_^^r}IPhMR(^vHmocM9~;1QEFq2H z#-BJI#uu1V6wzc6@cLHDYEpZ>?j3~1WNn_@@@umyq&DJqFAPH8v-u%jFJ}v z>$~Mb7mWStocH?VADwfyF5}BzI3MO%rpULbcMOm2-APzh?pe5;82P|`wk1|rG)AVa zQcT*6O)OeJWTd+*5IWg@n)h78{J9P>i!xLBOJ?26MPVXY?*jnas;6Clt0MnWn(&}% zjm_-Bj=2;3CE4EuX3%QhqLBU*kO$6*EecNOx)=C$yE{p+we+LVv7JVbP#oT29E~X} zttMa1pMZuIL1}DrhLI!ULMQv!F1fsE@22ujyQ^B-<*z(07Gy1E9!V_;t(yX&Cm*Fk zZBovE(9cB@;R_RSQF~BZ0JU+R8)YjVbk1KLGcVIOM`k^SyLS|X^hcnFg;NEjkeGZj z7-B14hXV83s);Fe&g+NPcx3h!vBJ_UFR5vU1MTS8*i|H8QRyiSeVW(_aaRhn@{E28<4ehZZ5UXecv+(7kC8J z|DHdgMe;q%XmNzNvec_%1hNI6sO@jD44t*0XnRKJ&wdl5_9#Y?)`@h4&vRwzK<%C! zKNVsEl_ueykQeXU6nMRrD^mg7n+OHO7COP3?8wqu9E6F2wOh55k z>F#5n0qDRXrW1&DCrx-G(*n{u2a+KS7s!t(c%3Bh!JhJS!_91Oqb$^l5ScUy(p1Z+ z7%U3xD>FCrXmrQpkNm(m{E`X+;A1AjMOjcNYDr8`wdREIIbvJz<4MZkhB<|H27JJV zDxBUDP=Q*(0mL${p8_CJVg5>kb31UBs$#Lfp@ivVV{dV5TFaSYL7cD9G**c9!eF6U ze!%zInTUDwM)?Yu_VtJ3Fp3{dgAX5@r<7yc_Gqpy{z3$HH&RI|5v%kHcZeZ} z)HEp+7Lu|?)@ik#)o zPGI6yaUq;8nE^zl!}t})AvoQe=^0%lglsZ(OVx*z?)WK_czTJlFcmR-GixF% zO~D00j?D>aCFJ$wr_Vf{_3*z}ax(ROR5@D%`_=3q@IB2dxawwfC$k&M$(6yF#R_9I z_#TJl*(|9?@QPSpZc^XO;-4i8#!OyP0P5(Hh8t`q%)lCacWoI9;2>=FxkfoP^vg;| z02yUVy_|Vg2Wr-vz&5y}0jP97>!8ZcEM&5(^O6+t0>i9jfv zHZnZ=&KCOSjfZJ+U7O|oDf4Zy{_mY*3+Z|ntFLDEflV~{BztY0%qHo^N05VN70&9H zD+lEOR{T499V<(`gFKVJImW6Vf3uI+s!;GQ+&qlCLyD_ zA5u}M5DbF8!+I&lEF+8LQk(f<53DSIdRvaKXv0W8W&;A!?mMA#iQ{_0mUV2nUmKnZ zkeHq4I!CIW%X6U<`3?^yHyMIWG>_qHZ*#{0gWYhf1unBCz~*V0Y^ebcxPY8PprmI- z%TOGe@hAkX=ewv5G7<;^Zga&PPI6BLGqTS=CkL{(mndGVN=JwD3RwDLu|U5*KCOdh z!hLpaR;pq*>%FSz_o8|}&9Z_&l6B3<&t9+E$~pkyY)C}!^T_z}V~#o50}s?pw7>6P zSnaU73a@GAt)<1mxy(SLlVAQjDquQ;|hx&GUK#bl@}fA=;Gk8e-F}JP z)1{T3Wt*CbQg;`_Xk`WZ{UF-(ysALWf=)MgsQ44tD}Vjk-GZ4y=skvp)+g8&p0pyg z?krvG$;0s-CF&UOp}HGDE}^CdH$G}}-;^$EVQ`l=HY5GyXyyTmfn-~%SG}+_-E0vU z5F$Vx?*?wjtjNBpY54Ay%b*Hn!aYpK^$`rLVy4SHZFitItG8{h@o-1Vc$#Vvx+|r( z4dyY9c7#s>>&`LjX0)g^kdEd?EY_uW$TY z0m0yH1~Ntgy=(wk3NwJCU5rqB2r+$+S=@7p>fpXU9DC z5*Wp;!2Ifdy#uhJQp}>=0jqSgpN3Z2vsFongAYu=`d4c%s>vj}jrwk#UzMrzt%{q& zQ5VfqY?i5Rc}aCv&Mh?)E1Dl$*xR-rYCS4?tfmJHJ=y*YGcqStuyMx5d7THRP7H8U z->&yN%3tcKhfg?ASkeJc1M6o-Cne^P7LCPh@Cbpe$c>5$`>opj7t&6*J#LbOb|6TB zY;eM7!^Dxs;zHl_e%xoUO=}pN(b1x@suO924glc1A*&o0F>$d%nij*WqqTV#8Gl+6 z-!@eercF0y)9+OqiA{4{mW#7@ZOn$G=zvc@*|+6zp3k+BLLgIxTyNhwu>AHdUA4o( zq;tZ|2=KY|MP>fFqG9kFo3(Q6>EG%Xju@;Up4ML12l?UA_|%UD!9KDNcrm=4k$(G* z){a{8bdk^4-fE2|x&}Gj2TuVBO?nk8gHuKllM~7ohkFWx3@r`S$|GiL)LsoUo9lRF zwX#!sTfL5!zfrQ*zU|AJBesPNs4uK3qG91dTth`0Ni(4RiC;wk%d8tO-7>roVysqj zd5vO_)&o?RQ)n_V7DBWL`{(B$x$)cWf8bK;)cQ3j8cn?2 zOzy4Cxog5!i8}vDA$k&t;iJI-LSo#|Nzqhtf1$a{<;2!#ze;2^Q+D;5oqE!+Y-&B_ zgfG6MJWr@xbkFb^@dF%MObntYgZ3`mOZrEv-FL>~-?dk`0!@bGw_99YflM^F=g*7e zs)zRL51o?=tR&8#AqM>2LRf*|Ki$69oAg$%31QSc@op=Iwk zy^jSVB}q>hd(vnSNHDnN=2k{6e%5O`Dk_$kckwimr*j#r`J~t0a;;?K5Xes^Ifl$6v%H2u zP!JQk%Nxke&2?`!=8(;qnhICm*@9LZh)Z&-6)R3ynMEXVn;r}E>#pGj+DdfRo#X}e zrk(68Iooa>GnE`1%>U?vR3FC72zt+t{SACi!cEhrCdZ99ki|9S!wK-k~yds$~HgL+v^+y;~zXwqO%yh)c-{VuivBf~@jY0*;uh ze{Qmu(%~EzjB`apZFQFJmK{EFutU4IQ~TaW z$TwBpIXuf53dL*+qG^mZ4boZDA!tXKL7og&RdE+9CR7C2XHel(&WdnAHQw;ho8WhM zPe%E23Y!H3At=tQMJi}@=yQ{~2`Gykd)+3{ni&!scI6tP z;4%;a3#)>-_tQPFG|z;a$)nydVP}l0RR_1$+PnN3;1#KTZB!Z?V<&pt`Fw}DA+WRS zC+nWUL`G&DG0&OU1Pr>+0JS|nV{2vx?HguqMUL)0IPl`da+|-4y&)w-%mdIoU6v6= zM+^hs#nf?K30H8J`G9S?S6Ka3*`@INtr^z;DD{>rpFOI9OyM;)OW>#lFBJyjlJlQX&pE*_ah(;N_T*COo@eQQ8 zSlh%023#{>LJ`7gxbO`!6^HZ>$PzV)w;@V;tn}DQ%Y;H#Ig4%AYx7CjTo}}_na%`_ zTV*-l^R7TFfKl6t4ymo+p_o{w)=W=(9v4Q8BZ4TNv9BWXvy2ZI-(*0`M@u%GQ3;o^ zndgS-??6mnM`T3+XV4lH4D1~irS7Xy*z~maY$K4SD3^Yak0Gr3tW65T!r1s5SJJB( zE^8wsg>MJqbM-@r;hd3|ozt1CtHi_$k~K8ud#bn5M*K;x=vRGHLD_jPN(O0={$o6F z1b{h}$D>eK+(s0;oZfusIj4ctm|GC=EPV(fK#_lq_UQ##P5FZi`A7|lKBA<&`6-C8 zJ44O3+yvF?QPvSrH)5=8o0|_ZZ!qCk#;~0?6~2#cr^?FT)j4>dqeJ0ihcqu=h%_p|Yl3y-(^oO$v+0%U5| zb2!z_EPBCoA98GKdJSXcE}o;yaDd#d3b;g73bX>ufq3r&^fj~ zX;RFY+9#LLVXeol{k9{(YN}WuAG_kMd5h!KytW+aHRPfdAUNm~hxkx7E~yB~qzn2O4eNhLo%+P zHWO3_HXg6djF`}`e@pvG&xB{&b-sxrfX$Pi&JW-?(Agq6f@tzg`O1Rcrf(=UkF4Uh zV4rf?s=Q#-UIKVndYHmweH+6UQ(kK)V6}jsLwlWMy9RpV_MC&`Qi)5d^ptCgKsaaF zb+EQuvI=XKb;+z3`aVv_Z0tpIdfmho!r%AMvX71bK%#X&dhyyo_WObW;W4&KJvDsC zR1WUg>JPQP6qe`$dz)U}L$M~AXl=z!+AZcSjmzdW0R?Et1a5Zg$*P>!;MXXdcq8nV z^>*VR*iK)vdUb^ouBtJ!isS1s&T!Aga23+OPI@K-4zOXJ^dA$b;{k*`*t>8)FVe#Z zKVrGXs}W&<$fupd7&*tX-6_h|x2J0j9sfq_YeRvh5(^Q>1Wje^x+*u>_!z(^>)GE| z;!iQZz6LyUW7$UoO+%ZkgP0{Me03A)MZueVeeZMH#27qQgeqXxwz`nuhnR=G zZ1mlR@0^nIa^j{3*SG$PmF14#LeQj1I<3XyWj;P9$M$pvufF0^)yIe1ymqQNuarQZ z<(ib#6VZM}^dO7*;5PWQt?YJSPzpw`Eg0qV*OWZgjX0?;kH1zB;zHixiUh8oc6=J=l_lrPKUnM2JESAX30gU;ttFmJ(FLQK5&vO`Sly_XyacUHWaZ zxN?JgahJtSIAQhvHN25x85&|T4nI0nJ-k&RRNiDZjbix-r#BVzVmLd@;2J}bL)u?8 z-C8#o3LfAV&ehQuVfr#xmn74P)F8^6qx~)RegnyLp*Ud30)L^gT0yf93TRtc?9Tpz zaF;C^Yn#ZM$y;*9@<~=CKzS1sZSCYYk2xjrl?}-7TCw0_7DTE+60M%BIgHvSva&I3 zzL{mWRu`Eak(V+XkwdHk6E!w+vxPgcnSEvtMYEy{!{TL6X>8wBAJFM&@l10F!$Zw& zM27L0nw^&GaX!I;5>ICRnhWLTdXfiBV8;4(?upJ&ZS@{y1xtbX2|e##Jt5>M$jCkt z{oenYCwUa&@We@gvVbHiUzk8*s0-6HHp_*V>|xxuqvQPIFBdnWWl{_!MG6uEazcIe z`L5RS3fn}HrY3A}eaA0eZ8Fa9+a)Ul26*t4+*nO9lx50rslBkT?i-rtc{?Ks_}1}^nzAZi zaWN-fpK~<<2V`?OomQ3}z>6ira#71YEhI(Vg6`(c^l>BbJPpjI^;efFbtp^Ise@WA zw?Hra)oh%jy=cKO6vLmLo`w|?DpK>6fT!$n?H&tKsZ(%n@L+-B2S;&vP^OOp z)R+Ep3P7w11B4u7Bj{^l4n`8(^3$XcI3YlPJ85b|Ea72y$E{BPE|C699RBdD3t9N- zakh&ySh2e&EryXecr$0tKqMsR>h{>kh%DQ^8FX?f)?C?*V(S@TbBO8tA~?YYFUgX(LhP&qhXYsVV0VpS(Wr3z{Si_ASaX;@OAEJD3JhANd?OOz?m zKidPM^S&Hsi^0&3cyvoV!`gKSC}jY7U7wVxbik7e$_R)b-_cCZYywY{$2#Go?x)tsuPmMjcA{g12P>Psd_1&+k+Lp#;)$_H_w5v@F zS|=M@p+;uiLHwQRj0+htgEyYO?Fd^vm+b1_GvaORaBNhh7y(Bw3Av!wzRt+J10Iv=Dw0A*t~b^#}x1;9;%~A7At{ zqeI8YHCLAWWunp~8~wmqOKd_#l-Sbyx1HdS8e64+RM=ZjfDIHtRl>U+|U%6Ql5I5`k)OO>~E#g4FQ(z%1WLLBz?l#2Hpvlivz8tO|>D{F~i zERHt=w+gDoo=?kSf;wigGtwt~O}_^#q@EGdP0R2F(K>yEBr`^Rmb38Vv?>?KCB`T! zSl{NY$URF=MOF+QCtPNP0s~iOA^rhN4i7(ZB=zjJUCrd(#mIi*c%L<2cG{>Td05`Y zf$zn7`1J&sJl%N9bT*dxrdSxET4*+rlolzp^o~mM*jy`G24-UKmr5ctj{Bj&j-APt zycwN7MN8vG4qJOt@=~!g7=Re9=S#Gf{w%64(NO#q%pXSm4&uCgAm3H23g%DSwePwHrpN!8=Igz-6s8OV& zOxUa^m)8;vqu2Btd12T4XoIO<(U>-);VJDiC9*ThLEQpz^md}pM5^ZHwQXjoJT$p3g)rB_#e!gUnTp8p=wu`ssQ3{x#lmf@6|NQ+IUR~Nd}}9iRRtjs!-SL<;j0q@@B}X1$h&t z=qGp+g@%dF&elw0i^RBl6I82#D&W?(z5&bl0!biEA~{GXwhlgl5i!T76XQl-VIX$| zYmObcVJ+rw3<;nPJA`Fs5+0#Y$EKgyQb-QbT5?3P?lz~!k+|5Ksm{JPVnwT`cw;?0 zUXV1UfhW+8-^syh+2n!r$opt4f|wU_l6u|aq65YPL+R1>e@f8?sf*cD&P!TS8|cr; z@jaObI$!$NBVWs@g@(&zSH5A+bFKq=bJT}X=U)(M<7}UO8Y+mG{3F?s6DfwwE`_!W zR|^w2ZsZYiGX0mYWq9f!tGLhw0T=wbgW4OLZ?(tD49wRBEw^E?^wTym_ppqKc({oF zY9avO6|mEimxeiw++PakzdwIbvbI+Zoh@{aO-JamlmA}Vppbs=HWn9@z?;6Tq)Act z7c6CkRY>KMbK?k7kANp0I67TJ3S&&TRR!1$8asIaSv+@deK1)+a)KM4=3QJx;$|y! zR$h<8xfvg5>NFbL!K|z(sjF|yx2SrqUyW3Vf})I_44AbL$(-BK_~@Dm=$jQKNkjNg zPUp=7>~yx(tY4P!@#rt~i{jH-Gf(n$YRtxVv^^fs4e%Jqz>P&u%9)$mL+k05x0V;fr4{MYi`Fql*QNkK&*KP&P>ThQn`ZNUJvlfE$!GUU;_0sXB6^l?1{uFQs@A ze32hUW|O6~&kqBQkIuNej4B|qCcpl~QSG|g1#SjJy5$O{`z}ct?L(4tbC|4weA^eD<*8Gc}t1127wwg z&o^8m08w@)b=;H1@T|w{+1T+VfUJaIyOK4`z2GC|Zr3HvYltE%^Lmgmt?2#^=@Z8l zsV9%#rJ2W&{Ta*sm+HppsJfcT1>K1yP2M5(&0y7IrBH#WLN-IXIHB`bK3u9M`NRnw zw#V?AMni?JxyK}dR>F=@wb6RwAyD{s6*e>T@gOzKn`;;D*?VyQ+ zqT8fO_T?k9X*j*L*;@XT;zZGSq)j>%fM9Fw#~#z!sV2~x z7((-J86q5g3l8_DT$$=qC?<C^*lhSM|F@x>ES&1C5pgj&VQa zXLM&K;dF~qP|&M|9Y;cDO!brIJ%btbErCD*3`!Q> z-$w=dlSUm>cV%|(Kz?0U5b+s+)$ywUtc>=5tSk78$jtsNM5d!*?(OQPOj&_)f>O8>AyF8;?x@@H}_Uk1EL3mzvKgJ&MV|I>zeAW zL{o3G*PX9PJYGNDP(Ex~YUM^0uM*0FPf-Z3%&S)hCv7D@9tY!QKtWH?DQ$ou55ir2Od37IRUB{n=F~@B~@te zxz>&IQe9dl_65Fxyt$Zpb;eb0wi0u85)mA@$$6!p%_aC30rt8V$eoraYv&7Q5ao$F0%?t=&)NqevH>SIORG;6-Rj37t5(P;@4^Ui|DCGxJgx$1j9 zG@~eD?C$GvukNPKgUk0%wE5qM3civpNRGG$m;HY54CQP#E5O|1c! zkO08PV?t&`*nViMVBO6jSN^>t;Xn7Zqv)^_qWY^5@22!N6pc3=RXgWXonm`og6X%L zK3*ZyE)OjR$2dN;ZHaKE>f3$d;Ox+$@y)BK0?mo)9i8ENj%F2nZD!9bNn=k);RiF8 z);juDLGe!=*7W#Fk<43#DMt*M!WcIz?X8c+*6+OPU8#SW-mnDxe5 za^ckQ6Sm*T0MVabPZcd)iCOE?XjQ;gNmoKo^gW7wv4Wcs&E(Ze$ohdbrTEynxv;;f zy!6|Izk`0hDo%0Yp_(&1*ClY}LZobhkG!%jsllWJ3i6SS1VcL0F*k}H{?Y;+{qFLe z|6FhWOSxM-Ot-A#Z(>mE73FH>bxObmgn9r>i0wpM^`x8DV8siX3k$d7dRUb1%NXt- zIfU9@Ze=-G&%fbjU6c8s+o*qU;I?!<V#^`h7kNMLS3OgAtrY{Hh$yC*I5oi`UcK+!Vu^slX6`LeoGIF2A+tIt**Y|sG`!9+9 z-zxO&X4CqQ)NSV-ahtDh%k4gusY|VE-FNG^iu`Tb&viSt@8{3Rk)ogLmgcr;?f$8Z6Nwi0PXT7#@%-cD>3NUD%$RXkkL z7s?eQCJ2-mw<9LPUc`*`>T%&i1EMnD4z{l8Ud@l5Ie;DW96X7QL2SyaYmVNquXP>K zecP{Nqz1I=qlGe_7QOJl>)!I6g}lK4Vg6QjG9a@hwE!)_X~L~M%tnt8@^V$%QN4)s zP}JG7a={Eo6B|)Pi3I5zKkr7;3jtzbx8Dje_}aqF$c`UTislTKh$E&bKL+>IvY{{} z*CjZ%i;bqMyCGxZsO08ZP!95clK6gou^fXr=@&B$q@#G@itoK`dInl|@3bXS-D&G8=A5 zUNDXj1!H>TR|0Ab6%#wmst5BERk6xOM;A~_c$# zMpc;6JG9wGc%Zv9av~4yOufn&2Z4M|*hiGix?wLPe+aD*$jeQ}Bi9IzJ{UZ^3?jv& zO2j0&Q5*WiTN5Jc0wvmLk7{694_KtEudlfLQo`&8Ft)PLnY1mQKeC!}GWuPzMq;&O z)yT}5`T{uq-dCbN1>PS(z7;{-F!Q{N-B)Clk9U*|{?IxY*N9Gx+m>|6bZ%@yVDV^Z zH%fZ~yMd^EIpap^quut*;wJkxI;sv)~Nko+dF_9faj1;SzJJi7M0K`4wySJ}ug`HCf7?y@R53 zUrv;EZSY9dGZRImRE7Z12|pP;DuS}S5**m)X4AJt*Q4sVa(VXI+vXoD2z#{Pbhl5s zO5YPX^izv)NIwo=W5V5ni zD>A>kJjcJ|Qz1I&-RQZciF5X)p<3y z-geUr#D{A-sJ|6OXnO??EIOQ*0TYfI3qoaJp1D^@HZ7=>B~{tarSiC#Rt1twtY~1i zMtXC38k>T<>HC)L+S4zeT;9(t=*;(D?Y2hrh%-rTFRZA+T#=7YkQ+RFt^Hflw1Ev9 zmN)aFDZtL&`iwzx@U8Lg=2e|Z-I;dxa>+P&F;ycWg=o}>f-@2MTx7YO4^{lx)odRb zy!SpRR_dO2dO2T|T?~=Zm#mn?EHD$HlQ8uxFidA0410->`f3sq@AP<`Ml6*w?*@lO z)M3h2Ao}X|iGrNbOcF*BG-L!0f|*UJ`Kd620vHQG%y{xF0-+W-5!bi6cEZP`w6K;B zy+{d3pYk@x<%xBBaTv*+K+JnF)?Gpha#{XuKi*QpvJsE0n0^XxEro}fLzkEaXGJ?5D>sdOHK6tfaXXWe@kOjcm&4nVUuq6eh=0_DXcY$S^K66 zu@NVWGQ{z5(1gVAAD+L=`NwMEm#y)S!~c%e!asic?@#%8$;Z3@;=^!P!y>#_$sL>D ze}fZ^J>IkFSzLtj>n$fxr$a8#Qlb3JDsB@fCoHMm?K$T$jRUTIpS^^P`z=9U5BKW{ z+7u!o&!a1S{V`=D0EhK~;6pk4c;+SD>dczvOIDA#S%a7HS{^A+tgdi+_LQehT)RCe zd*zSJf3(IQW8;sR@`ot+U4rqnp39(S{XnU*oh)q?BV)m&tEpbtsBMkHk_(L)=D%OQ z|B>_m-xjzoH*u#<^>t<4tX=%}bEfDm$I+52y8_Wxv{%cqh9kguk4V`jJ= z(FA0A=d;EtPEHeExJ~BQz#A!l9Tn*L%B~jAy4;NK033hB{_kyv%ucbgY8jJ2r}E)L zApn6UO&(W9|8#UyjOvyD6m{>4k5@>59oBIDY|`AR76jEH;Ham6D_;vgj7sl=lz?=G zybeM^@66@DWJ^b>?DSWC+}Pqfyh9Q2YGG*=>vap}kKH!5+>N;$J%2~TsL#7ztYEL< zqK`fYy}K)kzQv|Xi1rssv)QzG zt<`X3gn;}f0^^s-+SI2Bg14La#z6?mbbih5iedEW*&jDv#BE<(XB>k4(U1S_{rKNJ zXU-T#LcZ5$Ge>BO$h|li7IdD?X+b~B@tXcingccsRh4pWby3HqonuC7>0vCJ zy^xP_;#+?ox4-0B65u!R-O(Ybi4KK z?)A(~xq9ur!7G10U-);q|2E?5znTeUe%1(c{H~&3ZuGO5{aJpREdRYsJ>>YM#BW{? zLXcU<&qZ!N*;$iz{6+Z2ZE!V!|ll3^1HvwKKNf& z7IN&H9A~aC)GMaUNvOgOrlM$rnS~QN6SF{bn9kElN1^NcmMq zgl0Tq7LCB?=ih#Qpsk=;+7C9%FAa4NuA&3G^6pyAJLl3!K_N>%33PLl~uwI)-+W|b?ciqR*~NMAYaXBwg$Z?+*2h?I6iBRV)NW5 zboj^$;qn0cn%Q1c_!b{ox^KjK5GU*eHNzSPA3dw$HV4tcK%H(Cq7V{KdU5*m95^C) z?E?hTrl}K$K8Gy|8KMeXMH7idcfUS$#U%vQl-S`_tv22`h@3PCMnpEQ7cWB1bZC&s zv$m4BTZ&geN>xk6QQrMNA8UC9Y@Y{bP*M10j*SLFn$AdlTzsL?(-d_|7qzr(P zBSmn}p!6ngCM8znY%7{J4-RDEqZeRcD6rd)jc>jHtQIe|F`X?#eYl!TxX6u|F1#u* z9FPEoq_N3ZIYPc!E-r|mCoxieilOD?=uUHyIAq$07yzKk37OHR{q=FDFQkcZW+emX| z?tZSFe}(m|#FL^*Q`0Wf`DWov=i;7fGcaEawF+f6zVsxwdJri&D^8F(>)YS^iK8(u z#-Dn1b7lm{Yc@7|fO?9LK}GOc0+5Jr@%T7kXsPD8#=Hm6z;C<#L5@h*bXEg}-->EV zq$wDn#WSWZ?8M-1(I1_@exNx`v;+k9$y&}8Nf@*u7qH|-$ay++_<9AD%_wCyX~%J) zQmvmcYn@S-NxkQ6tbhG=qJ%|_0NWsB#2zj`tF9kBj~u(mIK!Grn|t!hUifPZ{iDDI zPw=8AYeoO|%OrH(#bCNt<|htegUi1Xd1Z9aA7~AN>Setz9IhQ$MH%vC?KG%`6hhck zX`sE?qPr*dz{&M&svvh`uFyBu#B3+0*=#V+SKZ<7wrIT5(Ba9x5sx&*+mi83dPo<$ zW>4~*)mMCJoy>qkx6`)~*g$r#n_54(4x3Y!c@p_evP41Z3ArXs>+{)eM1FD{bV;Zx zaEZnXSEpT(8qhuBT6e>k+TdbfLaMq<>TIBya-!=@Gq&yyFoD*ygISvnr9Ic1QxJJ4q0jRgx3 zrx3MXwtirk-7(^d>rHVyIL3nqp_ZrmSaYpS@eBY^p6EDXB+&9gV}96Hod~;SgNv1G z6kk-D=uu6}Ng&Qn=NS7ntl;+gx`SFod#lBemZa}u&$h?VTzvY5kQ>U3fiiPSbPEwr z90pFnZbu2ur@!g*xTu`w%3EpM1{O{}E+~~A6$b@jAW3kxw{r7(+=FL{bHbt-5{O%& zcOT}}ztwuGD|Qfj@Eu)@4axjp?Y(zcli9j9j^n5^DmsXW(i}lSLmQA#1;>Gahyg~@g${Pq0NRUu0NN-X?=)H$trTS&|-m_<)YyZx<=KQYf zeE)nW|K!P=m36&&*Sp^Jtmk>|`;OODM5SM&1GFAQ_brQKh%#X9Qyz2`;|D0H-1}Mc zH#VW{9o!OoB)q{-_eA;q#IgoTKnxie8;q)sK<@Hk!4jnpU9A)ga#NmuLyE5V&rD}l zqf7=MaxiU{El)OB`wJMtgBym>Dhib13XYb;Dp7u!@p(AlMG_F}2M!`dsLCaxxxBSw z>A=u&J;kCA&xgcq>ygfwQ>UGDUGMml_!STV$pz8`L-4HG7vWyaJtBf7Cy-AmdL!en zQYQt1R8co}rHCAb<0GUck}pzyt&GlV9dK9fs=9!TgWL`r1KTHN<*Fwod*+9^XoM=Ju=htio{65 zG{MJDijJ@{2f$hE;{357|fnf>#L5_!bJ& zmR+Lk)i-3>rAyCsT_N0DP5#c?GE0MtewJ7e9xR8>gqtI_HQGnJk2r@GS~@sw>v0vqXtedyPd&bg_Ix8{CwapMZf800KK>FwUblcN=#6!z^~pNxj)dA z+^XmM2JNFIX=#I9IfAemrSbF2M1VZ>YzH}ZC{OjmF!sc(P1t#BD{BR=(amr8T;Rh2Yf5&OvyG%qre}8^asem`K?=B6_I{eH4rWkj z9P6LVVk@NXH$n3FThVK*unBNl%m)nz-0~z`?Qp_Cvhzw&j8XKaM_X^n!%RQF{MrWU zyPZkXK;K(U^aZnXkQg0y1=iL|Q`@pfaRN@Z|TWQztw z5^K*|woK-@8g^G@YJ(`8KJ=x7`xV@0-j1JguuJZC3pISg`Hs2{M}&$y{oTcF21h?_y~6eBP-b!CH!I z{+6iI0szq&u7kIff*nkL&B~y=q{fz)SD$6zpM&)ZAZ1M*b$!9hcYR)dbYBPuuK0Ix z15NRky0KW6qN(-s1{=w;{-8#IVANeApYrN3yE?xtb>KGVq|4(T#}L9<+m80yuR@Wg zs6O}Tk{ZI2VhB9`LSDt98M!eh^^me^_)=`^>XvK1W5<9Dz$pmtrW{9%P(Yw%qPX<) z!BebnwJ^H-+t_T4WZkr|4rN#^qaup>o`%tZ?=Xo@Ddm_2ixYLleWvgswom}zNS!VM5G-N-c;P#tSNX7kzKPc8AA zz+RQWT#)Sri5fXdnnP(H*uSqo!nk9d*34K}>zED=i#R{AI4{5D;|CO_iy*rrn7b9L z%yDoax3E}@R^D}?J8r@V5lGt>UE4G1;CEI0T-Qp-iF4mLFuaqjH(X5&1RDW9CA6e_ zI;M``9$ve~VB0ShoOpOzAW^|gPk^7(;BZJL-i-0N`OrwNA6>vnQ2S{T>p1k#?X))a ztI+l>X?$!1^4v}n2E?r4f$tp3`F^+VRcI%pZJK}aq%Sc~f>u3;Q?j`bG;W%zE(@9} zjU?QLjB*7qm4ku)JK1FYyV=zTjz?+D-80Sytl@Le$L3!Mk8`Cde z(dq9na{>xjz%6j>P9bXcz%BMBC=%p-oOg9J$;nSISFN=wl8cx?LIajVKCiLo`&~=a zGa$S7Q`mB=qg=;hq#cR#l85=nv+}yI)iUHq$4H9D}uUsta6w6?s5 z2&4$kd1+zB9VMsJ!w=`%S$OE5_Pzhi3H$fse{RCf?*B``=>6|4Ki(?2GV8Z~{`wfbAH;&f@v5hu@7xvZFI z@=7S5a;G#vK!qSQf3w6SW9qpIIH42dC0-fj_V~g%QyV=v8p#lVa>YX09xM*t9!oPP z#4999fAZaY8aHd+xS91B5vLn*F`cwH%EN0f@c|hJ)fZzOSkmX4#qEL9U5Z0@3Rx>x zbCG=}s(1TOzoN~-Aq%gcbS0I5fX0h;p8L&AZ{=cZ=V^~aHLq{L8JA7S>(XH44sGb0 z;({`gVX_skn?Bpt#XKl;v1eMkbhcl58D+%PrfBKx=k+kQKvNk_=>!;f!$q;gcIRb^FT z7{m(NrslaGcS|`qLw7?F**hIM;r_BR!d<5F^_0Za2#>>u z#*vqU)V{dEQpbxkAnu<)xyhcm1Q&8LnJh-|ILoa8VjUzf)&9ZSjMBZZg4tI^7dZA_ z>xxil^3KnZ8&pc*SD|1|P-9>e;A`$JV3&ZO$uFvwuE*pN0b$neyO-rcPA#`Idq)i`5Zt;*t}-;%7X z36Piho)SjuXJkBdYDeM<)DOB#!_P9y0z4%WbOf@v64FYR37MFXF!i2N3pYh9-p(x( zufd;(jOews5-&|gZP2NnOzGE_Bf|(Z`>}ug4k+6ssZDB;Z zd90QAvU|^;BHmmLUS$_gNg-P;cqgk>W%ae-K|3qlfI-R=uCVkipB{tc431)0=yvR5 zW^l{m2bGoZWqk16c-4muf&SZCDsM;NZEljk6jZv0b(K#|%H5}q`YDF(z#+V*eIEpn zJoEEMlA;x^xD-{MGsHMbU&02=tg8cH(U42^^(*P0FTV_&jd*vZP|El_CHR`Ybe&d9 zO?M&2o=88I6Y9|))Hg@ZQ^__c&@nr)zxc#WY&anRb@7evvKzjc3w!E`7ZJ0M%1Z_F z@QA9}v6_Zv*ZI&)>z+0wGDJjoRAB;u+8qx@BQc(s$BPnN&$)oX(umghz5KPxJ4J0* z0^SX3NgNJEY1w{y8Q#LG|Ip+%>^DsWh^1qP&eu*+H6wg$W|!4T`(e7|3}atUu3i6K zEzG|A$?VTB6NcZAex!ZJs zs^jsx=ut9WH0F-M{ydek;V;*!8Zv4%ePeX>wIa^7DeU7xWig;*=uBpTmrmA;qzA!+ z1=j1?IShZTZkB|iZTpI^kLpyOwCIghHX2KBR^N=xbors|c`Wilt*OFUUowrSv9Pqb zKu<}f@V%0CdmX+CnHCbAlrhv5*VgpXW27VBmzMw5A{LT}i_lnMAAMdA$E5vGR`tAi zzd_WsFGvmkv!XK3whGF($ccH>avYlDYS}Z>;kOW{n7h{unQN^@fS`2FQa4pL*L z92;+_rwY$%wk6p4=7id$#k4VX`7GmTZeXe1(QKW|mB8-JU%IWDC;dv#DYfG(&0t2K zaK*FG_WQF?iGHbA1XO%&i6pB3vJ#d5bXW?rqv7AB+UQKfDX`I%G}#(59xIqsjHss-fZcqtZB4SuVTXIcHqT+O!o2FWETAZK)wruszq3#df0@6z9SnWwFbB z3?;$R^xrJ2+q2zP1d3r;5PL8GSeN_c5DDww8wKE2!|Z3pKgPC1jJ@5x|7rfls5O^4 z4<(t{?3M3>tb=Hk?|zwn`Lhi5a@w2RmtFqpuV#1R7-xn2)B{-?xtxqJig5HWpe~R`}Dsbd*vBs#5R2y*oV@0Mc3kS zFJ#katv%YH;8G9;JY!io~-YYjqo!78{P4S42}b&$#*8QfZv5V zAvN(_;%A39^>;7cE^%-vg3*!oiN*=$9b3sYvrXrT8ZDxDF&v`36J`l-ff<^b9y*i# zDC)Q`Si{p+Kh^e9SLpP+Xq!1Ln{Hch2X`Bf&!qS}mXw z8ML6J!u`$G<#i!$LwAL)!4*?6saH%%7bwPj&{jA)43MAi!IuwemXtet)o$)!#rp4S zSza??(Jn?98~LLUEl6#54v6y5qR;z)2fcgWiJOYkty884KUQfPT}{&P!_df_$+1!N zrK+4gQO%kjP7TvEzNZxsJ!MWXK^w}NfMoq-0TPMQ0{DYul+&Enu6eS+b?bg5qhiPF zbFLSgCm3_b=L1F>KcFnsZV264zVk~9!6v!q&i&>n>3353j2XP%3SrK5cfWCceweUu zM?(47?b7}M z)b^INh-vG1-;+B$EA241iN;ulw;Lf^%BJ08@=hP!dqXIZ>!m6a4nh5j_UY)BpeSa) z&Y~NCoDG3PFbm5nl#-w>H$C4^R5kKBv=}KafXYWOWtEzZ9KXc*flAP*4~>I{fkI!Z zSh2?WBLCnLJQevS#zkk=-0m<7)(i3|IT36-zM5)Bl4p3&an^Gu#tm->B{kQSI zm=c#0(Yh&$WYX*0-bdX_gNOl?#s*+i&WIe!9Bi;KIE;fYh=!kaYW)tAF2#V%<5`FW_wo zHBBG#FW!+7(RtP)^pnVppu|6|znNOQt-9k}mmeGY{GCJqJVs0FCja_}7Zr zwd;hfJ6QzUYS0rk?%||HE3geCEix8j?tp_E3pKfDhnH_9So`4ok?KIhdU-lthgz*z z$O{((=yP!VjSbT$c2oY{y=)yIc?@;+xle49kFBw6KF+9*=dh@=eM$Joy*l`tYg=oO zo24C4L>*lzJ|R8-_fCp%0}u?b^?VeekmgZrBl`~4GV%5~_rPj#jl)h7@9 zlF*zHq>ju1#oSmFTA9f%Pm-KVYTzL(45kH*E|6hFd&KLWPXhjK3l$ueH0bri4YUq!(Ss8yJ~G=MLpj9xPbwDHC$O z4JCH{R2NOC6Qk!8x07eM+}71DVjr%LC*a9|>4?TfF*s)iDi*fxUeF)53*cJnPFYQN zakdDfp1lAN+d?DxPH^vxKixwt9$MRq!@Acg5NJh*Tr44fpYPq{j3q@JvgP;Z&MkE; z-bOX#@H*i6Xt>!C{_%B3_wy+E1;N8{(NRkvt0Z*OS2(3pO)1Jp6PM#^Mzg{|&LhH#68ik3T|p+E2auJ46S zT0zps9vgpbu46efE5|ft6S@QL?Q3(KTar;Ws8nwMY_d<&F16w?)|jb12NkR-HIY#= zk&h62UT}sq)2gJ8Xa&ziZ)#_HO6nV>watSyOtn_l?}lqnm)5ypw~ki7re`Ni`IYs1 zOrgt!&xKnWocIF9fWa$%s=61DLQvI>el)hU1J=X#x4WJB0OEqYo@=aWMUlgoVFPw3 zFZ&d9z6uSYE4~W#ihdQ!vU-0~k8#nga9jN$n-4{j@};Ki4kCg${Lz52DuKDq1!kKVWh zl&W5mpjg0Nu%@2L6ms!?E6jMO{i7(@Vx%4Xf;@PfoZ`Am4wlOrH{5>6j^9#T4SiuhE29*kr5=Vlv_^%-EKA_T77`#R1}u0~7)r)ETZJc&6h+ZI8Al3>LUTX2*K|ql zkK|;9g2m&%Z9(E%bXIxZLNC0I)Z3WF+cPCgO~vZva&RAJ+G3pjfPC?F;^?x@!C-+i z_22Rhk37DDdrWwk!Jpu8B{k_bgaR>4Bzz!`H}S z@Ui7}@gR(^TL4O?8r2%8ETDPqpZTrLC~$YlgN$ERef#rSYp4O%;PYDCTYcAz)TqE9 zm+VRzPM&>=0I5XZnZ+$j=J?#Q*%x@zG-39{GSrX$N^rA#obS$ktZ+BwL{a=@1&}=b z!w+r0c3NO~+rY$zA@iMzRUpcaub1vz9y-S_E$N?6F&fqU*(7a;`f}G~yT=P|^Ck$MdaTe|oWhv;KOe#p$RquOCb`(t7YLhuIFgKzkur*4ObD z8DqugHq5#M9V6VCTyh*FYR=Q1>sbhCfz?D4#dPki-5(mYL8nLqugImSvtr;S9N?ay zRkMKx{H%iXO>z2JOs%i}=GD6#qL3y{)!JsA8`#-N=X)EoW z%wcoVVq0H7Z$~uPoJ-oAY~R$*d#z0y?7$v4MXElZ#|;vPxaUOJJ;-ivb6*{4ECxJD zlR#t)MF{-!c7>dLRKmx#axIn=kA*XlU4%duWRxk2%)a@QL;B2OkoSpQF&I;8?h|K< z^bXpG8zQNciobsqc26|B$DtYD1gWu&=C(vEB(4aN9@bPX*=a(rZN>=K5jgT7xef(P z4sz5)0Tiyl_}g{eJ3@SlDXu5UVt@mm%}ZD_TXiSGly>$)BHcRIer0*Y*;^Ln2kEZi zuQoQ$28Fl5(Lt!h_xqpzeR!nJ1gt^LUbMHp6tCj}EjbBwqex?x4$5e_{5Rb%eVaWA zU4xu1kR|ZI)lVJaoC>h&xPzk*^Yf+D1LVJVu_wLAwPP!3cmrDmK_bEFA|OXe5$ikz zFPDWI-aSb02l?G69f)}{%AR3Yi* zLPDpu0`0utx@p`v2KS7(=|~?r7sqvA(9~PnyyaR?WTp@3OAurM|Kg*H z3f=o&N@nFFdQVwT&L30Py~{eWR1_kD3zGSMKtY}^P{;fS*z4$l3w60)dXsBBEkiI2 zAqLZ=KmHq_(9SG-~~thEwWc2MEY{{o5YK6tn3->$8q&Aq=)lM+nQJS zsbdNtOl%9fzF&|zbdWkO{N1HHcJc*dR@}U5er9gAXNQ7*u0N6i1w%|^K`PNPl{!s& zb12t*``nJLY(GQ0+jqy5gkzTsAY4&AmE(&T=KLr#cZ> z43$_w#^Odu3l8RjiL>y3yVfA**&Viy=9NOLF%32S&h*6{%$UWoh!1JenS__D+TFq- zK>Wecsf0p-hNYKv{G6N6S!j)}+(UfA2(1p)Fj>M()v_>be7 z(3=I8f}B#~K}_0i(g^7bvcBm_E_+)Om^Cy@7zt}}S%dHwbT#J5vEs=1rcxlPx$?61 z;+jrqZl#|@S(?idA7+}945Zw?7AcPGv&cl6qc!~Qdd$q`snCloEuFq}FkRLw`9HB@ zs=iBkn1vjlFmk|3y(8=wDcZ~}LFcU5y33QQshM%i73vstBX~*_l@5lqO`-MLRkXG- zU3V%c-XPoZm0LePV{6JP*czFy+6`JwMrS+_-yhX zu*pbb6g{bwPG0hx%;w3}%(4%=k+vF8Y{V+X%v4f1>!?)s>T89Dl8XS%+yKWVHic4P^9J2i9%YXYhV3Bqp* zvUmHDmS^8;S`e)1fr(1XR}wgZC|hbzW$ptoH`fR;h8D3KY7xT?4Eb~gdO(T80qfd9 z&UBv@p1iEMYwk;;Gk7qg_s(eyZ5erINJ=9u$HI%y#?i34?sN}+I zOM{m-o(Y5XrG;Yv?*}oWE&(fCt98y46#7w9FAxH?B}#DE=i1DX%LEBxriXY*<%bt! zu;CT2%p@ll9@|WEI$(QT%Zf3*sk0FR)A*v5k5K}7=n~-jO=Fr{p*>6adhyBZuVzJcidwifGl7vF&MAIOhHIGhYX5L& zS~>kg8VBH4I~Z1VN)F>oU^uYX`gdYe9n;fNjD)}`gLuC@5a14!`}?C)tj9yU1IHMO#zexi;(bISE%hi-ors&mwVMG{2r_-3m?bB?FTXP%l*}02|z$I;do6E4N#?l>+AXr zXZhe`Db9Q`sJR}@`994OM;SIwO4yAo1V*3Mmt<85j! z4ilDDVkQK%(z-R8YB!@7BQ=jV=drJK>zs`v_Xu15(kUK}LO2Q3QgO%y{-9RcY1T*~ zt{7{smw*}o&RH=zp^pKU3v@?}=}poPE{O&$2j4hc4IisMoZU4dSL3NR=~)6oTJg*d zx%3TD4lp=k*U}mj9tzi}T8HIu6(Ob?b%ocetES{)n>`)!^A>pMmeTR?rfJVb)p(0KEBhUz^A5UFBpxu20 zD@+wsWR-%$% z9-H11b5Tr0#4ZnXoA-J2hDMJ;^ITGwK-DPC?k0Qmc0nGbbDA!E{qBirdi4}KcnJhL zH7%U!wsFMbxwUT^m~0z^4tT}}UOUueKFSLdjVR|f`xQMVDC`>=9HHeUb3ltYZw5W>ZW*;R>``7@jX@8x zDtO-uWx`VhWX zOd>LFFb|DN7j1my!=@DKHJwZDRMrf$7e8BUqObyr<1-TRkvtz+SsxGvh^c@thSe=U zb#&ux?V1|8#*JP7VwLb+(13*6l3H~9JPQdO8--I|PR^FiOu-?L=xq49RG2g@VsFS% zfsXoDp)HX;757HF`r(eA#qC{!Ma+t%zpgVET77F*}4lrSR505y4oVa4y=K0G8-@oTDx+hL)3CIFgc^2ruLN5;mmI$>ym#T`Sq@ zj}ufI;D62^+Q=OqVqTl!Y?+xJo_#<9G9&_ZsQFdgK3+(DC6ZqKz@7GfXd1`PJ<)I; z80T_>bh2~P=g`PG|0F8#ZpafgrB7UI6FX9)np_el_NKM_T(mqzg)fU1T{}~qe=u^I z4U08BMq(8TLKF)E*L(N;D_6D`{br9_NNiQ~a~#yQ;{^W$Fx$5y+QcM9WFPuoI=>ji zp)4JMFlNuC;%jKNrSxMY)z9zV=kGb*J@K*X%LXUgy|(3&s1BU!#}^Z7CVW78aRePv$AcjMJ;O78i~3vG;`EQq2WH`RlS6SB8*yZ` z@mViF&n5yZz;XYR0?qIju0cIXnvK}Nu3W3B6Q{hz#r!lq;7K_x0u>pDgE19|OR>+< z)Ft8KiKMkuiD^^Xi_WoIaz#NW85ZhvGcq{En z!xS+01xl#tIeSs}yq%+5M`&z6TFX9?NUNu0n`2YE^Gm$Lo}uiP>d9Av9wg?XIBq$) z#?y_Lvy3MvMIoq2z0U)(gS#p$ugG)Ft|WSEp;*N7aOtk z@aI1M9khj|d4=%GfMKHcGWhyV-PYai1Muu6(vSoKb;AlAN7(P4q*gVq(`;leB~nKx z$p*c>43aIKW_`&L~g_u4YNe%i<|vRz~h=!~%t)bok~Y=>PCTzK(CWgRevNg(OSWsuLs;$~jpYa(;aC0HTFIOVt3WN)&M z8?_vJ@Y2YFTX;CIp&+_sTpEw&E8~^e)0>etP_O$vZJ8&lhq1tyZx*uZ*$n=r zjlI4xU}dJfuJ?OdKoqJ&kT7@H(4Hg`WH+A9H8KyD+Bt1-$NNNG>EzO;d{!+WTYScQ ziJ~jN_U_6WJDN;)%d7QMrrP(NT`|*g7L-h92E@71j_^ZJNMpdAxP8w(Fc;r8R%VVY zs=L~E9ErVOFPVaL7Em|&<0e{QaCm#&5>Vq}szO4#x7)#0VdOHuEtFE%baXGsr6!M zV8M^114QkNjkN@H4u4tGH)V0eRj@(jqlE$Ut*82U-JMAci07y=paoq;i@~EQkAzr4 zLh+WssJEkww&^JDi#IE$N<9;R| zT4hz}r_+Nm8Fx<;DfkCE7dWpAHf_W=ZD_O!w^E?pD|BjnzU8PhRwoG>-34{3#x=&rDc~B+Qvs26aa@ z5Eyf%!649jr9faX(RSuV;l@6sp)@w`cq&s37CH?Iq7ED^K^U#v-;>$ocWHmUZ&z=7 z8`lMYt=kN2DEVR0^aEpLaJ%0D6j?rIW?cW%+n=7=f}}?YL+Y!W-Eqid!n7%)vUbD_``DnGYl52D8}wvPr7X+t&SsGR6zpq-+dfl&a|fKe43iOJy&ft zFbNC_ic24X6ppW`f@b(D~sc-7VeLD$l{;0qNK6BEHf z+7~_9;ZJ!Z9b00q<)*nBM+YdBa710KgD$3Ivse^qWC9`yq>?cAPM@r*s$yzpTDQ0S zp2p4i_LAa>Gfr>%=Ct(mk2-bOqe5v7Nn1=6fHS99B-mt)8jU%AKQDCYlAUP&FrHf- z-!npTMU(})I1^_l!a*Eaf7#oH>(L{cPc3^l5A9QMvNS-ZHt^#UQGo343RJ126FZT6 zN^aeyMJh5fngiDGTks}Q{3YJ>_@-UbEIFs;^!XQt04F82BUT5L+5@FP=>%D*+BNLr zCqH1WvCL*9IUgp{W+FH2FQ`_jgwF4$(`JUhG^U++Wvg^|Kv+yKy>!$K$a6eI1c0#> z+KiCeDV4f6y$O?Bu^kQ79alNEXW^#e_Kt_}3?t<762VODG4EHFW{(@`aacB_1!6(E4)rNFI)78aGvt0O;`C(0C6n;aHs*he#dS3%Q3 zqSh94l&rbr3Y!2r%Q8?O(uAYYgY3gNGlIPLtP~JcS^q)9T;Yw-(s{KK=(``^_D@~V z?Q0$EV3WPyuJR+>1<@!JPFqm3aazx|aII^UrBWLlCPe)?wTi zGaVhxg_vJxpiqStUPjrRE$*6A%|uys%UZi<2eg7dReI0G47krp&2i29AudHOftVQN z^h>5YNGo*4Zq99ukFTv1WWH=;K7_abo|yivd=O2B!?~yzNr9WG%1Obw^%E zYBdNV>2#|_b7b?586}m4?Qb-lGP%{(?UiWfq4y+pZHTP9iN08dn8EdW+1{`Ms7WIX} zL~Mx}ds|7_kE7!b+FE(TKS(;oa)3F3Y`Q$X8h_;11CLxj z$8+V2 z6*dn$ew$1)x(mOeEv>QV_yfN-_-r)Ot%P*9lgt8Yv<%&-RMK1JNM*roL`QL`TF(ee(; zCqD)9u79H4Ihx4O)DIi;W~xeq+wPkSUBBoF4$s7B&$)VJQF9&`-@RU30hK755@lJ{ zlY9{n1aDhe6Z$D9Dp~KGt@2iPbw@(>Qdv)Kn_$TcOzWI!KY)DM1=+l2$4HYyrd$dWsw=)C8pkBy_vG@ZZ1<7_Oe^>ZG7mKVP&6 z5(Xah6#BR2?qcA!qzs$e4-!C)vI%oMP1a3nQj`j3ni@GPQHp|KWXbf`*+L;F*;)dk zR#WU7n0j2S4AUDd0GXyFA)5qylHYY7&7B{tM_SJZmEiiv40$Sns~v>b3FTTB<2WiK zi6P)|G(7qXV*Q@zVREBm@@!y*R69<@TCHQvbNXzooixO-&svLH7{*~1Gp&5?PbHlAk zJ(aYvA9gqQH2iOqzjj?ja{q(};iYq~)&}NA>T0p3-hG4N3JSk375&%a{~x~n&oDz$ z`YF(*$cXR*u5EWnrw4x4xnI#0FmV3K`sYBjR^6GMmAx5gF;eczS(13mjG$QK9IZ?BbuCi3! zpN0Og4BtXk>z6ejH}hvg|Fr(-;D5XNPp?(r ztmFwYTM$A{3nf6v>4|bD(nZ5?H5|{fam9Q8^#J~dZ-3e{>e{x+h8$=1p1xYx;182L zb~y|QS)kk#QkVYdaVJcxK;df8_t}dx{SE0q3jJZ7>6K5ZE(lW(xVPsI>&b0`qfFyW zZL83MKdgUtAoNe`j}HFd?kaZwQD&!_*>=#?xdcS // message, field number = 9 - > test_oneof; - - bool has_name() const { - return test_oneof.index() == 1; - } - void set_name(std::string name) { - test_oneof.emplace<1>(std::move(name)); - } - const std::string& name() const { - assert(test_oneof.index() == 1); - return std::get<1>(test_oneof); - } - - bool has_sub_message() const { - return test_oneof.index() == 2; - } - void set_allocated_sub_message(::SubMessage* p) { - assert(p); - test_oneof.emplace<2>(p); - } - const std::unique_ptr<::SubMessage>& sub_message() const { - assert(test_oneof.index() == 2); - return std::get<2>(test_oneof); - } -}; -struct SubMessage { - int32_t val; // int32, field number = 1 -}; -``` - -## Maps - -``` -syntax = "proto3"; -message SampleMap { - map projects = 3; -} -message Project { - string name = 1; -} -``` - -```cpp -struct SampleMap { - std::map projects; // message, field number = 3 -}; -struct Project { - std::string name; // string, field number = 1 -}; -``` \ No newline at end of file diff --git a/website/docs/en/struct_pb/struct_pb_intro.md b/website/docs/en/struct_pb/struct_pb_intro.md index 746f4385d..26f4de8e5 100644 --- a/website/docs/en/struct_pb/struct_pb_intro.md +++ b/website/docs/en/struct_pb/struct_pb_intro.md @@ -1,31 +1,132 @@ -# struct_pb Introduction +# struct_pb introduction -## Motivation -Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data. So many programs use protobuf as their serialization library. It is convienient for our customers to use `struct_pack` if we (`struct_pack`) can compatible with protobuf binary format. That is why we create `struct_pb`. +struct_pb is an easy to use, C++17, header only, high performance protobuf format serialization library. -## Background -In this section, we introduce the [protocol buffer wire format](https://developers.google.com/protocol-buffers/docs/encoding), which defines the details of how protobuf message is sent on the wire and how much space it consumes on disk. -### Message Structure -A protocol buffer message is a series of key-value pairs. The binary version of a message just uses the field's number as the key -- the name and declared type for each field can only be determined on the decoding end by referencing the message type's definition. -![](images/pb_format.jpeg) +## motiviation +Don't depend on proto files, don't depend on protoc to generate code. + +Utilize inline, zero copy, compile-time compute to optimize performance. + +## example + +### define struct ```cpp -Tag = (field_number << 3) | wire_type +#include + +struct my_struct { + int x; + bool y; + struct_pb::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest { + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest, name, value, var); ``` +### serialization and deserialization +```cpp +int main() { + nest v{"Hi", {1, false, {3}}, 5}, v2{}; + std::string s; + struct_pb::to_pb(v, s); + struct_pb::from_pb(v2, s); + assert(v.var == v2.var); + assert(v.value.y == v2.value.y); + assert(v.value.z == v2.value.z); +} +``` +the above struct mapping to a proto file, like this: +``` +message my_struct { + int32 optional_int32 = 1; + bool optional_int64 = 2; + sfixed64 z = 3; +} +message nest { + string name = 1; + my_struct value = 2; + int32 var = 3; +} +``` -### Base 128 Varints -Variable-width integers, or _varints_, are at the core of the wire format. They allow encoding unsigned 64-bit integers using anywhere between one and ten bytes, with small values using fewer bytes. +## dynamic reflection +features: +- create instance by object's name; +- get all fields name from an object; +- get/set field value by filed name and instance; -## Design -![](images/struct_pb_overview.jpeg) +### create instance by object's name +```cpp +struct my_struct { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 : public iguana::base_imple { + nest1() = default; + nest1(std::string s, my_struct t, int d) + : name(std::move(s)), value(t), var(d) {} + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest1, name, value, var); +``` -## Type Mapping -proto3 first, -see also [Protocol Buffers Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#scalar) +```cpp +std::shared_ptr t = struct_pb::create_instance("nest1"); +``` +"create instance by object's name" require the struct inherited from struct_pb::base_impl. If not inherited,create_instance will throw exception. + +### get/set field value by filed name and instance +```cpp + auto t = iguana::create_instance("nest1"); + + std::vector fields_name = t->get_fields_name(); + CHECK(fields_name == std::vector{"name", "value", "var"}); + + my_struct mt{2, true, {42}}; + t->set_field_value("value", mt); + t->set_field_value("name", std::string("test")); + t->set_field_value("var", 41); + nest1 *st = dynamic_cast(t.get()); + auto p = *st; + std::cout << p.name << "\n"; + auto &r0 = t->get_field_value("name"); + CHECK(r0 == "test"); + auto &r = t->get_field_value("var"); + CHECK(r == 41); + auto &r1 = t->get_field_value("value"); + CHECK(r1.x == 2); +``` +“set field value by filed name and instance” require the setting value type is same with filed type, don't allow explicit transform, otherwise throw exception. + +also support set field value with its type: +```cpp +t->set_field_value("name", "test"); +``` +implicit set field type can support implicit assign field value. If the field type is not the real field type, will throw exception. + +## benchmark -### Overview +monster case: + +struct_pb is 2.4 faster than protobuf when serializing a monster; + +struct_pb is 3.4 faster than protobuf when deserializing a monster; + +the code in struct_pack benchmark. + +## struct_pb and protobuf type mapping Scalar Value Types with no modifier (a.k.a **singular**) -> T Scalar Value Types with **optional** -> `std::optional ` @@ -38,33 +139,9 @@ any message type -> `std::optional ` enum -> enum class -oneof -> `std::variant ` - - -Note: - -- singular. - You cannot determine whether it was parsed from the wire. It will be serialized to the wire unless it is the default value. see also [Field Presence](https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md). -- optional. - You can check to see if the value was explicitly set. -- repeat. - In proto3, repeated fields of scalar numeric types use packed encoding by default. -- map. - The key of map can be any integral or string type except enum. - The value of map can be any type except another map. -- enum. - Every enum definition must contain a constant that maps to zero as its first element. - Enumerator constants must be in the range of a 32-bit integer. - During deserialization, unrecognized enum values will be preserved in the message -- oneof. - If you set an oneof field to the default value (such as setting an int32 oneof field to 0), the "case" of that oneof field will be set, and the value will be serialized on the wire. -- default value - - For numeric types, the default is 0. - - For enums, the default is the zero-valued enumerator. - - For strings, bytes, and repeated fields, the default is the zero-length value. - - For messages, the default is the language-specific null value. - -### Basic +oneof -> `std::variant <...>` + +### type mapping table | .proto Type | struct_pb Type | pb native C++ type | Notes | |-------------|-----------------------------------|--------------------|------------------------------------| | double | double | double | 8 bytes | @@ -73,98 +150,26 @@ Note: | int64 | int64 | int64 | | | uint32 | uint32 | uint32 | | | uint64 | uint64 | uint64 | | -| sint32 | int32 | int32 | ZigZag + variable-length encoding. | -| sint64 | int64 | int64 | | -| fixed32 | uint32 | uint32 | 4 bytes | -| fixed64 | uint64 | uint64 | 8 bytes | -| sfixed32 | int32 | int32 | 4 bytes,$2^{28}$ | -| sfixed64 | int64 | int64 | 8 bytes,$2^{56}$ | +| sint32 | sint32_t | int32 | ZigZag + variable-length encoding. | +| sint64 | sint6_t | int64 | | +| fixed32 | fixed32_t | uint32 | 4 bytes | +| fixed64 | fixed64_t | uint64 | 8 bytes | +| sfixed32 | sfixed32_t | int32 | 4 bytes,$2^{28}$ | +| sfixed64 | sfixed64_t | int64 | 8 bytes,$2^{56}$ | | bool | bool | bool | | | string | std::string | string | $len < 2^{32}$ | | bytes | std::string | string | | -| enum | enum class: int {} | enum: int {} | | -| oneof | std::variant | | | - -Note: - -- for enum, we use `enum class` instead of `enum` -- for oneof, we use `std::variant` with first template argument `std::monostate` - -## File Mapping -each `xxx.proto`file generates corresponding `xxx.struct_pb.h` and `xxx.struct_pb.cc` -all dependencies will convert to include corresponding headers. -``` -syntax = "proto3"; - -import "foo.proto"; - -message Bar { - Foo f = 2; -} -``` -mapping to cpp -```cpp -#include "foo.struct_pb.h" -struct Bar { -std::unique_ptr f; -}; - -``` -## protoc Plugin -```bash -protoc --plugin=path/to/protoc-gen-structpb --structpb_out=$OUT_PATH xxx.proto -``` -e.g. -```shell -protoc --plugin=/tmp/protoc-gen-structpb --structpb_out=. conformance.proto -``` -## TODO - --[ ] using value instead of `std::unique_ptr` when no circle dependencies - -for example, we convert the message `SearchResponse` to c++ struct `SearchResponse_v1` -``` -message SearchResponse { - Result result = 1; -} - -message Result { - string url = 1; -} -``` - -```cpp -struct SearchResponse_v1 { - std::unique_ptr result; -}; -``` - -we can optimize the pointer overhead if we can convert the message `SearchResponse` to c++ struct `SearchResponse_v2` -```cpp -struct SearchResponse_v2 { - Result result; -}; -``` - - -## Compatibility -see also - -- [Language Guide (proto3) -- Updating A Message Type](https://developers.google.com/protocol-buffers/docs/proto3#updating) -- [oneof compatibility](https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility_issues) -## Limitation - -- SGROUP(deprecated) and EGROUP(deprecated) are not support -- Reflection not support -- proto2 extension not support - -## Acknowledge - -- [Embedded Proto](https://embeddedproto.com/): an easy to use C++ Protocol Buffer implementation specifically suited for microcontrollers -- [protobuf-c](https://github.com/protobuf-c/protobuf-c): Protocol Buffers implementation in C -- [protozero](https://github.com/mapbox/protozero): Minimalist protocol buffer decoder and encoder in C++ -- [protopuf](https://github.com/PragmaTwice/protopuf): A little, highly templated, and protobuf-compatible serialization/deserialization header-only library written in C++20 - -## Reference - -- [Protocol Buffers Compiler Plugins](https://developers.google.com/protocol-buffers/docs/reference/other#plugins) +| enum | enum class: int {}/enum | enum: int {} | | +| oneof | std::variant<...> | | | + +## limitation +- only support proto3, not support proto2 now; +- don't support reflection now; +- don't support unkonwn fields; +- struct must inherited from base_impl; + +## roadmap +- support proto2; +- support reflection; +- support unkonwn fields; +- no need inheriting from base_impl; diff --git a/website/docs/en/struct_pb/struct_pb_quick_start.md b/website/docs/en/struct_pb/struct_pb_quick_start.md deleted file mode 100644 index 28fdb4d3c..000000000 --- a/website/docs/en/struct_pb/struct_pb_quick_start.md +++ /dev/null @@ -1,237 +0,0 @@ -# struct_pb Quick Start - -Note: if you are not familiar with the official c++ implement, -[Protocol Buffer Basics: C++](https://developers.google.com/protocol-buffers/docs/cpptutorial) -is a good material to learn. - -This tutorial provides a basic C++ programmer's introduction to work with struct_pb, -which is the protobuf compatible solution of the [yalantinglibs](https://github.com/alibaba/yalantinglibs). - -By walking through creating a simple example application, it shows you how to - -- Define message formats in a `.proto` file. (same as official protobuf document) -- Use the protocol buffer compiler (`protoc`) with `struct_pb` plugin. -- Use the `struct_pb` low-level API to write and read messages. - -## Defining Your Protocol Format - -we use proto3 here. - -``` -syntax = "proto3"; - -package tutorial; - -message Person { - string name = 1; - int32 id = 2; - string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - string number = 1; - PhoneType type = 2; - } - - repeated PhoneNumber phones = 4; -} - -message AddressBook { - repeated Person people = 1; -} - -``` - -## Compiling Your Protocol Buffers - -Now that you have a `.proto`, the next thing you need to do is generate the struct you'll need to -read and write `AddressBook` (and hence `Person` and `PhoneNumber`) messages. -To do this, you need to run the protocol buffer compiler `protoc` with `struct_pb` plugin `protoc-gen-struct_pb` on your `.proto`. - -```shell -protoc -I=$SRC_DIR --plugin=$PATH_TO_protoc-gen-struct_pb --struct_pb_out=$DST_DIR $SRC_DIR/addressbook.proto -``` -see [Generating source code](https://alibaba.github.io/yalantinglibs/en/struct_pb/struct_pb_generating_your_struct.html) for details. - -This generates the following files in your specified destination directory: - -- `addressbook.struct_pb.h`, the header which declares your generated struct. -- `addressbook.struct_pb.cc`, which contains the `struct_pb` low-level API implementation of your struct. - - -## The struct_pb low-level API - -Let's look at some generated code and see what struct and functions the compiler has created for you. -If you look in `addressbook.struct_pb.h`, you can see that you have a struct for each message you specified in `addressbook.proto`. - - -```cpp - -namespace tutorial { -struct Person; -struct AddressBook; -struct Person { - enum class PhoneType: int { - MOBILE = 0, - HOME = 1, - WORK = 2, - }; - struct PhoneNumber { - std::string number; // string, field number = 1 - ::tutorial::Person::PhoneType type; // enum, field number = 2 - }; - std::string name; // string, field number = 1 - int32_t id; // int32, field number = 2 - std::string email; // string, field number = 3 - std::vector<::tutorial::Person::PhoneNumber> phones; // message, field number = 4 -}; -struct AddressBook { - std::vector<::tutorial::Person> people; // message, field number = 1 -}; - -} // namespace tutorial -namespace struct_pb { -namespace internal { -// ::tutorial::Person::PhoneNumber -template<> -std::size_t get_needed_size<::tutorial::Person::PhoneNumber>(const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person::PhoneNumber>(char*, std::size_t, const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t); - -// ::tutorial::Person -template<> -std::size_t get_needed_size<::tutorial::Person>(const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person>(char*, std::size_t, const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t); - -// ::tutorial::AddressBook -template<> -std::size_t get_needed_size<::tutorial::AddressBook>(const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::AddressBook>(char*, std::size_t, const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -## The struct_pb high-level API - -We encapsulate the low-level API to make `struct_pb` easier to use. - -``` -/* - * High-Level API for struct_pb user - * If you need more fine-grained operations, encapsulate the internal API yourself. - */ -template, typename T> -Buffer serialize(const T& t, const UnknownFields& unknown_fields = {}) { - Buffer buffer; - auto size = struct_pb::internal::get_needed_size(t, unknown_fields); - buffer.resize(size); - struct_pb::internal::serialize_to(buffer.data(), buffer.size(), t, unknown_fields); - return buffer; -} -template -bool deserialize_to(T& t, UnknownFields& unknown_fields, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size(), unknown_fields); -} -template -bool deserialize_to(T& t, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size()); -} - -``` - -## Writing A Message - -```cpp -void prompt_for_address(tutorial::Person& person) { - std::cout << "==================================" << std::endl; - std::cout << " Add People " << std::endl; - std::cout << "==================================" << std::endl; - std::cout << "Enter person ID number: "; - std::cin >> person.id; - std::cin.ignore(256, '\n'); - std::cout << "Enter name: "; - std::getline(std::cin, person.name); - std::cout << "Enter email address (blank for none): "; - std::getline(std::cin, person.email); - while (true) { - std::cout << "Enter a phone number (or leave blank to finish): "; - tutorial::Person::PhoneNumber phone_number; - std::getline(std::cin, phone_number.number); - if (phone_number.number.empty()) { - break ; - } - std::cout << "Is this a mobile, home, or work phone? "; - std::string type; - std::getline(std::cin, type); - if (type == "mobile") { - phone_number.type = tutorial::Person::PhoneType::MOBILE; - } - else if (type == "home") { - phone_number.type = tutorial::Person::PhoneType::HOME; - } - else if (type == "work") { - phone_number.type = tutorial::Person::PhoneType::WORK; - } - else { - std::cout << "Unknown phone type: Using default." << std::endl; - } - person.phones.push_back(phone_number); - } -} -``` - -## Reading A Message - -```cpp -void list_people(const tutorial::AddressBook& address_book) { - std::cout << "==================================" << std::endl; - std::cout << " List People " << std::endl; - std::cout << "==================================" << std::endl; - for(const auto& person: address_book.people) { - std::cout << " Person ID: " << person.id << std::endl; - std::cout << " Name: " << person.name << std::endl; - if (!person.email.empty()) { - std::cout << "E-mail address: " << person.email << std::endl; - } - for(const auto& phone: person.phones) { - switch (phone.type) { - case tutorial::Person::PhoneType::MOBILE: - std::cout << "Mobile phone #: "; - break; - case tutorial::Person::PhoneType::HOME: - std::cout << " Home phone #: "; - break; - case tutorial::Person::PhoneType::WORK: - std::cout << " Work phone #: "; - break; - } - std::cout << phone.number << std::endl; - } - } -} -``` - -## the demo code - -- [code in yalantinglibs repo](https://github.com/alibaba/yalantinglibs/blob/main/src/struct_pb/examples/tutorial.cpp) -- [code in standalone repo](https://github.com/PikachuHyA/struct_pb_tutorial) diff --git a/website/docs/en/struct_pb/struct_pb_supported_features.md b/website/docs/en/struct_pb/struct_pb_supported_features.md deleted file mode 100644 index a47a96177..000000000 --- a/website/docs/en/struct_pb/struct_pb_supported_features.md +++ /dev/null @@ -1,67 +0,0 @@ -# Supported Features - -## proto3 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | - -## proto2 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Extensions | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | diff --git a/website/docs/zh/guide/what_is_yalantinglibs.md b/website/docs/zh/guide/what_is_yalantinglibs.md index 9356d2625..fd484bf13 100644 --- a/website/docs/zh/guide/what_is_yalantinglibs.md +++ b/website/docs/zh/guide/what_is_yalantinglibs.md @@ -426,11 +426,9 @@ yalantinglibs工程自身支持如下配置项,如果你使用cmake find_packa 无依赖。 -### struct_pb (可选) +### struct_pb -默认情况下我们不会安装struct_pb, 你需要手动安装以下依赖: - -- [protobuf](https://protobuf.dev/) +无依赖。 ## 独立子仓库 diff --git a/website/docs/zh/struct_pb/struct_pb_api.md b/website/docs/zh/struct_pb/struct_pb_api.md deleted file mode 100644 index 2bc379d4e..000000000 --- a/website/docs/zh/struct_pb/struct_pb_api.md +++ /dev/null @@ -1,65 +0,0 @@ -# struct_pb API - -Current, struct_pb provide low-level APIs only, which are in namespace `struct_pb::internal`. - -For example, the `SearchRequest` message from [Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#simple) - -``` -syntax = "proto3"; - -message SearchRequest { - string query = 1; - int32 page_number = 2; - int32 result_per_page = 3; -} -``` - -we generate the source code -```cpp -struct SearchRequest { - std::string query; // string, field number = 1 - int32_t page_number; // int32, field number = 2 - int32_t result_per_page; // int32, field number = 3 -}; - -namespace struct_pb { -namespace internal { -// ::SearchRequest -std::size_t get_needed_size(const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -void serialize_to(char*, std::size_t, const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -bool deserialize_to(::SearchRequest&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -bool deserialize_to(::SearchRequest&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -## Serialization - -- get_needed_size - -To get the buffer size, use the `get_needed_size` function. - -To support [Unknown Fields](https://developers.google.com/protocol-buffers/docs/proto3#unknowns), -an extra argument `unknown_fields` with default value is added. - -- serialize_to - -To serialize a message to a buffer, use the `serialize_to` function. - -Before use this function, make sure the buffer is sufficiently large. -e.g. use `get_needed_size` and then allocate buffer. - -To support [Unknown Fields](https://developers.google.com/protocol-buffers/docs/proto3#unknowns), -an extra argument `unknown_fields` with default value is added. - -## Deserialization - -- deserialize_to - -To deserialize a message from buffer, use the `deserialize_to` function. - -Returns true on success. - -To support [Unknown Fields](https://developers.google.com/protocol-buffers/docs/proto3#unknowns), -the overload function with an extra argument `unknown_fields` is added. diff --git a/website/docs/zh/struct_pb/struct_pb_generating_your_struct.md b/website/docs/zh/struct_pb/struct_pb_generating_your_struct.md deleted file mode 100644 index 10b2d0021..000000000 --- a/website/docs/zh/struct_pb/struct_pb_generating_your_struct.md +++ /dev/null @@ -1,34 +0,0 @@ -# Generating source code - -First, you need install protobuf. - -on Mac -```shell -brew install protobuf -``` - -on Ubuntu -```shell -apt-get install protobuf -``` - -on CentOS -```shell -yum install protobuf -``` - -Second, you need install or compile struct_pb protoc plugin `protoc-gen-struct_pb`. - -Finally, you can use the following command to generate the code. - -```shell -protoc --plugin=protoc-gen-struct_pb --struct_pb_out . xxx.proto -``` - -or use the helper function on your `CMakeLists.txt` - -```cmake -find_package(Protobuf) -protobuf_generate_struct_pb(PROTO_SRCS PROTO_HDRS xxxx.proto) -``` - diff --git a/website/docs/zh/struct_pb/struct_pb_guide_proto3.md b/website/docs/zh/struct_pb/struct_pb_guide_proto3.md deleted file mode 100644 index 9366ccb28..000000000 --- a/website/docs/zh/struct_pb/struct_pb_guide_proto3.md +++ /dev/null @@ -1,194 +0,0 @@ -# struct_pb Guide (proto3) - -## Defining A Message Type - -Here is a simple message type from [official document - Defining A Message Type](https://developers.google.com/protocol-buffers/docs/proto3#simple). - -``` -syntax = "proto3"; - -message SearchRequest { - string query = 1; - int32 page_number = 2; - int32 result_per_page = 3; -} -``` -Our protoc plugin convert the message type to C++ struct and corresponding low-level serialization API. - -```cpp -struct SearchRequest { - std::string query; // string, field number = 1 - int32_t page_number; // int32, field number = 2 - int32_t result_per_page; // int32, field number = 3 -}; -namespace struct_pb { -namespace internal { -// ::SearchRequest -std::size_t get_needed_size(const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -void serialize_to(char*, std::size_t, const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -bool deserialize_to(::SearchRequest&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -bool deserialize_to(::SearchRequest&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -You can use the struct `SearchRequest` as a normal C++ struct. - -## Enumerations - -``` -syntax = "proto3"; -enum Corpus { - CORPUS_UNSPECIFIED = 0; - CORPUS_UNIVERSAL = 1; - CORPUS_WEB = 2; - CORPUS_IMAGES = 3; - CORPUS_LOCAL = 4; - CORPUS_NEWS = 5; - CORPUS_PRODUCTS = 6; - CORPUS_VIDEO = 7; -} -``` - -```cpp -enum class Corpus: int { - CORPUS_UNSPECIFIED = 0, - CORPUS_UNIVERSAL = 1, - CORPUS_WEB = 2, - CORPUS_IMAGES = 3, - CORPUS_LOCAL = 4, - CORPUS_NEWS = 5, - CORPUS_PRODUCTS = 6, - CORPUS_VIDEO = 7, -}; -``` - -## Nested messages - -Here is the sample from [proto3 Nested Types](https://developers.google.com/protocol-buffers/docs/proto3#nested) - -``` -syntax = "proto3"; -message Outer { // Level 0 - message MiddleAA { // Level 1 - message Inner { // Level 2 - int64 ival = 1; - bool booly = 2; - } - } - message MiddleBB { // Level 1 - message Inner { // Level 2 - int32 ival = 1; - bool booly = 2; - } - } -} -``` - -```cpp -struct Outer { - struct MiddleAA { - struct Inner { - int64_t ival; // int64, field number = 1 - bool booly; // bool, field number = 2 - }; - }; - struct MiddleBB { - struct Inner { - int32_t ival; // int32, field number = 1 - bool booly; // bool, field number = 2 - }; - }; -}; -``` - -## Oneof - -Here is the sample from [proto3 Oneof](https://developers.google.com/protocol-buffers/docs/proto3#oneof) - -``` -syntax = "proto3"; -message SampleMessage { - oneof test_oneof { - string name = 4; - SubMessage sub_message = 9; - } -} -message SubMessage { - int32 val = 1; -} -``` -The oneof type is mapped to `std::varint` with lots of helper functions. - -```cpp -struct SampleMessage { - enum class TestOneofCase { - none = 0, - name = 4, - sub_message = 9, - }; - TestOneofCase test_oneof_case() const { - switch (test_oneof.index()) { - case 1: - return TestOneofCase::name; - case 2: - return TestOneofCase::sub_message; - default: - return TestOneofCase::none; - } - } - - std::variant // message, field number = 9 - > test_oneof; - - bool has_name() const { - return test_oneof.index() == 1; - } - void set_name(std::string name) { - test_oneof.emplace<1>(std::move(name)); - } - const std::string& name() const { - assert(test_oneof.index() == 1); - return std::get<1>(test_oneof); - } - - bool has_sub_message() const { - return test_oneof.index() == 2; - } - void set_allocated_sub_message(::SubMessage* p) { - assert(p); - test_oneof.emplace<2>(p); - } - const std::unique_ptr<::SubMessage>& sub_message() const { - assert(test_oneof.index() == 2); - return std::get<2>(test_oneof); - } -}; -struct SubMessage { - int32_t val; // int32, field number = 1 -}; -``` - -## Maps - -``` -syntax = "proto3"; -message SampleMap { - map projects = 3; -} -message Project { - string name = 1; -} -``` - -```cpp -struct SampleMap { - std::map projects; // message, field number = 3 -}; -struct Project { - std::string name; // string, field number = 1 -}; -``` \ No newline at end of file diff --git a/website/docs/zh/struct_pb/struct_pb_intro.md b/website/docs/zh/struct_pb/struct_pb_intro.md index 746f4385d..0e1292fa3 100644 --- a/website/docs/zh/struct_pb/struct_pb_intro.md +++ b/website/docs/zh/struct_pb/struct_pb_intro.md @@ -1,31 +1,124 @@ -# struct_pb Introduction +# struct_pb 简介 -## Motivation -Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data. So many programs use protobuf as their serialization library. It is convienient for our customers to use `struct_pack` if we (`struct_pack`) can compatible with protobuf binary format. That is why we create `struct_pb`. +struct_pb 是基于C++17 开发的高性能、易用、header only的protobuf格式序列化/反序列化库。 -## Background -In this section, we introduce the [protocol buffer wire format](https://developers.google.com/protocol-buffers/docs/encoding), which defines the details of how protobuf message is sent on the wire and how much space it consumes on disk. -### Message Structure -A protocol buffer message is a series of key-value pairs. The binary version of a message just uses the field's number as the key -- the name and declared type for each field can only be determined on the decoding end by referencing the message type's definition. -![](images/pb_format.jpeg) +## 动机 +不再依赖proto文件去定义dsl message,而是通过C++ 结构体去定义需要序列化/反序列化的对象;因为没有protoc文件所以也不再依赖protoc去生成代码。通过C++17去实现可以做很多性能优化,从而获得更好的性能,比如可以支持反序列化时对字符串的零拷贝、尽可能内联和编译期计算以及字符串非memset的resize等。 +## 例子 + +### 定义结构体 +```cpp +#include + +struct my_struct : struct_pb::base_impl { + int x; + bool y; + struct_pb::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest : struct_pb::base_impl { + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest, name, value, var); +``` + +### 序列化 +```cpp +int main() { + nest v{"Hi", {1, false, {3}}, 5}, v2{}; + std::string s; + struct_pb::to_pb(v, s); + struct_pb::from_pb(v2, s); + assert(v.var == v2.var); + assert(v.value.y == v2.value.y); + assert(v.value.z == v2.value.z); +} +``` +上面的这个结构体如果对应到protobuf的proto文件则是: +``` +message my_struct { + int32 optional_int32 = 1; + bool optional_int64 = 2; + sfixed64 z = 3; +} + +message nest { + string name = 1; + my_struct value = 2; + int32 var = 3; +} +``` + +## 动态反射 +特性: +- 根据对象名称创建实例; +- 获取对象的所有字段名; +- 根据对象实例和字段名获取或设置字段的值 + +### 根据名称创建对象 ```cpp -Tag = (field_number << 3) | wire_type +struct my_struct { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 : public iguana::base_imple { + nest1() = default; + nest1(std::string s, my_struct t, int d) + : name(std::move(s)), value(t), var(d) {} + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest1, name, value, var); ``` +```cpp +std::shared_ptr t = iguana::create_instance("nest1"); +``` +根据对象nest1创建了实例,返回的是基类指针。 +“根据对象名称创建实例” 要求对象必须从iguana::base_impl 派生,如果没有派生则创建实例会抛异常。 -### Base 128 Varints -Variable-width integers, or _varints_, are at the core of the wire format. They allow encoding unsigned 64-bit integers using anywhere between one and ten bytes, with small values using fewer bytes. +### 根据名称设置字段的值 +```cpp + auto t = iguana::create_instance("nest1"); + + std::vector fields_name = t->get_fields_name(); + CHECK(fields_name == std::vector{"name", "value", "var"}); + + my_struct mt{2, true, {42}}; + t->set_field_value("value", mt); + t->set_field_value("name", std::string("test")); + t->set_field_value("var", 41); + nest1 *st = dynamic_cast(t.get()); + auto p = *st; + std::cout << p.name << "\n"; + auto &r0 = t->get_field_value("name"); + CHECK(r0 == "test"); + auto &r = t->get_field_value("var"); + CHECK(r == 41); + auto &r1 = t->get_field_value("value"); + CHECK(r1.x == 2); +``` +“根据对象实例和字段名获取或设置字段的值” 如果字段名不存在则会抛异常;如果设置的值类型和结构体字段类型不相同则会抛异常;需要类型完全一样,不允许隐式转换。比如字段类型是double,但是设置字段的值类型是int也会抛异常,必须显式传double;如果字段类型是std::string, 设置值类型是const char * 同样会报错;如果字段类型是int32_t, 设置值类型是uint_8也会抛异常,因为类型不相同。 -## Design -![](images/struct_pb_overview.jpeg) +设置字段值时也可以显式指定字段类型: +```cpp +t->set_field_value("name", "test"); +``` +这种方式则不要求设置值的类型和字段类型完全一样,只要能赋值成功即可。如果显式指定的字段类型不是实际的字段类型时也会抛异常。 -## Type Mapping -proto3 first, -see also [Protocol Buffers Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#scalar) +## benchmark +在benchmark monster场景下,struct_pb 性能比protobuf 更好,序列化速度是protobuf的2.4倍,反序列化是protobuf的3.4倍。详情可以自行运行struct_pack 中的benchmark复现结果。 -### Overview +## struct_pb 和 protobuf 类型映射 Scalar Value Types with no modifier (a.k.a **singular**) -> T Scalar Value Types with **optional** -> `std::optional ` @@ -38,33 +131,9 @@ any message type -> `std::optional ` enum -> enum class -oneof -> `std::variant ` - - -Note: - -- singular. - You cannot determine whether it was parsed from the wire. It will be serialized to the wire unless it is the default value. see also [Field Presence](https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md). -- optional. - You can check to see if the value was explicitly set. -- repeat. - In proto3, repeated fields of scalar numeric types use packed encoding by default. -- map. - The key of map can be any integral or string type except enum. - The value of map can be any type except another map. -- enum. - Every enum definition must contain a constant that maps to zero as its first element. - Enumerator constants must be in the range of a 32-bit integer. - During deserialization, unrecognized enum values will be preserved in the message -- oneof. - If you set an oneof field to the default value (such as setting an int32 oneof field to 0), the "case" of that oneof field will be set, and the value will be serialized on the wire. -- default value - - For numeric types, the default is 0. - - For enums, the default is the zero-valued enumerator. - - For strings, bytes, and repeated fields, the default is the zero-length value. - - For messages, the default is the language-specific null value. - -### Basic +oneof -> `std::variant <...>` + +### 映射表 | .proto Type | struct_pb Type | pb native C++ type | Notes | |-------------|-----------------------------------|--------------------|------------------------------------| | double | double | double | 8 bytes | @@ -73,98 +142,26 @@ Note: | int64 | int64 | int64 | | | uint32 | uint32 | uint32 | | | uint64 | uint64 | uint64 | | -| sint32 | int32 | int32 | ZigZag + variable-length encoding. | -| sint64 | int64 | int64 | | -| fixed32 | uint32 | uint32 | 4 bytes | -| fixed64 | uint64 | uint64 | 8 bytes | -| sfixed32 | int32 | int32 | 4 bytes,$2^{28}$ | -| sfixed64 | int64 | int64 | 8 bytes,$2^{56}$ | +| sint32 | sint32_t | int32 | ZigZag + variable-length encoding. | +| sint64 | sint6_t | int64 | | +| fixed32 | fixed32_t | uint32 | 4 bytes | +| fixed64 | fixed64_t | uint64 | 8 bytes | +| sfixed32 | sfixed32_t | int32 | 4 bytes,$2^{28}$ | +| sfixed64 | sfixed64_t | int64 | 8 bytes,$2^{56}$ | | bool | bool | bool | | | string | std::string | string | $len < 2^{32}$ | | bytes | std::string | string | | -| enum | enum class: int {} | enum: int {} | | -| oneof | std::variant | | | - -Note: - -- for enum, we use `enum class` instead of `enum` -- for oneof, we use `std::variant` with first template argument `std::monostate` - -## File Mapping -each `xxx.proto`file generates corresponding `xxx.struct_pb.h` and `xxx.struct_pb.cc` -all dependencies will convert to include corresponding headers. -``` -syntax = "proto3"; - -import "foo.proto"; - -message Bar { - Foo f = 2; -} -``` -mapping to cpp -```cpp -#include "foo.struct_pb.h" -struct Bar { -std::unique_ptr f; -}; - -``` -## protoc Plugin -```bash -protoc --plugin=path/to/protoc-gen-structpb --structpb_out=$OUT_PATH xxx.proto -``` -e.g. -```shell -protoc --plugin=/tmp/protoc-gen-structpb --structpb_out=. conformance.proto -``` -## TODO - --[ ] using value instead of `std::unique_ptr` when no circle dependencies - -for example, we convert the message `SearchResponse` to c++ struct `SearchResponse_v1` -``` -message SearchResponse { - Result result = 1; -} - -message Result { - string url = 1; -} -``` - -```cpp -struct SearchResponse_v1 { - std::unique_ptr result; -}; -``` - -we can optimize the pointer overhead if we can convert the message `SearchResponse` to c++ struct `SearchResponse_v2` -```cpp -struct SearchResponse_v2 { - Result result; -}; -``` - - -## Compatibility -see also - -- [Language Guide (proto3) -- Updating A Message Type](https://developers.google.com/protocol-buffers/docs/proto3#updating) -- [oneof compatibility](https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility_issues) -## Limitation - -- SGROUP(deprecated) and EGROUP(deprecated) are not support -- Reflection not support -- proto2 extension not support - -## Acknowledge - -- [Embedded Proto](https://embeddedproto.com/): an easy to use C++ Protocol Buffer implementation specifically suited for microcontrollers -- [protobuf-c](https://github.com/protobuf-c/protobuf-c): Protocol Buffers implementation in C -- [protozero](https://github.com/mapbox/protozero): Minimalist protocol buffer decoder and encoder in C++ -- [protopuf](https://github.com/PragmaTwice/protopuf): A little, highly templated, and protobuf-compatible serialization/deserialization header-only library written in C++20 - -## Reference - -- [Protocol Buffers Compiler Plugins](https://developers.google.com/protocol-buffers/docs/reference/other#plugins) +| enum | enum class: int {}/enum | enum: int {} | | +| oneof | std::variant<...> | | | + +## 约束 +- 目前还只支持proto3,不支持proto2; +- 目前还没支持反射; +- 还没支持unkonwn字段; +- struct_pb 结构体必须派生于base_impl + +## roadmap +- 支持proto2; +- 支持反射; +- 支持unkonwn字段; +- 去除struct_pb 结构体必须派生于base_impl的约束; diff --git a/website/docs/zh/struct_pb/struct_pb_quick_start.md b/website/docs/zh/struct_pb/struct_pb_quick_start.md deleted file mode 100644 index 28fdb4d3c..000000000 --- a/website/docs/zh/struct_pb/struct_pb_quick_start.md +++ /dev/null @@ -1,237 +0,0 @@ -# struct_pb Quick Start - -Note: if you are not familiar with the official c++ implement, -[Protocol Buffer Basics: C++](https://developers.google.com/protocol-buffers/docs/cpptutorial) -is a good material to learn. - -This tutorial provides a basic C++ programmer's introduction to work with struct_pb, -which is the protobuf compatible solution of the [yalantinglibs](https://github.com/alibaba/yalantinglibs). - -By walking through creating a simple example application, it shows you how to - -- Define message formats in a `.proto` file. (same as official protobuf document) -- Use the protocol buffer compiler (`protoc`) with `struct_pb` plugin. -- Use the `struct_pb` low-level API to write and read messages. - -## Defining Your Protocol Format - -we use proto3 here. - -``` -syntax = "proto3"; - -package tutorial; - -message Person { - string name = 1; - int32 id = 2; - string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - string number = 1; - PhoneType type = 2; - } - - repeated PhoneNumber phones = 4; -} - -message AddressBook { - repeated Person people = 1; -} - -``` - -## Compiling Your Protocol Buffers - -Now that you have a `.proto`, the next thing you need to do is generate the struct you'll need to -read and write `AddressBook` (and hence `Person` and `PhoneNumber`) messages. -To do this, you need to run the protocol buffer compiler `protoc` with `struct_pb` plugin `protoc-gen-struct_pb` on your `.proto`. - -```shell -protoc -I=$SRC_DIR --plugin=$PATH_TO_protoc-gen-struct_pb --struct_pb_out=$DST_DIR $SRC_DIR/addressbook.proto -``` -see [Generating source code](https://alibaba.github.io/yalantinglibs/en/struct_pb/struct_pb_generating_your_struct.html) for details. - -This generates the following files in your specified destination directory: - -- `addressbook.struct_pb.h`, the header which declares your generated struct. -- `addressbook.struct_pb.cc`, which contains the `struct_pb` low-level API implementation of your struct. - - -## The struct_pb low-level API - -Let's look at some generated code and see what struct and functions the compiler has created for you. -If you look in `addressbook.struct_pb.h`, you can see that you have a struct for each message you specified in `addressbook.proto`. - - -```cpp - -namespace tutorial { -struct Person; -struct AddressBook; -struct Person { - enum class PhoneType: int { - MOBILE = 0, - HOME = 1, - WORK = 2, - }; - struct PhoneNumber { - std::string number; // string, field number = 1 - ::tutorial::Person::PhoneType type; // enum, field number = 2 - }; - std::string name; // string, field number = 1 - int32_t id; // int32, field number = 2 - std::string email; // string, field number = 3 - std::vector<::tutorial::Person::PhoneNumber> phones; // message, field number = 4 -}; -struct AddressBook { - std::vector<::tutorial::Person> people; // message, field number = 1 -}; - -} // namespace tutorial -namespace struct_pb { -namespace internal { -// ::tutorial::Person::PhoneNumber -template<> -std::size_t get_needed_size<::tutorial::Person::PhoneNumber>(const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person::PhoneNumber>(char*, std::size_t, const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t); - -// ::tutorial::Person -template<> -std::size_t get_needed_size<::tutorial::Person>(const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person>(char*, std::size_t, const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t); - -// ::tutorial::AddressBook -template<> -std::size_t get_needed_size<::tutorial::AddressBook>(const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::AddressBook>(char*, std::size_t, const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -## The struct_pb high-level API - -We encapsulate the low-level API to make `struct_pb` easier to use. - -``` -/* - * High-Level API for struct_pb user - * If you need more fine-grained operations, encapsulate the internal API yourself. - */ -template, typename T> -Buffer serialize(const T& t, const UnknownFields& unknown_fields = {}) { - Buffer buffer; - auto size = struct_pb::internal::get_needed_size(t, unknown_fields); - buffer.resize(size); - struct_pb::internal::serialize_to(buffer.data(), buffer.size(), t, unknown_fields); - return buffer; -} -template -bool deserialize_to(T& t, UnknownFields& unknown_fields, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size(), unknown_fields); -} -template -bool deserialize_to(T& t, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size()); -} - -``` - -## Writing A Message - -```cpp -void prompt_for_address(tutorial::Person& person) { - std::cout << "==================================" << std::endl; - std::cout << " Add People " << std::endl; - std::cout << "==================================" << std::endl; - std::cout << "Enter person ID number: "; - std::cin >> person.id; - std::cin.ignore(256, '\n'); - std::cout << "Enter name: "; - std::getline(std::cin, person.name); - std::cout << "Enter email address (blank for none): "; - std::getline(std::cin, person.email); - while (true) { - std::cout << "Enter a phone number (or leave blank to finish): "; - tutorial::Person::PhoneNumber phone_number; - std::getline(std::cin, phone_number.number); - if (phone_number.number.empty()) { - break ; - } - std::cout << "Is this a mobile, home, or work phone? "; - std::string type; - std::getline(std::cin, type); - if (type == "mobile") { - phone_number.type = tutorial::Person::PhoneType::MOBILE; - } - else if (type == "home") { - phone_number.type = tutorial::Person::PhoneType::HOME; - } - else if (type == "work") { - phone_number.type = tutorial::Person::PhoneType::WORK; - } - else { - std::cout << "Unknown phone type: Using default." << std::endl; - } - person.phones.push_back(phone_number); - } -} -``` - -## Reading A Message - -```cpp -void list_people(const tutorial::AddressBook& address_book) { - std::cout << "==================================" << std::endl; - std::cout << " List People " << std::endl; - std::cout << "==================================" << std::endl; - for(const auto& person: address_book.people) { - std::cout << " Person ID: " << person.id << std::endl; - std::cout << " Name: " << person.name << std::endl; - if (!person.email.empty()) { - std::cout << "E-mail address: " << person.email << std::endl; - } - for(const auto& phone: person.phones) { - switch (phone.type) { - case tutorial::Person::PhoneType::MOBILE: - std::cout << "Mobile phone #: "; - break; - case tutorial::Person::PhoneType::HOME: - std::cout << " Home phone #: "; - break; - case tutorial::Person::PhoneType::WORK: - std::cout << " Work phone #: "; - break; - } - std::cout << phone.number << std::endl; - } - } -} -``` - -## the demo code - -- [code in yalantinglibs repo](https://github.com/alibaba/yalantinglibs/blob/main/src/struct_pb/examples/tutorial.cpp) -- [code in standalone repo](https://github.com/PikachuHyA/struct_pb_tutorial) diff --git a/website/docs/zh/struct_pb/struct_pb_supported_features.md b/website/docs/zh/struct_pb/struct_pb_supported_features.md deleted file mode 100644 index a47a96177..000000000 --- a/website/docs/zh/struct_pb/struct_pb_supported_features.md +++ /dev/null @@ -1,67 +0,0 @@ -# Supported Features - -## proto3 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | - -## proto2 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Extensions | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | From 9c7cffe0564a50ea8bd5d44eb6ee6347ff6fe20c Mon Sep 17 00:00:00 2001 From: yinghaoyu <42765754+yinghaoyu@users.noreply.github.com> Date: Wed, 29 May 2024 14:57:00 +0800 Subject: [PATCH 10/12] [easylog] fix last_tid (#686) --- include/ylt/easylog/appender.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/ylt/easylog/appender.hpp b/include/ylt/easylog/appender.hpp index 9118bd774..08f6772e2 100644 --- a/include/ylt/easylog/appender.hpp +++ b/include/ylt/easylog/appender.hpp @@ -145,6 +145,7 @@ class appender { auto [ptr, ec] = std::to_chars(buf + 1, buf + 21, tid); buf[22] = ']'; buf[23] = ' '; + last_tid = tid; last_len = ptr - buf; buf[last_len++] = ']'; buf[last_len++] = ' '; From 9a7b36ac0a4fcdf948d61cb8fd19b4078ebb18dd Mon Sep 17 00:00:00 2001 From: qicosmos Date: Fri, 31 May 2024 15:57:06 +0800 Subject: [PATCH 11/12] fix ssl option (#687) --- include/ylt/standalone/cinatra/coro_http_client.hpp | 7 ++++++- src/coro_http/examples/example.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/ylt/standalone/cinatra/coro_http_client.hpp b/include/ylt/standalone/cinatra/coro_http_client.hpp index ce76a3572..5f90831b6 100644 --- a/include/ylt/standalone/cinatra/coro_http_client.hpp +++ b/include/ylt/standalone/cinatra/coro_http_client.hpp @@ -294,7 +294,12 @@ class coro_http_client : public std::enable_shared_from_this { bool no_schema = !has_schema(uri); std::string append_uri; if (no_schema) { - append_uri.append("http://").append(uri); +#ifdef CINATRA_ENABLE_SSL + if (is_ssl_schema_) + append_uri.append("https://").append(uri); + else +#endif + append_uri.append("http://").append(uri); } auto [ok, u] = handle_uri(data, no_schema ? append_uri : uri); diff --git a/src/coro_http/examples/example.cpp b/src/coro_http/examples/example.cpp index 38f8d7062..3c8142e62 100644 --- a/src/coro_http/examples/example.cpp +++ b/src/coro_http/examples/example.cpp @@ -424,6 +424,17 @@ async_simple::coro::Lazy basic_usage() { co_await client3.connect("https://www.baidu.com"); result = co_await client3.async_get("/"); assert(result.status == 200); + + coro_http_client client4{}; + client4.set_ssl_schema(true); + result = client4.get("www.baidu.com"); + assert(result.status == 200); + + coro_http_client client5{}; + client5.set_ssl_schema(true); + co_await client5.connect("www.baidu.com"); + result = co_await client5.async_get("/"); + assert(result.status == 200); #endif } From 9d2966424e9d7f96b01f43b0be4d88ab008ea05b Mon Sep 17 00:00:00 2001 From: saipubw Date: Tue, 4 Jun 2024 16:27:30 +0800 Subject: [PATCH 12/12] [struct_pack] support 256 field (#688) --- include/ylt/struct_pack/foreach_macro.h | 138 +- include/ylt/struct_pack/reflection.hpp | 7807 ++++++++++++++++- src/struct_pack/tests/test_many_members.cpp | 278 + test.cpp | 14 + website/docs/en/coro_rpc/coro_rpc_server.md | 2 +- .../en/struct_pack/struct_pack_type_system.md | 2 +- website/docs/zh/coro_rpc/coro_rpc_server.md | 2 +- .../zh/struct_pack/struct_pack_type_system.md | 2 +- 8 files changed, 7953 insertions(+), 292 deletions(-) create mode 100644 src/struct_pack/tests/test_many_members.cpp create mode 100644 test.cpp diff --git a/include/ylt/struct_pack/foreach_macro.h b/include/ylt/struct_pack/foreach_macro.h index 87ba6dc04..dcbed8a2c 100644 --- a/include/ylt/struct_pack/foreach_macro.h +++ b/include/ylt/struct_pack/foreach_macro.h @@ -15,23 +15,10 @@ */ #pragma once // clang-format off -#define STRUCT_PACK_ARG_COUNT(...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_INTERNAL_ARG_COUNT(0, ##__VA_ARGS__,\ - 64, 63, 62, 61, 60, \ - 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ - 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ - 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ - 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ - 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ - 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +#define STRUCT_PACK_ARG_COUNT(...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_INTERNAL_ARG_COUNT(0, ##__VA_ARGS__,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) #define STRUCT_PACK_INTERNAL_ARG_COUNT(\ - _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ - _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ - _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ - _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \ - _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, \ - _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, \ - _60, _61, _62, _63, _64, N, ...) N +_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100,_101,_102,_103,_104,_105,_106,_107,_108,_109,_110,_111,_112,_113,_114,_115,_116,_117,_118,_119,_120,_121,_122,_123,_124, N, ...) N #define STRUCT_PACK_CONCAT_(l, r) l ## r #define STRUCT_PACK_CONCAT(l, r) STRUCT_PACK_CONCAT_(l, r) @@ -103,6 +90,66 @@ #define STRUCT_PACK_DOARG62(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG61(s,f,__VA_ARGS__)) s f(61,t) #define STRUCT_PACK_DOARG63(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG62(s,f,__VA_ARGS__)) s f(62,t) #define STRUCT_PACK_DOARG64(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG63(s,f,__VA_ARGS__)) s f(63,t) +#define STRUCT_PACK_DOARG65(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG64(s,f,__VA_ARGS__)) s f(64,t) +#define STRUCT_PACK_DOARG66(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG65(s,f,__VA_ARGS__)) s f(65,t) +#define STRUCT_PACK_DOARG67(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG66(s,f,__VA_ARGS__)) s f(66,t) +#define STRUCT_PACK_DOARG68(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG67(s,f,__VA_ARGS__)) s f(67,t) +#define STRUCT_PACK_DOARG69(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG68(s,f,__VA_ARGS__)) s f(68,t) +#define STRUCT_PACK_DOARG70(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG69(s,f,__VA_ARGS__)) s f(69,t) +#define STRUCT_PACK_DOARG71(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG70(s,f,__VA_ARGS__)) s f(70,t) +#define STRUCT_PACK_DOARG72(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG71(s,f,__VA_ARGS__)) s f(71,t) +#define STRUCT_PACK_DOARG73(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG72(s,f,__VA_ARGS__)) s f(72,t) +#define STRUCT_PACK_DOARG74(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG73(s,f,__VA_ARGS__)) s f(73,t) +#define STRUCT_PACK_DOARG75(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG74(s,f,__VA_ARGS__)) s f(74,t) +#define STRUCT_PACK_DOARG76(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG75(s,f,__VA_ARGS__)) s f(75,t) +#define STRUCT_PACK_DOARG77(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG76(s,f,__VA_ARGS__)) s f(76,t) +#define STRUCT_PACK_DOARG78(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG77(s,f,__VA_ARGS__)) s f(77,t) +#define STRUCT_PACK_DOARG79(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG78(s,f,__VA_ARGS__)) s f(78,t) +#define STRUCT_PACK_DOARG80(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG79(s,f,__VA_ARGS__)) s f(79,t) +#define STRUCT_PACK_DOARG81(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG80(s,f,__VA_ARGS__)) s f(80,t) +#define STRUCT_PACK_DOARG82(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG81(s,f,__VA_ARGS__)) s f(81,t) +#define STRUCT_PACK_DOARG83(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG82(s,f,__VA_ARGS__)) s f(82,t) +#define STRUCT_PACK_DOARG84(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG83(s,f,__VA_ARGS__)) s f(83,t) +#define STRUCT_PACK_DOARG85(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG84(s,f,__VA_ARGS__)) s f(84,t) +#define STRUCT_PACK_DOARG86(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG85(s,f,__VA_ARGS__)) s f(85,t) +#define STRUCT_PACK_DOARG87(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG86(s,f,__VA_ARGS__)) s f(86,t) +#define STRUCT_PACK_DOARG88(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG87(s,f,__VA_ARGS__)) s f(87,t) +#define STRUCT_PACK_DOARG89(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG88(s,f,__VA_ARGS__)) s f(88,t) +#define STRUCT_PACK_DOARG90(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG89(s,f,__VA_ARGS__)) s f(89,t) +#define STRUCT_PACK_DOARG91(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG90(s,f,__VA_ARGS__)) s f(90,t) +#define STRUCT_PACK_DOARG92(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG91(s,f,__VA_ARGS__)) s f(91,t) +#define STRUCT_PACK_DOARG93(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG92(s,f,__VA_ARGS__)) s f(92,t) +#define STRUCT_PACK_DOARG94(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG93(s,f,__VA_ARGS__)) s f(93,t) +#define STRUCT_PACK_DOARG95(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG94(s,f,__VA_ARGS__)) s f(94,t) +#define STRUCT_PACK_DOARG96(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG95(s,f,__VA_ARGS__)) s f(95,t) +#define STRUCT_PACK_DOARG97(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG96(s,f,__VA_ARGS__)) s f(96,t) +#define STRUCT_PACK_DOARG98(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG97(s,f,__VA_ARGS__)) s f(97,t) +#define STRUCT_PACK_DOARG99(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG98(s,f,__VA_ARGS__)) s f(98,t) +#define STRUCT_PACK_DOARG100(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG99(s,f,__VA_ARGS__)) s f(99,t) +#define STRUCT_PACK_DOARG101(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG100(s,f,__VA_ARGS__)) s f(100,t) +#define STRUCT_PACK_DOARG102(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG101(s,f,__VA_ARGS__)) s f(101,t) +#define STRUCT_PACK_DOARG103(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG102(s,f,__VA_ARGS__)) s f(102,t) +#define STRUCT_PACK_DOARG104(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG103(s,f,__VA_ARGS__)) s f(103,t) +#define STRUCT_PACK_DOARG105(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG104(s,f,__VA_ARGS__)) s f(104,t) +#define STRUCT_PACK_DOARG106(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG105(s,f,__VA_ARGS__)) s f(105,t) +#define STRUCT_PACK_DOARG107(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG106(s,f,__VA_ARGS__)) s f(106,t) +#define STRUCT_PACK_DOARG108(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG107(s,f,__VA_ARGS__)) s f(107,t) +#define STRUCT_PACK_DOARG109(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG108(s,f,__VA_ARGS__)) s f(108,t) +#define STRUCT_PACK_DOARG110(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG109(s,f,__VA_ARGS__)) s f(109,t) +#define STRUCT_PACK_DOARG111(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG110(s,f,__VA_ARGS__)) s f(110,t) +#define STRUCT_PACK_DOARG112(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG111(s,f,__VA_ARGS__)) s f(111,t) +#define STRUCT_PACK_DOARG113(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG112(s,f,__VA_ARGS__)) s f(112,t) +#define STRUCT_PACK_DOARG114(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG113(s,f,__VA_ARGS__)) s f(113,t) +#define STRUCT_PACK_DOARG115(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG114(s,f,__VA_ARGS__)) s f(114,t) +#define STRUCT_PACK_DOARG116(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG115(s,f,__VA_ARGS__)) s f(115,t) +#define STRUCT_PACK_DOARG117(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG116(s,f,__VA_ARGS__)) s f(116,t) +#define STRUCT_PACK_DOARG118(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG117(s,f,__VA_ARGS__)) s f(117,t) +#define STRUCT_PACK_DOARG119(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG118(s,f,__VA_ARGS__)) s f(118,t) +#define STRUCT_PACK_DOARG120(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG119(s,f,__VA_ARGS__)) s f(119,t) +#define STRUCT_PACK_DOARG121(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG120(s,f,__VA_ARGS__)) s f(120,t) +#define STRUCT_PACK_DOARG122(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG121(s,f,__VA_ARGS__)) s f(121,t) +#define STRUCT_PACK_DOARG123(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG122(s,f,__VA_ARGS__)) s f(122,t) +#define STRUCT_PACK_DOARG124(s,f,t,...) STRUCT_PACK_MARCO_EXPAND(STRUCT_PACK_DOARG123(s,f,__VA_ARGS__)) s f(123,t) #define STRUCT_PACK_MAKE_ARGS0(Type) #define STRUCT_PACK_MAKE_ARGS1(Type) Type @@ -169,7 +216,66 @@ #define STRUCT_PACK_MAKE_ARGS62(Type) STRUCT_PACK_MAKE_ARGS61(Type), Type #define STRUCT_PACK_MAKE_ARGS63(Type) STRUCT_PACK_MAKE_ARGS62(Type), Type #define STRUCT_PACK_MAKE_ARGS64(Type) STRUCT_PACK_MAKE_ARGS63(Type), Type - +#define STRUCT_PACK_MAKE_ARGS65(Type) STRUCT_PACK_MAKE_ARGS64(Type), Type +#define STRUCT_PACK_MAKE_ARGS66(Type) STRUCT_PACK_MAKE_ARGS65(Type), Type +#define STRUCT_PACK_MAKE_ARGS67(Type) STRUCT_PACK_MAKE_ARGS66(Type), Type +#define STRUCT_PACK_MAKE_ARGS68(Type) STRUCT_PACK_MAKE_ARGS67(Type), Type +#define STRUCT_PACK_MAKE_ARGS69(Type) STRUCT_PACK_MAKE_ARGS68(Type), Type +#define STRUCT_PACK_MAKE_ARGS70(Type) STRUCT_PACK_MAKE_ARGS69(Type), Type +#define STRUCT_PACK_MAKE_ARGS71(Type) STRUCT_PACK_MAKE_ARGS70(Type), Type +#define STRUCT_PACK_MAKE_ARGS72(Type) STRUCT_PACK_MAKE_ARGS71(Type), Type +#define STRUCT_PACK_MAKE_ARGS73(Type) STRUCT_PACK_MAKE_ARGS72(Type), Type +#define STRUCT_PACK_MAKE_ARGS74(Type) STRUCT_PACK_MAKE_ARGS73(Type), Type +#define STRUCT_PACK_MAKE_ARGS75(Type) STRUCT_PACK_MAKE_ARGS74(Type), Type +#define STRUCT_PACK_MAKE_ARGS76(Type) STRUCT_PACK_MAKE_ARGS75(Type), Type +#define STRUCT_PACK_MAKE_ARGS77(Type) STRUCT_PACK_MAKE_ARGS76(Type), Type +#define STRUCT_PACK_MAKE_ARGS78(Type) STRUCT_PACK_MAKE_ARGS77(Type), Type +#define STRUCT_PACK_MAKE_ARGS79(Type) STRUCT_PACK_MAKE_ARGS78(Type), Type +#define STRUCT_PACK_MAKE_ARGS80(Type) STRUCT_PACK_MAKE_ARGS79(Type), Type +#define STRUCT_PACK_MAKE_ARGS81(Type) STRUCT_PACK_MAKE_ARGS80(Type), Type +#define STRUCT_PACK_MAKE_ARGS82(Type) STRUCT_PACK_MAKE_ARGS81(Type), Type +#define STRUCT_PACK_MAKE_ARGS83(Type) STRUCT_PACK_MAKE_ARGS82(Type), Type +#define STRUCT_PACK_MAKE_ARGS84(Type) STRUCT_PACK_MAKE_ARGS83(Type), Type +#define STRUCT_PACK_MAKE_ARGS85(Type) STRUCT_PACK_MAKE_ARGS84(Type), Type +#define STRUCT_PACK_MAKE_ARGS86(Type) STRUCT_PACK_MAKE_ARGS85(Type), Type +#define STRUCT_PACK_MAKE_ARGS87(Type) STRUCT_PACK_MAKE_ARGS86(Type), Type +#define STRUCT_PACK_MAKE_ARGS88(Type) STRUCT_PACK_MAKE_ARGS87(Type), Type +#define STRUCT_PACK_MAKE_ARGS89(Type) STRUCT_PACK_MAKE_ARGS88(Type), Type +#define STRUCT_PACK_MAKE_ARGS90(Type) STRUCT_PACK_MAKE_ARGS89(Type), Type +#define STRUCT_PACK_MAKE_ARGS91(Type) STRUCT_PACK_MAKE_ARGS90(Type), Type +#define STRUCT_PACK_MAKE_ARGS92(Type) STRUCT_PACK_MAKE_ARGS91(Type), Type +#define STRUCT_PACK_MAKE_ARGS93(Type) STRUCT_PACK_MAKE_ARGS92(Type), Type +#define STRUCT_PACK_MAKE_ARGS94(Type) STRUCT_PACK_MAKE_ARGS93(Type), Type +#define STRUCT_PACK_MAKE_ARGS95(Type) STRUCT_PACK_MAKE_ARGS94(Type), Type +#define STRUCT_PACK_MAKE_ARGS96(Type) STRUCT_PACK_MAKE_ARGS95(Type), Type +#define STRUCT_PACK_MAKE_ARGS97(Type) STRUCT_PACK_MAKE_ARGS96(Type), Type +#define STRUCT_PACK_MAKE_ARGS98(Type) STRUCT_PACK_MAKE_ARGS97(Type), Type +#define STRUCT_PACK_MAKE_ARGS99(Type) STRUCT_PACK_MAKE_ARGS98(Type), Type +#define STRUCT_PACK_MAKE_ARGS100(Type) STRUCT_PACK_MAKE_ARGS99(Type), Type +#define STRUCT_PACK_MAKE_ARGS101(Type) STRUCT_PACK_MAKE_ARGS100(Type), Type +#define STRUCT_PACK_MAKE_ARGS102(Type) STRUCT_PACK_MAKE_ARGS101(Type), Type +#define STRUCT_PACK_MAKE_ARGS103(Type) STRUCT_PACK_MAKE_ARGS102(Type), Type +#define STRUCT_PACK_MAKE_ARGS104(Type) STRUCT_PACK_MAKE_ARGS103(Type), Type +#define STRUCT_PACK_MAKE_ARGS105(Type) STRUCT_PACK_MAKE_ARGS104(Type), Type +#define STRUCT_PACK_MAKE_ARGS106(Type) STRUCT_PACK_MAKE_ARGS105(Type), Type +#define STRUCT_PACK_MAKE_ARGS107(Type) STRUCT_PACK_MAKE_ARGS106(Type), Type +#define STRUCT_PACK_MAKE_ARGS108(Type) STRUCT_PACK_MAKE_ARGS107(Type), Type +#define STRUCT_PACK_MAKE_ARGS109(Type) STRUCT_PACK_MAKE_ARGS108(Type), Type +#define STRUCT_PACK_MAKE_ARGS110(Type) STRUCT_PACK_MAKE_ARGS109(Type), Type +#define STRUCT_PACK_MAKE_ARGS111(Type) STRUCT_PACK_MAKE_ARGS110(Type), Type +#define STRUCT_PACK_MAKE_ARGS112(Type) STRUCT_PACK_MAKE_ARGS111(Type), Type +#define STRUCT_PACK_MAKE_ARGS113(Type) STRUCT_PACK_MAKE_ARGS112(Type), Type +#define STRUCT_PACK_MAKE_ARGS114(Type) STRUCT_PACK_MAKE_ARGS113(Type), Type +#define STRUCT_PACK_MAKE_ARGS115(Type) STRUCT_PACK_MAKE_ARGS114(Type), Type +#define STRUCT_PACK_MAKE_ARGS116(Type) STRUCT_PACK_MAKE_ARGS115(Type), Type +#define STRUCT_PACK_MAKE_ARGS117(Type) STRUCT_PACK_MAKE_ARGS116(Type), Type +#define STRUCT_PACK_MAKE_ARGS118(Type) STRUCT_PACK_MAKE_ARGS117(Type), Type +#define STRUCT_PACK_MAKE_ARGS119(Type) STRUCT_PACK_MAKE_ARGS118(Type), Type +#define STRUCT_PACK_MAKE_ARGS120(Type) STRUCT_PACK_MAKE_ARGS119(Type), Type +#define STRUCT_PACK_MAKE_ARGS121(Type) STRUCT_PACK_MAKE_ARGS120(Type), Type +#define STRUCT_PACK_MAKE_ARGS122(Type) STRUCT_PACK_MAKE_ARGS121(Type), Type +#define STRUCT_PACK_MAKE_ARGS123(Type) STRUCT_PACK_MAKE_ARGS122(Type), Type +#define STRUCT_PACK_MAKE_ARGS124(Type) STRUCT_PACK_MAKE_ARGS123(Type), Type #define STRUCT_PACK_MAKE_ARGS(Type,Count) \ STRUCT_PACK_CONCAT(STRUCT_PACK_MAKE_ARGS,Count)(Type) diff --git a/include/ylt/struct_pack/reflection.hpp b/include/ylt/struct_pack/reflection.hpp index e20346b6b..6aa0da1d1 100644 --- a/include/ylt/struct_pack/reflection.hpp +++ b/include/ylt/struct_pack/reflection.hpp @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +// clang-format off #pragma once #include #include @@ -189,7 +190,6 @@ constexpr bool can_shrink_to_fit = can_shrink_to_fit_impl::value; template struct compatible; -// clang-format off namespace detail { #if __cpp_concepts >= 201907L @@ -1011,7 +1011,7 @@ constexpr bool trivially_copyable_container = } } - constexpr static auto MaxVisitMembers = 64; + constexpr static auto MaxVisitMembers = 256; template constexpr decltype(auto) STRUCT_PACK_INLINE visit_members_by_user_defined_refl(Object &&object, @@ -1032,143 +1032,1723 @@ constexpr bool trivially_copyable_container = return visit_members_by_structure_binding(object,visitor); } } + template + constexpr decltype(auto) STRUCT_PACK_INLINE + visit_members_by_user_defined_refl(Object &&o, Visitor &&visitor) { + using type = remove_cvref_t; + constexpr auto Count = decltype(STRUCT_PACK_FIELD_COUNT(o))::value; - template - constexpr decltype(auto) STRUCT_PACK_INLINE visit_members_by_user_defined_refl(Object &&object, - Visitor &&visitor) { - using type = remove_cvref_t; - constexpr auto Count = decltype(STRUCT_PACK_FIELD_COUNT(object))::value; - static_assert(Count <= MaxVisitMembers, "exceed max visit members"); if constexpr (Count >= 0) { - if constexpr (Count==1) { return visitor(STRUCT_PACK_GET_0(object)); + if constexpr (Count == 1) { + return visitor(_SPG0(o)); + } + else if constexpr (Count == 2) { + return visitor(_SPG0(o), _SPG1(o)); + } + else if constexpr (Count == 3) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o)); + } + else if constexpr (Count == 4) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o)); + } + else if constexpr (Count == 5) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o)); + } + else if constexpr (Count == 6) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o)); + } + else if constexpr (Count == 7) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o)); + } + else if constexpr (Count == 8) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o)); + } + else if constexpr (Count == 9) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o)); + } + else if constexpr (Count == 10) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o)); + } + else if constexpr (Count == 11) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o)); + } + else if constexpr (Count == 12) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o)); + } + else if constexpr (Count == 13) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o)); + } + else if constexpr (Count == 14) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o)); + } + else if constexpr (Count == 15) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o)); + } + else if constexpr (Count == 16) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o)); + } + else if constexpr (Count == 17) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o)); + } + else if constexpr (Count == 18) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o)); + } + else if constexpr (Count == 19) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o)); + } + else if constexpr (Count == 20) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o)); + } + else if constexpr (Count == 21) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o)); + } + else if constexpr (Count == 22) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o)); + } + else if constexpr (Count == 23) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o)); + } + else if constexpr (Count == 24) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o)); + } + else if constexpr (Count == 25) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o)); + } + else if constexpr (Count == 26) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o)); + } + else if constexpr (Count == 27) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o)); + } + else if constexpr (Count == 28) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o)); + } + else if constexpr (Count == 29) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o)); + } + else if constexpr (Count == 30) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o)); + } + else if constexpr (Count == 31) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o)); + } + else if constexpr (Count == 32) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o)); + } + else if constexpr (Count == 33) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o)); + } + else if constexpr (Count == 34) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o)); + } + else if constexpr (Count == 35) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o)); + } + else if constexpr (Count == 36) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o)); + } + else if constexpr (Count == 37) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o)); + } + else if constexpr (Count == 38) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o)); + } + else if constexpr (Count == 39) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o)); + } + else if constexpr (Count == 40) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o)); + } + else if constexpr (Count == 41) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o)); + } + else if constexpr (Count == 42) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o)); + } + else if constexpr (Count == 43) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), + _SPG40(o), _SPG41(o), _SPG42(o)); + } + else if constexpr (Count == 44) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), + _SPG40(o), _SPG41(o), _SPG42(o), _SPG43(o)); + } + else if constexpr (Count == 45) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), + _SPG40(o), _SPG41(o), _SPG42(o), _SPG43(o), _SPG44(o)); + } + else if constexpr (Count == 46) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o)); + } + else if constexpr (Count == 47) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o)); + } + else if constexpr (Count == 48) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o)); + } + else if constexpr (Count == 49) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), + _SPG40(o), _SPG41(o), _SPG42(o), _SPG43(o), _SPG44(o), + _SPG45(o), _SPG46(o), _SPG47(o), _SPG48(o)); + } + else if constexpr (Count == 50) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), + _SPG40(o), _SPG41(o), _SPG42(o), _SPG43(o), _SPG44(o), + _SPG45(o), _SPG46(o), _SPG47(o), _SPG48(o), _SPG49(o)); + } + else if constexpr (Count == 51) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o)); + } + else if constexpr (Count == 52) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o)); + } + else if constexpr (Count == 53) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o)); + } + else if constexpr (Count == 54) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o)); + } + else if constexpr (Count == 55) { + return visitor(_SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), + _SPG5(o), _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), + _SPG10(o), _SPG11(o), _SPG12(o), _SPG13(o), _SPG14(o), + _SPG15(o), _SPG16(o), _SPG17(o), _SPG18(o), _SPG19(o), + _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), _SPG24(o), + _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), + _SPG35(o), _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), + _SPG40(o), _SPG41(o), _SPG42(o), _SPG43(o), _SPG44(o), + _SPG45(o), _SPG46(o), _SPG47(o), _SPG48(o), _SPG49(o), + _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), _SPG54(o)); + } + else if constexpr (Count == 56) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o)); + } + else if constexpr (Count == 57) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o)); + } + else if constexpr (Count == 58) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o)); + } + else if constexpr (Count == 59) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o)); } - else if constexpr (Count==2) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object)); + else if constexpr (Count == 60) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o)); } - else if constexpr (Count==3) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object)); + else if constexpr (Count == 61) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o)); } - else if constexpr (Count==4) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object)); + else if constexpr (Count == 62) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o)); } - else if constexpr (Count==5) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object)); + else if constexpr (Count == 63) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o)); } - else if constexpr (Count==6) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object)); + else if constexpr (Count == 64) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o)); } - else if constexpr (Count==7) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object)); + else if constexpr (Count == 65) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o)); } - else if constexpr (Count==8) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object)); + else if constexpr (Count == 66) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o)); } - else if constexpr (Count==9) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object)); + else if constexpr (Count == 67) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o)); } - else if constexpr (Count==10) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object)); + else if constexpr (Count == 68) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o)); } - else if constexpr (Count==11) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object)); + else if constexpr (Count == 69) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o)); } - else if constexpr (Count==12) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object)); + else if constexpr (Count == 70) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o)); } - else if constexpr (Count==13) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object)); + else if constexpr (Count == 71) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o)); } - else if constexpr (Count==14) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object)); + else if constexpr (Count == 72) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o)); } - else if constexpr (Count==15) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object)); + else if constexpr (Count == 73) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o)); } - else if constexpr (Count==16) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object)); + else if constexpr (Count == 74) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o)); } - else if constexpr (Count==17) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object)); + else if constexpr (Count == 75) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o)); } - else if constexpr (Count==18) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object)); + else if constexpr (Count == 76) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o)); } - else if constexpr (Count==19) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object)); + else if constexpr (Count == 77) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o)); } - else if constexpr (Count==20) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object)); + else if constexpr (Count == 78) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o)); } - else if constexpr (Count==21) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object)); + else if constexpr (Count == 79) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o)); } - else if constexpr (Count==22) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object)); + else if constexpr (Count == 80) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o)); } - else if constexpr (Count==23) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object)); + else if constexpr (Count == 81) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o)); } - else if constexpr (Count==24) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object)); + else if constexpr (Count == 82) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o)); } - else if constexpr (Count==25) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object)); + else if constexpr (Count == 83) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o)); } - else if constexpr (Count==26) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object)); + else if constexpr (Count == 84) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o)); } - else if constexpr (Count==27) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object)); + else if constexpr (Count == 85) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o)); } - else if constexpr (Count==28) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object)); + else if constexpr (Count == 86) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o)); } - else if constexpr (Count==29) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object)); + else if constexpr (Count == 87) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o)); } - else if constexpr (Count==30) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object)); + else if constexpr (Count == 88) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o)); } - else if constexpr (Count==31) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object)); + else if constexpr (Count == 89) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o)); } - else if constexpr (Count==32) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object)); + else if constexpr (Count == 90) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o)); } - else if constexpr (Count==33) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object)); + else if constexpr (Count == 91) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o)); } - else if constexpr (Count==34) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object)); + else if constexpr (Count == 92) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o)); } - else if constexpr (Count==35) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object)); + else if constexpr (Count == 93) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o)); } - else if constexpr (Count==36) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object)); + else if constexpr (Count == 94) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o)); } - else if constexpr (Count==37) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object)); + else if constexpr (Count == 95) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o)); } - else if constexpr (Count==38) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object)); + else if constexpr (Count == 96) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o)); } - else if constexpr (Count==39) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object)); + else if constexpr (Count == 97) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o)); } - else if constexpr (Count==40) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object)); + else if constexpr (Count == 98) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o)); } - else if constexpr (Count==41) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object)); + else if constexpr (Count == 99) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o)); } - else if constexpr (Count==42) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object)); + else if constexpr (Count == 100) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o)); } - else if constexpr (Count==43) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object)); + else if constexpr (Count == 101) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o)); } - else if constexpr (Count==44) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object)); + else if constexpr (Count == 102) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o)); } - else if constexpr (Count==45) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object)); + else if constexpr (Count == 103) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o)); } - else if constexpr (Count==46) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object)); + else if constexpr (Count == 104) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o)); } - else if constexpr (Count==47) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object)); + else if constexpr (Count == 105) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o)); } - else if constexpr (Count==48) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object)); + else if constexpr (Count == 106) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o)); } - else if constexpr (Count==49) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object)); + else if constexpr (Count == 107) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o)); } - else if constexpr (Count==50) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object)); + else if constexpr (Count == 108) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o)); } - else if constexpr (Count==51) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object)); + else if constexpr (Count == 109) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o)); } - else if constexpr (Count==52) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object)); + else if constexpr (Count == 110) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o)); } - else if constexpr (Count==53) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object)); + else if constexpr (Count == 111) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o)); } - else if constexpr (Count==54) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object)); + else if constexpr (Count == 112) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o)); } - else if constexpr (Count==55) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object)); + else if constexpr (Count == 113) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o)); } - else if constexpr (Count==56) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object)); + else if constexpr (Count == 114) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o)); } - else if constexpr (Count==57) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object)); + else if constexpr (Count == 115) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o)); } - else if constexpr (Count==58) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object),STRUCT_PACK_GET_57(object)); + else if constexpr (Count == 116) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o)); } - else if constexpr (Count==59) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object),STRUCT_PACK_GET_57(object),STRUCT_PACK_GET_58(object)); + else if constexpr (Count == 117) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o)); } - else if constexpr (Count==60) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object),STRUCT_PACK_GET_57(object),STRUCT_PACK_GET_58(object),STRUCT_PACK_GET_59(object)); + else if constexpr (Count == 118) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o), + _SPG117(o)); } - else if constexpr (Count==61) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object),STRUCT_PACK_GET_57(object),STRUCT_PACK_GET_58(object),STRUCT_PACK_GET_59(object),STRUCT_PACK_GET_60(object)); + else if constexpr (Count == 119) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o), + _SPG117(o), _SPG118(o)); } - else if constexpr (Count==62) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object),STRUCT_PACK_GET_57(object),STRUCT_PACK_GET_58(object),STRUCT_PACK_GET_59(object),STRUCT_PACK_GET_60(object),STRUCT_PACK_GET_61(object)); + else if constexpr (Count == 120) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o), + _SPG117(o), _SPG118(o), _SPG119(o)); } - else if constexpr (Count==63) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object),STRUCT_PACK_GET_57(object),STRUCT_PACK_GET_58(object),STRUCT_PACK_GET_59(object),STRUCT_PACK_GET_60(object),STRUCT_PACK_GET_61(object),STRUCT_PACK_GET_62(object)); + else if constexpr (Count == 121) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o), + _SPG117(o), _SPG118(o), _SPG119(o), _SPG120(o)); + } + else if constexpr (Count == 122) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o), + _SPG117(o), _SPG118(o), _SPG119(o), _SPG120(o), _SPG121(o)); + } + else if constexpr (Count == 123) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o), + _SPG117(o), _SPG118(o), _SPG119(o), _SPG120(o), _SPG121(o), + _SPG122(o)); + } + else if constexpr (Count == 124) { + return visitor( + _SPG0(o), _SPG1(o), _SPG2(o), _SPG3(o), _SPG4(o), _SPG5(o), + _SPG6(o), _SPG7(o), _SPG8(o), _SPG9(o), _SPG10(o), _SPG11(o), + _SPG12(o), _SPG13(o), _SPG14(o), _SPG15(o), _SPG16(o), _SPG17(o), + _SPG18(o), _SPG19(o), _SPG20(o), _SPG21(o), _SPG22(o), _SPG23(o), + _SPG24(o), _SPG25(o), _SPG26(o), _SPG27(o), _SPG28(o), _SPG29(o), + _SPG30(o), _SPG31(o), _SPG32(o), _SPG33(o), _SPG34(o), _SPG35(o), + _SPG36(o), _SPG37(o), _SPG38(o), _SPG39(o), _SPG40(o), _SPG41(o), + _SPG42(o), _SPG43(o), _SPG44(o), _SPG45(o), _SPG46(o), _SPG47(o), + _SPG48(o), _SPG49(o), _SPG50(o), _SPG51(o), _SPG52(o), _SPG53(o), + _SPG54(o), _SPG55(o), _SPG56(o), _SPG57(o), _SPG58(o), _SPG59(o), + _SPG60(o), _SPG61(o), _SPG62(o), _SPG63(o), _SPG64(o), _SPG65(o), + _SPG66(o), _SPG67(o), _SPG68(o), _SPG69(o), _SPG70(o), _SPG71(o), + _SPG72(o), _SPG73(o), _SPG74(o), _SPG75(o), _SPG76(o), _SPG77(o), + _SPG78(o), _SPG79(o), _SPG80(o), _SPG81(o), _SPG82(o), _SPG83(o), + _SPG84(o), _SPG85(o), _SPG86(o), _SPG87(o), _SPG88(o), _SPG89(o), + _SPG90(o), _SPG91(o), _SPG92(o), _SPG93(o), _SPG94(o), _SPG95(o), + _SPG96(o), _SPG97(o), _SPG98(o), _SPG99(o), _SPG100(o), _SPG101(o), + _SPG102(o), _SPG103(o), _SPG104(o), _SPG105(o), _SPG106(o), + _SPG107(o), _SPG108(o), _SPG109(o), _SPG110(o), _SPG111(o), + _SPG112(o), _SPG113(o), _SPG114(o), _SPG115(o), _SPG116(o), + _SPG117(o), _SPG118(o), _SPG119(o), _SPG120(o), _SPG121(o), + _SPG122(o), _SPG123(o)); } - else if constexpr (Count==64) { return visitor(STRUCT_PACK_GET_0(object),STRUCT_PACK_GET_1(object),STRUCT_PACK_GET_2(object),STRUCT_PACK_GET_3(object),STRUCT_PACK_GET_4(object),STRUCT_PACK_GET_5(object),STRUCT_PACK_GET_6(object),STRUCT_PACK_GET_7(object),STRUCT_PACK_GET_8(object),STRUCT_PACK_GET_9(object),STRUCT_PACK_GET_10(object),STRUCT_PACK_GET_11(object),STRUCT_PACK_GET_12(object),STRUCT_PACK_GET_13(object),STRUCT_PACK_GET_14(object),STRUCT_PACK_GET_15(object),STRUCT_PACK_GET_16(object),STRUCT_PACK_GET_17(object),STRUCT_PACK_GET_18(object),STRUCT_PACK_GET_19(object),STRUCT_PACK_GET_20(object),STRUCT_PACK_GET_21(object),STRUCT_PACK_GET_22(object),STRUCT_PACK_GET_23(object),STRUCT_PACK_GET_24(object),STRUCT_PACK_GET_25(object),STRUCT_PACK_GET_26(object),STRUCT_PACK_GET_27(object),STRUCT_PACK_GET_28(object),STRUCT_PACK_GET_29(object),STRUCT_PACK_GET_30(object),STRUCT_PACK_GET_31(object),STRUCT_PACK_GET_32(object),STRUCT_PACK_GET_33(object),STRUCT_PACK_GET_34(object),STRUCT_PACK_GET_35(object),STRUCT_PACK_GET_36(object),STRUCT_PACK_GET_37(object),STRUCT_PACK_GET_38(object),STRUCT_PACK_GET_39(object),STRUCT_PACK_GET_40(object),STRUCT_PACK_GET_41(object),STRUCT_PACK_GET_42(object),STRUCT_PACK_GET_43(object),STRUCT_PACK_GET_44(object),STRUCT_PACK_GET_45(object),STRUCT_PACK_GET_46(object),STRUCT_PACK_GET_47(object),STRUCT_PACK_GET_48(object),STRUCT_PACK_GET_49(object),STRUCT_PACK_GET_50(object),STRUCT_PACK_GET_51(object),STRUCT_PACK_GET_52(object),STRUCT_PACK_GET_53(object),STRUCT_PACK_GET_54(object),STRUCT_PACK_GET_55(object),STRUCT_PACK_GET_56(object),STRUCT_PACK_GET_57(object),STRUCT_PACK_GET_58(object),STRUCT_PACK_GET_59(object),STRUCT_PACK_GET_60(object),STRUCT_PACK_GET_61(object),STRUCT_PACK_GET_62(object),STRUCT_PACK_GET_63(object)); - } } else { static_assert(!sizeof(type), "empty struct/class is not allowed!"); @@ -1725,195 +3305,5879 @@ constexpr bool trivially_copyable_container = a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, a62, a63, a64); } - } -// clang-format off -template -constexpr decltype(auto) STRUCT_PACK_INLINE template_switch(std::size_t index, - Args &&...args) { - switch (index) { - case 0: - return Func::template run<0>(std::forward(args)...); - case 1: - return Func::template run<1>(std::forward(args)...); - case 2: - return Func::template run<2>(std::forward(args)...); - case 3: - return Func::template run<3>(std::forward(args)...); - case 4: - return Func::template run<4>(std::forward(args)...); - case 5: - return Func::template run<5>(std::forward(args)...); - case 6: - return Func::template run<6>(std::forward(args)...); - case 7: - return Func::template run<7>(std::forward(args)...); - case 8: - return Func::template run<8>(std::forward(args)...); - case 9: - return Func::template run<9>(std::forward(args)...); - case 10: - return Func::template run<10>(std::forward(args)...); - case 11: - return Func::template run<11>(std::forward(args)...); - case 12: - return Func::template run<12>(std::forward(args)...); - case 13: - return Func::template run<13>(std::forward(args)...); - case 14: - return Func::template run<14>(std::forward(args)...); - case 15: - return Func::template run<15>(std::forward(args)...); - case 16: - return Func::template run<16>(std::forward(args)...); - case 17: - return Func::template run<17>(std::forward(args)...); - case 18: - return Func::template run<18>(std::forward(args)...); - case 19: - return Func::template run<19>(std::forward(args)...); - case 20: - return Func::template run<20>(std::forward(args)...); - case 21: - return Func::template run<21>(std::forward(args)...); - case 22: - return Func::template run<22>(std::forward(args)...); - case 23: - return Func::template run<23>(std::forward(args)...); - case 24: - return Func::template run<24>(std::forward(args)...); - case 25: - return Func::template run<25>(std::forward(args)...); - case 26: - return Func::template run<26>(std::forward(args)...); - case 27: - return Func::template run<27>(std::forward(args)...); - case 28: - return Func::template run<28>(std::forward(args)...); - case 29: - return Func::template run<29>(std::forward(args)...); - case 30: - return Func::template run<30>(std::forward(args)...); - case 31: - return Func::template run<31>(std::forward(args)...); - case 32: - return Func::template run<32>(std::forward(args)...); - case 33: - return Func::template run<33>(std::forward(args)...); - case 34: - return Func::template run<34>(std::forward(args)...); - case 35: - return Func::template run<35>(std::forward(args)...); - case 36: - return Func::template run<36>(std::forward(args)...); - case 37: - return Func::template run<37>(std::forward(args)...); - case 38: - return Func::template run<38>(std::forward(args)...); - case 39: - return Func::template run<39>(std::forward(args)...); - case 40: - return Func::template run<40>(std::forward(args)...); - case 41: - return Func::template run<41>(std::forward(args)...); - case 42: - return Func::template run<42>(std::forward(args)...); - case 43: - return Func::template run<43>(std::forward(args)...); - case 44: - return Func::template run<44>(std::forward(args)...); - case 45: - return Func::template run<45>(std::forward(args)...); - case 46: - return Func::template run<46>(std::forward(args)...); - case 47: - return Func::template run<47>(std::forward(args)...); - case 48: - return Func::template run<48>(std::forward(args)...); - case 49: - return Func::template run<49>(std::forward(args)...); - case 50: - return Func::template run<50>(std::forward(args)...); - case 51: - return Func::template run<51>(std::forward(args)...); - case 52: - return Func::template run<52>(std::forward(args)...); - case 53: - return Func::template run<53>(std::forward(args)...); - case 54: - return Func::template run<54>(std::forward(args)...); - case 55: - return Func::template run<55>(std::forward(args)...); - case 56: - return Func::template run<56>(std::forward(args)...); - case 57: - return Func::template run<57>(std::forward(args)...); - case 58: - return Func::template run<58>(std::forward(args)...); - case 59: - return Func::template run<59>(std::forward(args)...); - case 60: - return Func::template run<60>(std::forward(args)...); - case 61: - return Func::template run<61>(std::forward(args)...); - case 62: - return Func::template run<62>(std::forward(args)...); - case 63: - return Func::template run<63>(std::forward(args)...); - case 64: - return Func::template run<64>(std::forward(args)...); - case 65: - return Func::template run<65>(std::forward(args)...); - case 66: - return Func::template run<66>(std::forward(args)...); - case 67: - return Func::template run<67>(std::forward(args)...); - case 68: - return Func::template run<68>(std::forward(args)...); - case 69: - return Func::template run<69>(std::forward(args)...); - case 70: - return Func::template run<70>(std::forward(args)...); - case 71: - return Func::template run<71>(std::forward(args)...); - case 72: - return Func::template run<72>(std::forward(args)...); - case 73: - return Func::template run<73>(std::forward(args)...); - case 74: - return Func::template run<74>(std::forward(args)...); - case 75: - return Func::template run<75>(std::forward(args)...); - case 76: - return Func::template run<76>(std::forward(args)...); - case 77: - return Func::template run<77>(std::forward(args)...); - case 78: - return Func::template run<78>(std::forward(args)...); - case 79: - return Func::template run<79>(std::forward(args)...); - case 80: - return Func::template run<80>(std::forward(args)...); - case 81: - return Func::template run<81>(std::forward(args)...); - case 82: - return Func::template run<82>(std::forward(args)...); - case 83: - return Func::template run<83>(std::forward(args)...); - case 84: - return Func::template run<84>(std::forward(args)...); - case 85: - return Func::template run<85>(std::forward(args)...); - case 86: - return Func::template run<86>(std::forward(args)...); - case 87: - return Func::template run<87>(std::forward(args)...); - case 88: - return Func::template run<88>(std::forward(args)...); - case 89: - return Func::template run<89>(std::forward(args)...); - case 90: - return Func::template run<90>(std::forward(args)...); - case 91: + else if constexpr (Count == 65) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65); + } + else if constexpr (Count == 66) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66); + } + else if constexpr (Count == 67) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67); + } + else if constexpr (Count == 68) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68); + } + else if constexpr (Count == 69) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69); + } + else if constexpr (Count == 70) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70); + } + else if constexpr (Count == 71) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71); + } + else if constexpr (Count == 72) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72); + } + else if constexpr (Count == 73) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73); + } + else if constexpr (Count == 74) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74); + } + else if constexpr (Count == 75) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75); + } + else if constexpr (Count == 76) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76); + } + else if constexpr (Count == 77) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77); + } + else if constexpr (Count == 78) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78); + } + else if constexpr (Count == 79) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79); + } + else if constexpr (Count == 80) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80); + } + else if constexpr (Count == 81) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81); + } + else if constexpr (Count == 82) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82); + } + else if constexpr (Count == 83) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83); + } + else if constexpr (Count == 84) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84); + } + else if constexpr (Count == 85) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85); + } + else if constexpr (Count == 86) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86); + } + else if constexpr (Count == 87) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87); + } + else if constexpr (Count == 88) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88); + } + else if constexpr (Count == 89) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89); + } + else if constexpr (Count == 90) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90); + } + else if constexpr (Count == 91) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91); + } + else if constexpr (Count == 92) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92); + } + else if constexpr (Count == 93) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93); + } + else if constexpr (Count == 94) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94); + } + else if constexpr (Count == 95) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95); + } + else if constexpr (Count == 96) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96); + } + else if constexpr (Count == 97) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97); + } + else if constexpr (Count == 98) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98); + } + else if constexpr (Count == 99) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99); + } + else if constexpr (Count == 100) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100); + } + else if constexpr (Count == 101) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101); + } + else if constexpr (Count == 102) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102); + } + else if constexpr (Count == 103) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103); + } + else if constexpr (Count == 104) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104); + } + else if constexpr (Count == 105) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, + a105] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105); + } + else if constexpr (Count == 106) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106); + } + else if constexpr (Count == 107) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107); + } + else if constexpr (Count == 108) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108); + } + else if constexpr (Count == 109) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109); + } + else if constexpr (Count == 110) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110); + } + else if constexpr (Count == 111) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111); + } + else if constexpr (Count == 112) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112); + } + else if constexpr (Count == 113) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113); + } + else if constexpr (Count == 114) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114); + } + else if constexpr (Count == 115) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115); + } + else if constexpr (Count == 116) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, + a116] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116); + } + else if constexpr (Count == 117) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117); + } + else if constexpr (Count == 118) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118); + } + else if constexpr (Count == 119) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119); + } + else if constexpr (Count == 120) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120); + } + else if constexpr (Count == 121) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121); + } + else if constexpr (Count == 122) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122); + } + else if constexpr (Count == 123) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123); + } + else if constexpr (Count == 124) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124); + } + else if constexpr (Count == 125) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125); + } + else if constexpr (Count == 126) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126] = + object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125, a126); + } + else if constexpr (Count == 127) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, + a127] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127); + } + else { + return visit_members_by_structure_binding_expanded(object, visitor); + } + } + + template + constexpr decltype(auto) STRUCT_PACK_INLINE + visit_members_by_structure_binding_expanded(Object &&object, + Visitor &&visitor) { + using type = remove_cvref_t; + constexpr auto Count = struct_pack::members_count; + if constexpr (Count == 0 && std::is_class_v && + !std::is_same_v) { + static_assert(!sizeof(type), + "1. If the struct is empty, which is not allowed in " + "struct_pack type system.\n" + "2. If the strut is not empty, it means struct_pack can't " + "calculate your struct members' count. You can use macro " + "STRUCT_PACK_REFL(Typename, field1, field2...)."); + } + static_assert(Count <= MaxVisitMembers, "exceed max visit members"); + if constexpr (Count == 128) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128); + } + else if constexpr (Count == 129) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129); + } + else if constexpr (Count == 130) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130); + } + else if constexpr (Count == 131) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131); + } + else if constexpr (Count == 132) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132); + } + else if constexpr (Count == 133) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133); + } + else if constexpr (Count == 134) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134); + } + else if constexpr (Count == 135) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135); + } + else if constexpr (Count == 136) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136); + } + else if constexpr (Count == 137) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137); + } + else if constexpr (Count == 138) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, + a138] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138); + } + else if constexpr (Count == 139) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139); + } + else if constexpr (Count == 140) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140); + } + else if constexpr (Count == 141) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141); + } + else if constexpr (Count == 142) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142); + } + else if constexpr (Count == 143) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143); + } + else if constexpr (Count == 144) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144); + } + else if constexpr (Count == 145) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, + a138, a139, a140, a141, a142, a143, a144, a145); + } + else if constexpr (Count == 146) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, + a138, a139, a140, a141, a142, a143, a144, a145, a146); + } + else if constexpr (Count == 147) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147); + } + else if constexpr (Count == 148) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148); + } + else if constexpr (Count == 149) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, + a149] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149); + } + else if constexpr (Count == 150) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150); + } + else if constexpr (Count == 151) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151); + } + else if constexpr (Count == 152) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152); + } + else if constexpr (Count == 153) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153); + } + else if constexpr (Count == 154) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154); + } + else if constexpr (Count == 155) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155); + } + else if constexpr (Count == 156) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156] = object; + return visitor(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, + a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, + a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, + a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, + a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, + a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, + a86, a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, + a98, a99, a100, a101, a102, a103, a104, a105, a106, a107, + a108, a109, a110, a111, a112, a113, a114, a115, a116, a117, + a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, + a138, a139, a140, a141, a142, a143, a144, a145, a146, a147, + a148, a149, a150, a151, a152, a153, a154, a155, a156); + } + else if constexpr (Count == 157) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157); + } + else if constexpr (Count == 158) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158); + } + else if constexpr (Count == 159) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159); + } + else if constexpr (Count == 160) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, + a160] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160); + } + else if constexpr (Count == 161) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161); + } + else if constexpr (Count == 162) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162); + } + else if constexpr (Count == 163) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163); + } + else if constexpr (Count == 164) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164); + } + else if constexpr (Count == 165) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165); + } + else if constexpr (Count == 166) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166); + } + else if constexpr (Count == 167) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167); + } + else if constexpr (Count == 168) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168); + } + else if constexpr (Count == 169) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169); + } + else if constexpr (Count == 170) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170); + } + else if constexpr (Count == 171) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, + a171] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171); + } + else if constexpr (Count == 172) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172); + } + else if constexpr (Count == 173) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173); + } + else if constexpr (Count == 174) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174); + } + else if constexpr (Count == 175) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175); + } + else if constexpr (Count == 176) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176); + } + else if constexpr (Count == 177) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177); + } + else if constexpr (Count == 178) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178); + } + else if constexpr (Count == 179) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179); + } + else if constexpr (Count == 180) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180); + } + else if constexpr (Count == 181) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181); + } + else if constexpr (Count == 182) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, + a182] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182); + } + else if constexpr (Count == 183) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183); + } + else if constexpr (Count == 184) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184); + } + else if constexpr (Count == 185) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185); + } + else if constexpr (Count == 186) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186); + } + else if constexpr (Count == 187) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187); + } + else if constexpr (Count == 188) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188); + } + else if constexpr (Count == 189) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189); + } + else if constexpr (Count == 190) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190); + } + else if constexpr (Count == 191) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191); + } + else if constexpr (Count == 192) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192); + } + else if constexpr (Count == 193) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, + a193] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193); + } + else if constexpr (Count == 194) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194); + } + else if constexpr (Count == 195) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195); + } + else if constexpr (Count == 196) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196); + } + else if constexpr (Count == 197) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197); + } + else if constexpr (Count == 198) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198); + } + else if constexpr (Count == 199) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199); + } + else if constexpr (Count == 200) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200); + } + else if constexpr (Count == 201) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201); + } + else if constexpr (Count == 202) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202); + } + else if constexpr (Count == 203) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203); + } + else if constexpr (Count == 204) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, + a204] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204); + } + else if constexpr (Count == 205) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205); + } + else if constexpr (Count == 206) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206); + } + else if constexpr (Count == 207) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207); + } + else if constexpr (Count == 208) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208); + } + else if constexpr (Count == 209) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209); + } + else if constexpr (Count == 210) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210); + } + else if constexpr (Count == 211) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211); + } + else if constexpr (Count == 212) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212); + } + else if constexpr (Count == 213) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213); + } + else if constexpr (Count == 214) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214); + } + else if constexpr (Count == 215) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, + a215] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215); + } + else if constexpr (Count == 216) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216); + } + else if constexpr (Count == 217) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217); + } + else if constexpr (Count == 218) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218); + } + else if constexpr (Count == 219) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219); + } + else if constexpr (Count == 220) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220); + } + else if constexpr (Count == 221) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221); + } + else if constexpr (Count == 222) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222); + } + else if constexpr (Count == 223) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223); + } + else if constexpr (Count == 224) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224); + } + else if constexpr (Count == 225) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225); + } + else if constexpr (Count == 226) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, + a226] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226); + } + else if constexpr (Count == 227) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227); + } + else if constexpr (Count == 228) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228); + } + else if constexpr (Count == 229) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229); + } + else if constexpr (Count == 230) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230); + } + else if constexpr (Count == 231) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231); + } + else if constexpr (Count == 232) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232); + } + else if constexpr (Count == 233) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233); + } + else if constexpr (Count == 234) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234); + } + else if constexpr (Count == 235) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235); + } + else if constexpr (Count == 236) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236); + } + else if constexpr (Count == 237) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, + a237] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237); + } + else if constexpr (Count == 238) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238); + } + else if constexpr (Count == 239) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239); + } + else if constexpr (Count == 240) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240); + } + else if constexpr (Count == 241) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241); + } + else if constexpr (Count == 242) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242); + } + else if constexpr (Count == 243) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243); + } + else if constexpr (Count == 244) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244); + } + else if constexpr (Count == 245) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245); + } + else if constexpr (Count == 246) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246); + } + else if constexpr (Count == 247) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247] = + object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247); + } + else if constexpr (Count == 248) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, + a248] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248); + } + else if constexpr (Count == 249) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, a248, + a249] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248, a249); + } + else if constexpr (Count == 250) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, a248, + a249, a250] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248, a249, a250); + } + else if constexpr (Count == 251) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, a248, + a249, a250, a251] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248, a249, a250, a251); + } + else if constexpr (Count == 252) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, a248, + a249, a250, a251, a252] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248, a249, a250, a251, a252); + } + else if constexpr (Count == 253) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, a248, + a249, a250, a251, a252, a253] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248, a249, a250, a251, a252, a253); + } + else if constexpr (Count == 254) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, a248, + a249, a250, a251, a252, a253, a254] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248, a249, a250, a251, a252, a253, a254); + } + else if constexpr (Count == 255) { + auto &&[a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, + a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, + a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, + a55, a56, a57, a58, a59, a60, a61, a62, a63, a64, a65, a66, a67, + a68, a69, a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, a80, + a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, a92, a93, + a94, a95, a96, a97, a98, a99, a100, a101, a102, a103, a104, a105, + a106, a107, a108, a109, a110, a111, a112, a113, a114, a115, a116, + a117, a118, a119, a120, a121, a122, a123, a124, a125, a126, a127, + a128, a129, a130, a131, a132, a133, a134, a135, a136, a137, a138, + a139, a140, a141, a142, a143, a144, a145, a146, a147, a148, a149, + a150, a151, a152, a153, a154, a155, a156, a157, a158, a159, a160, + a161, a162, a163, a164, a165, a166, a167, a168, a169, a170, a171, + a172, a173, a174, a175, a176, a177, a178, a179, a180, a181, a182, + a183, a184, a185, a186, a187, a188, a189, a190, a191, a192, a193, + a194, a195, a196, a197, a198, a199, a200, a201, a202, a203, a204, + a205, a206, a207, a208, a209, a210, a211, a212, a213, a214, a215, + a216, a217, a218, a219, a220, a221, a222, a223, a224, a225, a226, + a227, a228, a229, a230, a231, a232, a233, a234, a235, a236, a237, + a238, a239, a240, a241, a242, a243, a244, a245, a246, a247, a248, + a249, a250, a251, a252, a253, a254, a255] = object; + return visitor( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, + a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, + a59, a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, + a73, a74, a75, a76, a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, + a87, a88, a89, a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, a100, + a101, a102, a103, a104, a105, a106, a107, a108, a109, a110, a111, + a112, a113, a114, a115, a116, a117, a118, a119, a120, a121, a122, + a123, a124, a125, a126, a127, a128, a129, a130, a131, a132, a133, + a134, a135, a136, a137, a138, a139, a140, a141, a142, a143, a144, + a145, a146, a147, a148, a149, a150, a151, a152, a153, a154, a155, + a156, a157, a158, a159, a160, a161, a162, a163, a164, a165, a166, + a167, a168, a169, a170, a171, a172, a173, a174, a175, a176, a177, + a178, a179, a180, a181, a182, a183, a184, a185, a186, a187, a188, + a189, a190, a191, a192, a193, a194, a195, a196, a197, a198, a199, + a200, a201, a202, a203, a204, a205, a206, a207, a208, a209, a210, + a211, a212, a213, a214, a215, a216, a217, a218, a219, a220, a221, + a222, a223, a224, a225, a226, a227, a228, a229, a230, a231, a232, + a233, a234, a235, a236, a237, a238, a239, a240, a241, a242, a243, + a244, a245, a246, a247, a248, a249, a250, a251, a252, a253, a254, + a255); + } + } +template +constexpr decltype(auto) STRUCT_PACK_INLINE template_switch(std::size_t index, + Args &&...args) { + switch (index) { + case 0: + return Func::template run<0>(std::forward(args)...); + case 1: + return Func::template run<1>(std::forward(args)...); + case 2: + return Func::template run<2>(std::forward(args)...); + case 3: + return Func::template run<3>(std::forward(args)...); + case 4: + return Func::template run<4>(std::forward(args)...); + case 5: + return Func::template run<5>(std::forward(args)...); + case 6: + return Func::template run<6>(std::forward(args)...); + case 7: + return Func::template run<7>(std::forward(args)...); + case 8: + return Func::template run<8>(std::forward(args)...); + case 9: + return Func::template run<9>(std::forward(args)...); + case 10: + return Func::template run<10>(std::forward(args)...); + case 11: + return Func::template run<11>(std::forward(args)...); + case 12: + return Func::template run<12>(std::forward(args)...); + case 13: + return Func::template run<13>(std::forward(args)...); + case 14: + return Func::template run<14>(std::forward(args)...); + case 15: + return Func::template run<15>(std::forward(args)...); + case 16: + return Func::template run<16>(std::forward(args)...); + case 17: + return Func::template run<17>(std::forward(args)...); + case 18: + return Func::template run<18>(std::forward(args)...); + case 19: + return Func::template run<19>(std::forward(args)...); + case 20: + return Func::template run<20>(std::forward(args)...); + case 21: + return Func::template run<21>(std::forward(args)...); + case 22: + return Func::template run<22>(std::forward(args)...); + case 23: + return Func::template run<23>(std::forward(args)...); + case 24: + return Func::template run<24>(std::forward(args)...); + case 25: + return Func::template run<25>(std::forward(args)...); + case 26: + return Func::template run<26>(std::forward(args)...); + case 27: + return Func::template run<27>(std::forward(args)...); + case 28: + return Func::template run<28>(std::forward(args)...); + case 29: + return Func::template run<29>(std::forward(args)...); + case 30: + return Func::template run<30>(std::forward(args)...); + case 31: + return Func::template run<31>(std::forward(args)...); + case 32: + return Func::template run<32>(std::forward(args)...); + case 33: + return Func::template run<33>(std::forward(args)...); + case 34: + return Func::template run<34>(std::forward(args)...); + case 35: + return Func::template run<35>(std::forward(args)...); + case 36: + return Func::template run<36>(std::forward(args)...); + case 37: + return Func::template run<37>(std::forward(args)...); + case 38: + return Func::template run<38>(std::forward(args)...); + case 39: + return Func::template run<39>(std::forward(args)...); + case 40: + return Func::template run<40>(std::forward(args)...); + case 41: + return Func::template run<41>(std::forward(args)...); + case 42: + return Func::template run<42>(std::forward(args)...); + case 43: + return Func::template run<43>(std::forward(args)...); + case 44: + return Func::template run<44>(std::forward(args)...); + case 45: + return Func::template run<45>(std::forward(args)...); + case 46: + return Func::template run<46>(std::forward(args)...); + case 47: + return Func::template run<47>(std::forward(args)...); + case 48: + return Func::template run<48>(std::forward(args)...); + case 49: + return Func::template run<49>(std::forward(args)...); + case 50: + return Func::template run<50>(std::forward(args)...); + case 51: + return Func::template run<51>(std::forward(args)...); + case 52: + return Func::template run<52>(std::forward(args)...); + case 53: + return Func::template run<53>(std::forward(args)...); + case 54: + return Func::template run<54>(std::forward(args)...); + case 55: + return Func::template run<55>(std::forward(args)...); + case 56: + return Func::template run<56>(std::forward(args)...); + case 57: + return Func::template run<57>(std::forward(args)...); + case 58: + return Func::template run<58>(std::forward(args)...); + case 59: + return Func::template run<59>(std::forward(args)...); + case 60: + return Func::template run<60>(std::forward(args)...); + case 61: + return Func::template run<61>(std::forward(args)...); + case 62: + return Func::template run<62>(std::forward(args)...); + case 63: + return Func::template run<63>(std::forward(args)...); + case 64: + return Func::template run<64>(std::forward(args)...); + case 65: + return Func::template run<65>(std::forward(args)...); + case 66: + return Func::template run<66>(std::forward(args)...); + case 67: + return Func::template run<67>(std::forward(args)...); + case 68: + return Func::template run<68>(std::forward(args)...); + case 69: + return Func::template run<69>(std::forward(args)...); + case 70: + return Func::template run<70>(std::forward(args)...); + case 71: + return Func::template run<71>(std::forward(args)...); + case 72: + return Func::template run<72>(std::forward(args)...); + case 73: + return Func::template run<73>(std::forward(args)...); + case 74: + return Func::template run<74>(std::forward(args)...); + case 75: + return Func::template run<75>(std::forward(args)...); + case 76: + return Func::template run<76>(std::forward(args)...); + case 77: + return Func::template run<77>(std::forward(args)...); + case 78: + return Func::template run<78>(std::forward(args)...); + case 79: + return Func::template run<79>(std::forward(args)...); + case 80: + return Func::template run<80>(std::forward(args)...); + case 81: + return Func::template run<81>(std::forward(args)...); + case 82: + return Func::template run<82>(std::forward(args)...); + case 83: + return Func::template run<83>(std::forward(args)...); + case 84: + return Func::template run<84>(std::forward(args)...); + case 85: + return Func::template run<85>(std::forward(args)...); + case 86: + return Func::template run<86>(std::forward(args)...); + case 87: + return Func::template run<87>(std::forward(args)...); + case 88: + return Func::template run<88>(std::forward(args)...); + case 89: + return Func::template run<89>(std::forward(args)...); + case 90: + return Func::template run<90>(std::forward(args)...); + case 91: return Func::template run<91>(std::forward(args)...); case 92: return Func::template run<92>(std::forward(args)...); @@ -2271,23 +9535,22 @@ constexpr bool checkable_reader_t = reader_t &&checkable_reader_t_impl::va #endif } // namespace struct_pack -// clang-format off #define STRUCT_PACK_RETURN_ELEMENT(Idx, X) \ if constexpr (Idx == I) {\ return c.X;\ -}\ +} -#define STRUCT_PACK_GET_INDEX(Idx, Type) \ -inline auto& STRUCT_PACK_GET_##Idx(Type& c) {\ - return STRUCT_PACK_GET()-1-Idx>(c);\ -}\ +#define STRUCT_PACK_GET_INDEX(Idx, Type) \ + inline auto &_SPG##Idx(Type &c) { \ + return STRUCT_PACK_GET() - 1 - Idx>(c); \ + } -#define STRUCT_PACK_GET_INDEX_CONST(Idx, Type) \ -inline const auto& STRUCT_PACK_GET_##Idx(const Type& c) {\ - return STRUCT_PACK_GET()-1-Idx>(c);\ -}\ +#define STRUCT_PACK_GET_INDEX_CONST(Idx, Type) \ + inline const auto &_SPG##Idx(const Type &c) { \ + return STRUCT_PACK_GET() - 1 - Idx>(c); \ + } #define STRUCT_PACK_REFL(Type,...) \ inline Type& STRUCT_PACK_REFL_FLAG(Type& t) {return t;} \ diff --git a/src/struct_pack/tests/test_many_members.cpp b/src/struct_pack/tests/test_many_members.cpp new file mode 100644 index 000000000..44a4e7807 --- /dev/null +++ b/src/struct_pack/tests/test_many_members.cpp @@ -0,0 +1,278 @@ +#include + +#include "doctest.h" +#include "ylt/struct_pack.hpp" +#include "ylt/struct_pack/type_calculate.hpp" +struct many_members { + int a1; + std::string b1; + int a2; + std::string b2; + int a3; + std::string b3; + int a4; + std::string b4; + int a5; + std::string b5; + int a6; + std::string b6; + int a7; + std::string b7; + int a8; + std::string b8; + int a9; + std::string b9; + int a10; + std::string b10; + int a11; + std::string b11; + int a12; + std::string b12; + int a13; + std::string b13; + int a14; + std::string b14; + int a15; + std::string b15; + int a16; + std::string b16; + int a17; + std::string b17; + int a18; + std::string b18; + int a19; + std::string b19; + int a20; + std::string b20; + int a21; + std::string b21; + int a22; + std::string b22; + int a23; + std::string b23; + int a24; + std::string b24; + int a25; + std::string b25; + int a26; + std::string b26; + int a27; + std::string b27; + int a28; + std::string b28; + int a29; + std::string b29; + int a30; + std::string b30; + int a31; + std::string b31; + int a32; + std::string b32; + int a33; + std::string b33; + int a34; + std::string b34; + int a35; + std::string b35; + int a36; + std::string b36; + int a37; + std::string b37; + int a38; + std::string b38; + int a39; + std::string b39; + int a40; + std::string b40; + int a41; + std::string b41; + int a42; + std::string b42; + int a43; + std::string b43; + int a44; + std::string b44; + int a45; + std::string b45; + int a46; + std::string b46; + int a47; + std::string b47; + int a48; + std::string b48; + int a49; + std::string b49; + int a50; + std::string b50; + int a51; + std::string b51; + int a52; + std::string b52; + int a53; + std::string b53; + int a54; + std::string b54; + int a55; + std::string b55; + int a56; + std::string b56; + int a57; + std::string b57; + int a58; + std::string b58; + int a59; + std::string b59; + int a60; + std::string b60; + int a61; + std::string b61; + int a62; + std::string b62; + int a63; + std::string b63; + int a64; + std::string b64; + int a65; + std::string b65; + int a66; + std::string b66; + int a67; + std::string b67; + int a68; + std::string b68; + int a69; + std::string b69; + int a70; + std::string b70; + int a71; + std::string b71; + int a72; + std::string b72; + int a73; + std::string b73; + int a74; + std::string b74; + int a75; + std::string b75; + int a76; + std::string b76; + int a77; + std::string b77; + int a78; + std::string b78; + int a79; + std::string b79; + int a80; + std::string b80; + int a81; + std::string b81; + int a82; + std::string b82; + int a83; + std::string b83; + int a84; + std::string b84; + int a85; + std::string b85; + int a86; + std::string b86; + int a87; + std::string b87; + int a88; + std::string b88; + int a89; + std::string b89; + int a90; + std::string b90; + int a91; + std::string b91; + int a92; + std::string b92; + int a93; + std::string b93; + int a94; + std::string b94; + int a95; + std::string b95; + int a96; + std::string b96; + int a97; + std::string b97; + int a98; + std::string b98; + int a99; + std::string b99; + int a100; + std::string b100; + int a101; + std::string b101; + int a102; + std::string b102; + int a103; + std::string b103; + int a104; + std::string b104; + int a105; + std::string b105; + int a106; + std::string b106; + int a107; + std::string b107; + int a108; + std::string b108; + int a109; + std::string b109; + int a110; + std::string b110; + int a111; + std::string b111; + int a112; + std::string b112; + int a113; + std::string b113; + int a114; + std::string b114; + int a115; + std::string b115; + int a116; + std::string b116; + int a117; + std::string b117; + int a118; + std::string b118; + int a119; + std::string b119; + int a120; + std::string b120; + int a121; + std::string b121; + int a122; + std::string b122; + int a123; + std::string b123; + int a124; + std::string b124; + int a125; + std::string b125; + int a126; + std::string b126; + int a127; + std::string b127; + int a128; +}; +struct many_members2 : public many_members {}; +STRUCT_PACK_REFL(many_members2, a1, b1, a2, b2, a3, b3, a4, b4, a5, b5, a6, b6, + a7, b7, a8, b8, a9, b9, a10, b10, a11, b11, a12, b12, a13, b13, + a14, b14, a15, b15, a16, b16, a17, b17, a18, b18, a19, b19, + a20, b20, a21, b21, a22, b22, a23, b23, a24, b24, a25, b25, + a26, b26, a27, b27, a28, b28, a29, b29, a30, b30, a31, b31, + a32, b32, a33, b33, a34, b34, a35, b35, a36, b36, a37, b37, + a38, b38, a39, b39, a40, b40, a41, b41, a42, b42, a43, b43, + a44, b44, a45, b45, a46, b46, a47, b47, a48, b48, a49, b49, + a50, b50, a51, b51, a52, b52, a53, b53, a54, b54, a55, b55, + a56, b56, a57, b57, a58, b58, a59, b59, a60, b60, a61, b61, + a62, b62); +TEST_CASE("test many members") { + CHECK(struct_pack::get_type_literal().size() == 384); + CHECK(struct_pack::get_type_literal().size() == 188); +} \ No newline at end of file diff --git a/test.cpp b/test.cpp new file mode 100644 index 000000000..a41527120 --- /dev/null +++ b/test.cpp @@ -0,0 +1,14 @@ +#include +#include +using namespace std; +string i1 = "else if constexpr (Count == "; +string j = " ){ return visitor("; +string l = ");}"; +int main() { + std::string list = "_SPG0(o)"; + for (int i = 2; i <= 256; ++i) { + list += ",_SPG" + to_string(i - 1) + "(o)"; + cout << i1 + to_string(i) + j + list + l << endl; + } + return 0; +} diff --git a/website/docs/en/coro_rpc/coro_rpc_server.md b/website/docs/en/coro_rpc/coro_rpc_server.md index 2eb8a3742..10abb82da 100644 --- a/website/docs/en/coro_rpc/coro_rpc_server.md +++ b/website/docs/en/coro_rpc/coro_rpc_server.md @@ -274,7 +274,7 @@ This means if your RPC functions will block the current thread (e.g., thread sle ## Parameter and Return Value Types -coro_rpc allows users to register rpc functions with multiple parameters (up to 64), and the types of arguments and return values can be user-defined aggregate structures. They also support various data structures provided by the C++ standard library and many third-party libraries. For details, see: [struct_pack type system](https://alibaba.github.io/yalantinglibs/en/struct_pack/struct_pack_type_system.html) +coro_rpc allows users to register rpc functions with multiple parameters (up to 255), and the types of arguments and return values can be user-defined aggregate structures. They also support various data structures provided by the C++ standard library and many third-party libraries. For details, see: [struct_pack type system](https://alibaba.github.io/yalantinglibs/en/struct_pack/struct_pack_type_system.html) If your rpc argument or return value type is not supported by the struct_pack type system, we also allow users to register their own structures or custom serialization algorithms. For more details, see: [Custom feature](https://alibaba.github.io/yalantinglibs/en/struct_pack/struct_pack_intro.html#custom-type) diff --git a/website/docs/en/struct_pack/struct_pack_type_system.md b/website/docs/en/struct_pack/struct_pack_type_system.md index 3bcd91d92..f46091ace 100644 --- a/website/docs/en/struct_pack/struct_pack_type_system.md +++ b/website/docs/en/struct_pack/struct_pack_type_system.md @@ -216,7 +216,7 @@ The class needs to provide: `size()`,`flip()`,`set()`,`reset()`,`count()`,and th ## Struct -`struct_pack` supports `struct` type. Up to **64** fields are supported and nested fields are supported too. All members +`struct_pack` supports `struct` type. Up to **255** fields are supported and nested fields are supported too. All members should be of valid `struct_pack` type. struct type could be `struct/class/std::tuple/tuplet::tuple/std::pair` diff --git a/website/docs/zh/coro_rpc/coro_rpc_server.md b/website/docs/zh/coro_rpc/coro_rpc_server.md index 0d3b8be46..2ee1144a6 100644 --- a/website/docs/zh/coro_rpc/coro_rpc_server.md +++ b/website/docs/zh/coro_rpc/coro_rpc_server.md @@ -272,7 +272,7 @@ rpc错误码是一个16位的无符号整数。其中,0-255是保留给rpc框 ## 参数与返回值类型 -coro_rpc允许用户注册的rpc函数具有多个参数(最多64个),参数和返回值的类型可以是用户自定义的聚合结构体,也支持了各种c++标准库提供的数据结构和许多第三方库提供的数据结构。详见:[struct_pack的类型系统](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_type_system.html) +coro_rpc允许用户注册的rpc函数具有多个参数(最多255个),参数和返回值的类型可以是用户自定义的聚合结构体,也支持了各种c++标准库提供的数据结构和许多第三方库提供的数据结构。详见:[struct_pack的类型系统](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_type_system.html) 如果你的rpc参数或返回值类型不属于struct_pack的类型系统支持的类型,我们也允许用户注册自己的结构体或者自定义序列化算法,详见:[自定义功能支持](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_intro.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96) diff --git a/website/docs/zh/struct_pack/struct_pack_type_system.md b/website/docs/zh/struct_pack/struct_pack_type_system.md index 6d3188c44..d37a1f788 100644 --- a/website/docs/zh/struct_pack/struct_pack_type_system.md +++ b/website/docs/zh/struct_pack/struct_pack_type_system.md @@ -219,7 +219,7 @@ concept unique_ptr = requires(Type ptr) { ## 结构体 -struct_pack支持结构体类型。结构体内可以包含最多64个字段,并允许结构体嵌套。结构体中的任何成员都必须是struct_pack的合法类型。 +struct_pack支持结构体类型。结构体内可以包含最多255个字段,并允许结构体嵌套。结构体中的任何成员都必须是struct_pack的合法类型。 struct_pack的结构体类型可以为:struct/class/std::pair/tuplet::tuple/std::tuple