Skip to content

Commit f6596e2

Browse files
drewdzzzalyapunov
authored andcommitted
Dec, Enc: introduce variant support
The commit adds variant support to decoder and encoder.
1 parent dbec81e commit f6596e2

File tree

4 files changed

+166
-3
lines changed

4 files changed

+166
-3
lines changed

src/mpp/Constants.hpp

+48
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,54 @@ static constexpr auto family_sequence_populate(struct family_sequence<FAMILY...>
209209
return family_sequence<NEW_FAMILY, FAMILY...>{};
210210
}
211211

212+
template <compact::Family ...FAMILY_A, compact::Family ...FAMILY_B>
213+
inline constexpr auto
214+
operator+(family_sequence<FAMILY_A...>, family_sequence<FAMILY_B...>)
215+
{
216+
return family_sequence<FAMILY_A..., FAMILY_B...>{};
217+
}
218+
219+
namespace details {
220+
221+
template <compact::Family NEEDLE, compact::Family HEAD, compact::Family ...TAIL>
222+
struct family_sequence_contains_impl_h {
223+
static constexpr bool value =
224+
family_sequence_contains_impl_h<NEEDLE, TAIL...>::value;
225+
};
226+
227+
template <compact::Family NEEDLE, compact::Family LAST>
228+
struct family_sequence_contains_impl_h<NEEDLE, LAST> {
229+
static constexpr bool value = false;
230+
};
231+
232+
template <compact::Family NEEDLE, compact::Family ...TAIL>
233+
struct family_sequence_contains_impl_h<NEEDLE, NEEDLE, TAIL...> {
234+
static constexpr bool value = true;
235+
};
236+
237+
template <compact::Family NEEDLE>
238+
struct family_sequence_contains_impl_h<NEEDLE, NEEDLE> {
239+
static constexpr bool value = true;
240+
};
241+
242+
template <compact::Family NEEDLE, compact::Family ...HAYSTACK>
243+
struct family_sequence_contains_h {
244+
static constexpr bool value =
245+
family_sequence_contains_impl_h<NEEDLE, HAYSTACK...>::value;
246+
};
247+
248+
template <compact::Family NEEDLE>
249+
struct family_sequence_contains_h<NEEDLE> {
250+
static constexpr bool value = false;
251+
};
252+
253+
} //namespace details
254+
255+
template <compact::Family NEEDLE, compact::Family ...HAYSTACK>
256+
static constexpr bool family_sequence_contains(family_sequence<HAYSTACK...>) {
257+
return details::family_sequence_contains_h<NEEDLE, HAYSTACK...>::value;
258+
}
259+
212260
template <compact::Family ...FAMILY>
213261
std::ostream&
214262
operator<<(std::ostream& strm, family_sequence<FAMILY...>)

src/mpp/Dec.hpp

+60-3
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@ constexpr auto getFamiliesByRules()
9898
return getFamiliesByRules<T>(tnt::tuple_iseq<T>{});
9999
}
100100

