1 Commits

Author SHA1 Message Date
a1a4176801 add more DataBuffer serialization types
All checks were successful
Linux arm64 / Build (push) Successful in 17s
2025-07-31 14:12:33 +02:00
3 changed files with 124 additions and 8 deletions

View File

@@ -10,9 +10,11 @@
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <list>
#include <map> #include <map>
#include <sp/common/VarInt.h> #include <memory>
#include <sp/common/ByteSwapping.h> #include <sp/common/ByteSwapping.h>
#include <sp/common/VarInt.h>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -82,6 +84,24 @@ class DataBuffer {
*/ */
DataBuffer& operator<<(const DataBuffer& data); DataBuffer& operator<<(const DataBuffer& data);
/**
* \brief Append a pointer to the buffer
* \param data The data to append
*/
template <typename T>
DataBuffer& operator<<(const std::shared_ptr<T>& data) {
return *this << *data;
}
/**
* \brief Append a pointer to the buffer
* \param data The data to append
*/
template <typename T>
DataBuffer& operator<<(const std::unique_ptr<T>& data) {
return *this << *data;
}
/** /**
* \brief Append a vector to the buffer by first writing the size * \brief Append a vector to the buffer by first writing the size
* \param data The vector to append * \param data The vector to append
@@ -95,6 +115,19 @@ class DataBuffer {
return *this; return *this;
} }
/**
* \brief Append a list to the buffer by first writing the size
* \param data The list to append
*/
template <typename T>
DataBuffer& operator<<(const std::list<T>& data) {
*this << VarInt{data.size()};
for (const auto& element : data) {
*this << element;
}
return *this;
}
/** /**
* \brief Append a map to the buffer by first writing the size * \brief Append a map to the buffer by first writing the size
* \param data The map to append * \param data The map to append
@@ -102,12 +135,34 @@ class DataBuffer {
template <typename K, typename V> template <typename K, typename V>
DataBuffer& operator<<(const std::map<K, V>& data) { DataBuffer& operator<<(const std::map<K, V>& data) {
*this << VarInt{data.size()}; *this << VarInt{data.size()};
for (const auto& element : data) { for (const auto& [key, value] : data) {
*this << element.first << element.second; *this << key << value;
} }
return *this; return *this;
} }
/**
* \brief Append a map to the buffer by first writing the size
* \param data The map to append
*/
template <typename K, typename V>
DataBuffer& operator<<(const std::unordered_map<K, V>& data) {
*this << VarInt{data.size()};
for (const auto& [key, value] : data) {
*this << key << value;
}
return *this;
}
/**
* \brief Append a pair to the buffer
* \param data The pair to append
*/
template <typename K, typename V>
DataBuffer& operator<<(const std::pair<K, V>& data) {
return *this << data.first << data.second;
}
/** /**
* \brief Append an array to the buffer by first writing the size * \brief Append an array to the buffer by first writing the size
* \param data The buffer to append * \param data The buffer to append
@@ -154,6 +209,24 @@ class DataBuffer {
*/ */
DataBuffer& operator>>(std::string& str); DataBuffer& operator>>(std::string& str);
/**
* \brief Read a pointer
*/
template <typename T>
DataBuffer& operator>>(std::shared_ptr<T>& data) {
data = std::make_shared<T>();
return *this >> *data;
}
/**
* \brief Read a pointer
*/
template <typename T>
DataBuffer& operator>>(std::unique_ptr<T>& data) {
data = std::make_unique<T>();
return *this >> *data;
}
/** /**
* \brief Read a vector (size + data) from the buffer * \brief Read a vector (size + data) from the buffer
* \pre The vector is assumed to be empty * \pre The vector is assumed to be empty
@@ -170,6 +243,22 @@ class DataBuffer {
return *this; return *this;
} }
/**
* \brief Read a list (size + data) from the buffer
* \pre The list is assumed to be empty
*/
template <typename T>
DataBuffer& operator>>(std::list<T>& data) {
VarInt arraySize;
*this >> arraySize;
for (std::size_t i = 0; i < arraySize.GetValue(); i++) {
T newElement;
*this >> newElement;
data.push_back(newElement);
}
return *this;
}
/** /**
* \brief Read a map (size + data) from the buffer * \brief Read a map (size + data) from the buffer
* \pre The map is assumed to be empty * \pre The map is assumed to be empty
@@ -187,6 +276,31 @@ class DataBuffer {
return *this; return *this;
} }
/**
* \brief Read a map (size + data) from the buffer
* \pre The map is assumed to be empty
*/
template <typename K, typename V>
DataBuffer& operator>>(std::unordered_map<K, V>& data) {
VarInt mapSize;
*this >> mapSize;
for (std::size_t i = 0; i < mapSize.GetValue(); i++) {
K newKey;
V newValue;
*this >> newKey >> newValue;
data.emplace(newKey, newValue);
}
return *this;
}
/**
* \brief Read a pair
*/
template <typename K, typename V>
DataBuffer& operator>>(std::pair<K, V>& data) {
return *this >> data.first >> data.second;
}
/** /**
* \brief Read an array from the buffer * \brief Read an array from the buffer
*/ */

