Skip to content

Commit

Permalink
Add support for vectors of strings (#106)
Browse files Browse the repository at this point in the history
* Add support for vectors of strings

Signed-off-by: John Sallay <[email protected]>

* Use static cast into of old-style

Signed-off-by: John Sallay <[email protected]>

---------

Signed-off-by: John Sallay <[email protected]>
  • Loading branch information
jsallay authored Oct 7, 2023
1 parent 96ecfa7 commit e22b410
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 6 deletions.
50 changes: 45 additions & 5 deletions include/pmtv/pmt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,18 @@ constexpr uint8_t pmtTypeIndex()
return 5;
else if constexpr (std::same_as<T, std::string>)
return 6;
else if constexpr (std::same_as<T, std::map<std::string, pmt>>)
return 7;
else if constexpr (std::same_as<T, std::vector<std::string>>)
return 8;
else if constexpr (std::ranges::range<T>) {
if constexpr (UniformVector<T>) {
return pmtTypeIndex<typename T::value_type>() << 4;
}
else {
return 7; // for vector of PMTs
return 9; // for vector of PMTs
}
}
else if constexpr (std::same_as<T, std::map<std::string, pmt>>)
return 8;
}

template <class T>
Expand Down Expand Up @@ -265,6 +267,21 @@ std::streamsize _serialize(std::streambuf& sb, const T& arg) {
}
return length;
}

template <UniformStringVector T>
std::streamsize _serialize(std::streambuf& sb, const T& arg) {
auto length = _serialize_id<T>(sb);
uint64_t sz = arg.size();
length += sb.sputn(reinterpret_cast<const char*>(&sz), sizeof(uint64_t));
for (auto& value: arg) {
// Send length then value
sz = value.size();
length += sb.sputn(reinterpret_cast<const char*>(&sz), sizeof(uint64_t));
length += sb.sputn(value.data(), value.size());
}
return length;
}

template <UniformVector T>
std::streamsize _serialize(std::streambuf& sb, const T& arg) {
auto length = _serialize_id<T>(sb);
Expand Down Expand Up @@ -393,7 +410,10 @@ static pmt deserialize(std::streambuf& sb)

case serialInfo<std::string>::value:
return _deserialize_val<std::string>(sb);

case serialInfo<std::vector<std::string>>::value:
return _deserialize_val<std::vector<std::string>>(sb);
case serialInfo<std::vector<pmtv::pmt>>::value:
return _deserialize_val<std::vector<pmtv::pmt>>(sb);
case serialInfo<map_t>::value:
return _deserialize_val<map_t>(sb);
default:
Expand All @@ -411,6 +431,15 @@ T _deserialize_val(std::streambuf& sb)
sb.sgetn(reinterpret_cast<char*>(&val), sizeof(val));
return val;
}
else if constexpr (PmtVector<T>) {
std::vector<pmt> val;
uint64_t nelems;
sb.sgetn(reinterpret_cast<char*>(&nelems), sizeof(nelems));
for (uint64_t n = 0; n < nelems; n++) {
val.push_back(deserialize(sb));
}
return val;
}
else if constexpr (UniformVector<T> && !String<T>) {
uint64_t sz;
sb.sgetn(reinterpret_cast<char*>(&sz), sizeof(uint64_t));
Expand All @@ -425,6 +454,17 @@ T _deserialize_val(std::streambuf& sb)
sb.sgetn(reinterpret_cast<char*>(val.data()), static_cast<std::streamsize>(sz));
return val;
}
else if constexpr (UniformStringVector<T>) {
uint64_t sz;
sb.sgetn(reinterpret_cast<char*>(&sz), sizeof(uint64_t));
std::vector<typename T::value_type> val(sz);
for (size_t i = 0; i < val.size(); i++) {
sb.sgetn(reinterpret_cast<char*>(&sz), sizeof(uint64_t));
val[i].resize(sz);
sb.sgetn(val[i].data(), sz);
}
return val;
}
else if constexpr (PmtMap<T>) {
map_t val;

Expand Down Expand Up @@ -567,7 +607,7 @@ struct formatter<P>
return fmt::format_to(ctx.out(), "{}", arg);
else if constexpr (std::same_as<T, std::string>)
return fmt::format_to(ctx.out(), "{}", arg);
else if constexpr (UniformVector<T>)
else if constexpr (UniformVector<T> || UniformStringVector<T>)
return fmt::format_to(ctx.out(), "[{}]", fmt::join(arg, ", "));
else if constexpr (std::same_as<T, std::vector<pmt>>) {
fmt::format_to(ctx.out(), "[");
Expand Down
5 changes: 5 additions & 0 deletions include/pmtv/type_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct as_pmt {
Args...,
std::vector<Args>...,
std::string,
std::vector<std::string>,
std::vector<rva::self_t>,
std::map<std::string, rva::self_t>
>;
Expand Down Expand Up @@ -79,6 +80,10 @@ template <typename T>
concept UniformBoolVector =
std::ranges::range<T> && std::same_as<typename T::value_type, bool>;

template <typename T>
concept UniformStringVector =
std::ranges::range<T> && std::same_as<typename T::value_type, std::string>;

template <typename T>
concept PmtMap = std::is_same_v<T, std::map<std::string, pmt_var_t>>;

Expand Down
34 changes: 34 additions & 0 deletions test/qa_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string>() };
EXPECT_EQ(std::get<std::vector<std::string>>(empty_vec).size(), 0);

std::vector<std::string> s1{{ "hello world" }, {"abc"}};

auto p = pmt(s1);

auto s2 = pmtv::cast<std::vector<std::string>>(p);

EXPECT_TRUE(s1 == s2);
}

TEST(PmtStringVec, Serialization)
{
std::vector<std::string> 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<std::string> s1{{ "hello world" }, {"abc"}};
pmt x(s1);
EXPECT_EQ(fmt::format("{}", x), fmt::format("[{}]", fmt::join(s1, ", ")));
}
2 changes: 1 addition & 1 deletion test/qa_uniform_vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ TYPED_TEST(PmtVectorFixture, VectorConstructors)

// Range Constructor
pmt range_vec(vec_t<TypeParam>, vec.begin(), vec.end());
EXPECT_EQ(range_vec.size(), num_values);
EXPECT_EQ(range_vec.size(), static_cast<size_t>(num_values));
const auto& range_vals = std::get<std::vector<TypeParam>>(range_vec);
for (std::size_t i = 0; i < range_vec.size(); i++) {
EXPECT_EQ(range_vals[i], vec[i]);
Expand Down

0 comments on commit e22b410

Please sign in to comment.