101+
template <class BUF, class T>
102+
constexpr auto detectFamily();
103+
104+
template <class BUF, class T, size_t I = 0>
105+
constexpr auto detectFamilyVariant()
106+
{
107+
static_assert(tnt::is_variant_v<T>);
108+
if constexpr (I < std::variant_size_v<T>) {
109+
constexpr auto curFamily =
110+
detectFamily<BUF, std::variant_alternative_t<I, T>>();
111+
return curFamily + detectFamilyVariant<BUF, T, I + 1>();
112+
} else {
113+
return family_sequence<>{};
114+
}
115+
}
116+
101117
template <class BUF, class T>
102118
constexpr auto detectFamily()
103119
{
@@ -117,6 +133,8 @@ constexpr auto detectFamily()
117133
} else if constexpr (tnt::is_optional_v<U>) {
118134
return family_sequence_populate<compact::MP_NIL>(
119135
detectFamily<BUF, tnt::value_type_t<U>>());
136+
} else if constexpr (tnt::is_variant_v<U>) {
137+
return detectFamilyVariant<BUF, U>();
120138
} else if constexpr (std::is_same_v<U, std::nullptr_t>) {
121139
return family_sequence<compact::MP_NIL>{};
122140
} else if constexpr (std::is_same_v<U, bool>) {
@@ -176,6 +194,7 @@ enum path_item_type {
176194
PIT_DYN_KEY,
177195
PIT_DYN_SKIP,
178196
PIT_OPTIONAL,
197+
PIT_VARIANT,
179198
PIT_RAW,
180199
};
181200

@@ -239,8 +258,11 @@ struct Resolver {
239258
static constexpr size_t SIZE = path_item_static_size(PI);
240259
static constexpr size_t USR_ARG_COUNT = path_item_static_size(P0);
241260
static_assert(path_item_type(P0) == PIT_STATIC_L0);
242-
static_assert((is_path_item_static(PI) && POS < SIZE) ||
243-
(!is_path_item_static(PI) && POS + SIZE == 0));
261+
/* Is set if the current path item requires static POS and SIZE. */
262+
static constexpr bool requires_pos_and_size =
263+
is_path_item_static(PI) || path_item_type(PI) == PIT_VARIANT;
264+
static_assert((requires_pos_and_size && POS < SIZE) ||
265+
(!requires_pos_and_size && POS + SIZE == 0));
244266

245267
template <size_t... J>
246268
static constexpr size_t dyn_arg_pos(tnt::iseq<J...>)
@@ -298,6 +320,8 @@ struct Resolver {
298320
auto &&opt = prev(t...);
299321
assert(opt.has_value());
300322
return *opt;
323+
} else if constexpr (TYPE == PIT_VARIANT) {
324+
return tnt::get<POS>(prev(t...));
301325
} else {
302326
static_assert(tnt::always_false_v<T...>);
303327
}
@@ -871,7 +895,7 @@ bool decode_next(BUF& buf, T... t)
871895
return decode_impl<SKIP_PATH>(buf, t...);
872896
} else if constexpr (static_done) {
873897
return decode_next<POP_PATH>(buf, t...);
874-
} else if constexpr (LAST_TYPE == PIT_OPTIONAL) {
898+
} else if constexpr (LAST_TYPE == PIT_OPTIONAL || LAST_TYPE == PIT_VARIANT) {
875899
return decode_next<POP_PATH>(buf, t...);
876900
} else if constexpr (!is_path_item_dynamic(LAST)) {
877901
return decode_impl<NEXT_PATH>(buf, t...);
@@ -1167,6 +1191,37 @@ bool jump_read_optional(BUF& buf, T... t)
11671191
}
11681192
}
11691193

1194+
template <size_t I, compact::Family FAMILY, size_t SUBRULE,
1195+
class PATH, class BUF, class... T>
1196+
bool jump_read_variant_impl(BUF& buf, T... t)
1197+
{
1198+
auto&& variant = unwrap(path_resolve(PATH{}, t...));
1199+
using variant_t = std::remove_reference_t<decltype(variant)>;
1200+
constexpr size_t size = std::variant_size_v<variant_t>;
1201+
static_assert(tnt::is_variant_v<variant_t>);
1202+
static_assert(I < size);
1203+
using curType = std::variant_alternative_t<I, variant_t>;
1204+
constexpr auto curFamilies = detectFamily<BUF, curType>();
1205+
1206+
if constexpr (family_sequence_contains<FAMILY>(curFamilies)) {
1207+
variant.template emplace<I>();
1208+
using NEXT_PATH = path_push_t<PATH, PIT_VARIANT, size, I>;
1209+
return decode_impl<NEXT_PATH>(buf, t...);
1210+
} else {
1211+
return jump_read_variant_impl<I + 1, FAMILY, SUBRULE, PATH>(buf, t...);
1212+
}
1213+
}
1214+
1215+
template <compact::Family FAMILY, size_t SUBRULE,
1216+
class PATH, class BUF, class... T>
1217+
bool jump_read_variant(BUF& buf, T... t)
1218+
{
1219+
auto&& dst = unwrap(path_resolve(PATH{}, t...));
1220+
using dst_t = std::remove_reference_t<decltype(dst)>;
1221+
static_assert(tnt::is_variant_v<dst_t>);
1222+
return jump_read_variant_impl<0, FAMILY, SUBRULE, PATH>(buf, t...);
1223+
}
1224+
11701225
template <compact::Family FAMILY, size_t SUBRULE,
11711226
class PATH, class BUF, class... T>
11721227
bool jump_common(BUF& buf, T... t)
@@ -1178,6 +1233,8 @@ bool jump_common(BUF& buf, T... t)
11781233
using dst_t = std::remove_reference_t<decltype(dst)>;
11791234
if constexpr (tnt::is_optional_v<dst_t>)
11801235
return jump_read_optional<FAMILY, SUBRULE, PATH>(buf, t...);
1236+
else if constexpr (tnt::is_variant_v<dst_t>)
1237+
return jump_read_variant<FAMILY, SUBRULE, PATH>(buf, t...);
11811238
else if constexpr (path_item_type(PATH::last()) == PIT_DYN_ADD)
11821239
return jump_add<FAMILY, SUBRULE, PATH>(buf, t...);
11831240
else if constexpr (path_item_type(PATH::last()) == PIT_DYN_KEY)