View File

@@ -13,7 +13,7 @@ class ConcreteMessage : public MessageBase {
using HandlerType = typename MessageBase::HandlerType; using HandlerType = typename MessageBase::HandlerType;
template <typename... T> template <typename... T>
ConcreteMessage(const T&... args) : m_Data{args...} {} ConcreteMessage(T&&... args) : m_Data{std::move(args)...} {}
virtual ~ConcreteMessage() {} virtual ~ConcreteMessage() {}

View File

@@ -24,11 +24,13 @@ using Message = sp::ConcreteMessage<TData, PacketBase, ID>;
struct KeepAlivePacket { struct KeepAlivePacket {
sp::BitField<std::uint16_t, 12> one; sp::BitField<std::uint16_t, 12> one;
sp::BitField<std::uint16_t, 4> two; sp::BitField<std::uint16_t, 4> two;
std::shared_ptr<std::string> test;
}; };
struct MDCPacket { struct MDCPacket {
sp::BitField<std::uint16_t, 12> one; sp::BitField<std::uint16_t, 12> one;
sp::BitField<PacketID, 4> two; sp::BitField<PacketID, 4> two;
std::unique_ptr<std::string> test;
}; };
using KeepAliveMessage = Message<KeepAlivePacket, PacketID::KeepAlive>; using KeepAliveMessage = Message<KeepAlivePacket, PacketID::KeepAlive>;
@@ -41,10 +43,10 @@ class PacketHandler : public sp::GenericHandler<AllMessages> {};
class MyHandler : public PacketHandler { class MyHandler : public PacketHandler {
public: public:
virtual void Handle(const KeepAliveMessage& msg) override { virtual void Handle(const KeepAliveMessage& msg) override {
std::cout << "I recieved a keep alive : " << *msg->one << " : " << *msg->two << "\n"; std::cout << "I recieved a keep alive : " << *msg->one << " : " << *msg->two << " : " << (msg->test ? *msg->test : "nullptr") << "\n";
} }
virtual void Handle(const MDCMessage& msg) override { virtual void Handle(const MDCMessage& msg) override {
std::cout << "I recieved a mdc : " << *msg->one << " : " << static_cast<unsigned>(*msg->two) << "\n"; std::cout << "I recieved a mdc : " << *msg->one << " : " << static_cast<unsigned>(*msg->two) << " : " << *msg->test << "\n";
} }
}; };
@@ -55,7 +57,7 @@ using PacketFactory = sp::MessageFactory<PacketBase, AllMessages>;
using PacketStream = sp::MessageStream<PacketFactory>; using PacketStream = sp::MessageStream<PacketFactory>;
int main() { int main() {
KeepAliveMessage m{69, 5}; KeepAliveMessage m{69, 5, std::make_shared<std::string>("I'm a keepalive")};
// dispatch tests // dispatch tests
@@ -79,7 +81,7 @@ int main() {
PacketStream p(std::make_shared<sp::StdOuput>(file)); PacketStream p(std::make_shared<sp::StdOuput>(file));
p.WriteMessage(m); p.WriteMessage(m);
p.WriteMessage(MDCMessage{42, PacketID::MDC}); p.WriteMessage(MDCMessage{42, PacketID::MDC, std::make_unique<std::string>("Coucou")});
file.flush(); file.flush();