From 40e2597b5708e940b82d500380fb6ac256f8751a Mon Sep 17 00:00:00 2001 From: John Sallay Date: Sat, 7 Oct 2023 08:08:30 -0400 Subject: [PATCH 1/2] Add support for vectors of strings Signed-off-by: John Sallay --- include/pmtv/pmt.hpp | 50 +++++++++++++++++++++++++++++++---- include/pmtv/type_helpers.hpp | 5 ++++ test/qa_string.cpp | 34 ++++++++++++++++++++++++ test/qa_uniform_vector.cpp | 2 +- 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/include/pmtv/pmt.hpp b/include/pmtv/pmt.hpp index 7a83a87..6c43952 100644 --- a/include/pmtv/pmt.hpp +++ b/include/pmtv/pmt.hpp @@ -186,16 +186,18 @@ constexpr uint8_t pmtTypeIndex() return 5; else if constexpr (std::same_as) return 6; + else if constexpr (std::same_as>) + return 7; + else if constexpr (std::same_as>) + return 8; else if constexpr (std::ranges::range) { if constexpr (UniformVector) { return pmtTypeIndex() << 4; } else { - return 7; // for vector of PMTs + return 9; // for vector of PMTs } } - else if constexpr (std::same_as>) - return 8; } template @@ -265,6 +267,21 @@ std::streamsize _serialize(std::streambuf& sb, const T& arg) { } return length; } + +template +std::streamsize _serialize(std::streambuf& sb, const T& arg) { + auto length = _serialize_id(sb); + uint64_t sz = arg.size(); + length += sb.sputn(reinterpret_cast(&sz), sizeof(uint64_t)); + for (auto& value: arg) { + // Send length then value + sz = value.size(); + length += sb.sputn(reinterpret_cast(&sz), sizeof(uint64_t)); + length += sb.sputn(value.data(), value.size()); + } + return length; +} + template std::streamsize _serialize(std::streambuf& sb, const T& arg) { auto length = _serialize_id(sb); @@ -393,7 +410,10 @@ static pmt deserialize(std::streambuf& sb) case serialInfo::value: return _deserialize_val(sb); - + case serialInfo>::value: + return _deserialize_val>(sb); + case serialInfo>::value: + return _deserialize_val>(sb); case serialInfo::value: return _deserialize_val(sb); default: @@ -411,6 +431,15 @@ T _deserialize_val(std::streambuf& sb) sb.sgetn(reinterpret_cast(&val), sizeof(val)); return val; } + else if constexpr (PmtVector) { + std::vector val; + uint64_t nelems; + sb.sgetn(reinterpret_cast(&nelems), sizeof(nelems)); + for (uint64_t n = 0; n < nelems; n++) { + val.push_back(deserialize(sb)); + } + return val; + } else if constexpr (UniformVector && !String) { uint64_t sz; sb.sgetn(reinterpret_cast(&sz), sizeof(uint64_t)); @@ -425,6 +454,17 @@ T _deserialize_val(std::streambuf& sb) sb.sgetn(reinterpret_cast(val.data()), static_cast(sz)); return val; } + else if constexpr (UniformStringVector) { + uint64_t sz; + sb.sgetn(reinterpret_cast(&sz), sizeof(uint64_t)); + std::vector val(sz); + for (size_t i = 0; i < val.size(); i++) { + sb.sgetn(reinterpret_cast(&sz), sizeof(uint64_t)); + val[i].resize(sz); + sb.sgetn(val[i].data(), sz); + } + return val; + } else if constexpr (PmtMap) { map_t val; @@ -567,7 +607,7 @@ struct formatter

return fmt::format_to(ctx.out(), "{}", arg); else if constexpr (std::same_as) return fmt::format_to(ctx.out(), "{}", arg); - else if constexpr (UniformVector) + else if constexpr (UniformVector || UniformStringVector) return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", ")); else if constexpr (std::same_as>) { fmt::format_to(ctx.out(), "["); diff --git a/include/pmtv/type_helpers.hpp b/include/pmtv/type_helpers.hpp index ae81224..d9cddf1 100644 --- a/include/pmtv/type_helpers.hpp +++ b/include/pmtv/type_helpers.hpp @@ -21,6 +21,7 @@ struct as_pmt { Args..., std::vector..., std::string, + std::vector, std::vector, std::map >; @@ -79,6 +80,10 @@ template concept UniformBoolVector = std::ranges::range && std::same_as; +template +concept UniformStringVector = + std::ranges::range && std::same_as; + template concept PmtMap = std::is_same_v>; diff --git a/test/qa_string.cpp b/test/qa_string.cpp index 6a3cea3..abd1298 100644 --- a/test/qa_string.cpp +++ b/test/qa_string.cpp @@ -48,3 +48,37 @@ TEST(PmtString, fmt) pmt x(s1); EXPECT_EQ(fmt::format("{}", x), fmt::format("{}", s1)); } + +TEST(PmtStringVec, Constructor) +{ + // Empty Constructor + pmt empty_vec{ std::vector() }; + EXPECT_EQ(std::get>(empty_vec).size(), 0); + + std::vector s1{{ "hello world" }, {"abc"}}; + + auto p = pmt(s1); + + auto s2 = pmtv::cast>(p); + + EXPECT_TRUE(s1 == s2); +} + +TEST(PmtStringVec, Serialization) +{ + std::vector s1{{ "hello world" }, {"abc"}}; + + auto x = pmt(s1); + + std::stringbuf sb; + pmtv::serialize(sb, x); + auto y = pmtv::deserialize(sb); + EXPECT_EQ(x == y, true); +} + +TEST(PmtStringVec, fmt) +{ + std::vector s1{{ "hello world" }, {"abc"}}; + pmt x(s1); + EXPECT_EQ(fmt::format("{}", x), fmt::format("[{}]", fmt::join(s1, ", "))); +} \ No newline at end of file diff --git a/test/qa_uniform_vector.cpp b/test/qa_uniform_vector.cpp index dc16998..80beaee 100644 --- a/test/qa_uniform_vector.cpp +++ b/test/qa_uniform_vector.cpp @@ -102,7 +102,7 @@ TYPED_TEST(PmtVectorFixture, VectorConstructors) // Range Constructor pmt range_vec(vec_t, vec.begin(), vec.end()); - EXPECT_EQ(range_vec.size(), num_values); + EXPECT_EQ(range_vec.size(), size_t(num_values)); const auto& range_vals = std::get>(range_vec); for (std::size_t i = 0; i < range_vec.size(); i++) { EXPECT_EQ(range_vals[i], vec[i]); From 8abb49796f18f18e2c0a88a9f93855bd2bcbec13 Mon Sep 17 00:00:00 2001 From: John Sallay Date: Sat, 7 Oct 2023 16:20:25 -0400 Subject: [PATCH 2/2] Use static cast into of old-style Signed-off-by: John Sallay --- test/qa_uniform_vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/qa_uniform_vector.cpp b/test/qa_uniform_vector.cpp index 80beaee..2ccd8e0 100644 --- a/test/qa_uniform_vector.cpp +++ b/test/qa_uniform_vector.cpp @@ -102,7 +102,7 @@ TYPED_TEST(PmtVectorFixture, VectorConstructors) // Range Constructor pmt range_vec(vec_t, vec.begin(), vec.end()); - EXPECT_EQ(range_vec.size(), size_t(num_values)); + EXPECT_EQ(range_vec.size(), static_cast(num_values)); const auto& range_vals = std::get>(range_vec); for (std::size_t i = 0; i < range_vec.size(); i++) { EXPECT_EQ(range_vals[i], vec[i]);