src/mpp/Enc.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,10 @@ encode(CONT &cont, tnt::CStr<C...> prefix,
550550
return encode(cont, prefix, ais, u.value(), more...);
551551
else
552552
return encode(cont, prefix, ais, nullptr, more...);
553+
} else if constexpr(tnt::is_variant_v<U>) {
554+
bool rc = false;
555+
tnt::visit([&](const auto &v){rc = encode(cont, prefix, ais, v, more...);}, u);
556+
return rc;
553557
} else if constexpr(is_wrapped_raw_v<T>) {
554558
if constexpr(std::is_base_of_v<ChildrenTag, U>) {
555559
using V = typename U::type;

test/EncDecTest.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,59 @@ test_raw()
16181618
}
16191619
}
16201620

1621+
void
1622+
test_variant()
1623+
{
1624+
TEST_INIT(0);
1625+
1626+
using Buf_t = tnt::Buffer<16 * 1024>;
1627+
Buf_t buf;
1628+
auto run = buf.begin<true>();
1629+
1630+
using variant_t = std::variant<bool, int, std::string, nullptr_t,
1631+
std::optional<double>, std::vector<int>, Body>;
1632+
1633+
variant_t wr;
1634+
variant_t rd;
1635+
1636+
wr.emplace<0>(true);
1637+
mpp::encode(buf, wr);
1638+
mpp::decode(run, rd);
1639+
fail_unless(wr == rd);
1640+
1641+
wr.emplace<1>(42);
1642+
mpp::encode(buf, wr);
1643+
mpp::decode(run, rd);
1644+
fail_unless(wr == rd);
1645+
1646+
wr.emplace<2>("string variant");
1647+
mpp::encode(buf, wr);
1648+
mpp::decode(run, rd);
1649+
fail_unless(wr == rd);
1650+
1651+
wr.emplace<3>(nullptr);
1652+
mpp::encode(buf, wr);
1653+
mpp::decode(run, rd);
1654+
fail_unless(wr == rd);
1655+
1656+
wr.emplace<4>(64.0);
1657+
mpp::encode(buf, wr);
1658+
mpp::decode(run, rd);
1659+
fail_unless(wr == rd);
1660+
1661+
wr.emplace<5>({1, 2, 3, 4, 5, 6, 7, 8});
1662+
mpp::encode(buf, wr);
1663+
mpp::decode(run, rd);
1664+
fail_unless(wr == rd);
1665+
1666+
Body body;
1667+
body.gen();
1668+
wr.emplace<6>(body);
1669+
mpp::encode(buf, wr);
1670+
mpp::decode(run, rd);
1671+
fail_unless(wr == rd);
1672+
}
1673+
16211674
int main()
16221675
{
16231676
test_under_ints();
@@ -1628,4 +1681,5 @@ int main()
16281681
test_object_codec();
16291682
test_optional();
16301683
test_raw();
1684+
test_variant();
16311685
}

0 commit comments

Comments
 (0)