*
**************************************************************************/
+/**
+ * \file Packet.hh
+ * Classes for building and interpreting datagram packets.
+ */
+
#ifndef _MOOF_PACKET_HH_
#define _MOOF_PACKET_HH_
#include <cstring>
+#include <stdexcept>
#include <string>
#include <vector>
namespace Mf {
+/**
+ * Represents a packet of serialized variables ready for transfer over the
+ * network. This method is most suitable for representing datagram
+ * packets, but it may also be useful for seralizing data for persistent
+ * state storage. The semantics are similar to that of a FIFO queue or
+ * stream where packets are written and read by inserting and extracting
+ * variables to and from the packet, although the actual order of the
+ * variables in the buffer may be different. At any time, a pointer to a
+ * buffer and the size of the buffer can be retrieved. This class also
+ * handles endian differences by serializing variables in network byte
+ * order (big endian).
+ */
class Packet
{
public:
+ /**
+ * Construct a packet with an initial capacity.
+ * \param capacity Initial capacity of the packet.
+ */
Packet(size_t size = PAGE_SIZE);
- Packet(const char* data, size_t size);
- ~Packet();
+ /**
+ * Construct a packet with some bytes from a buffer. The bytes will be
+ * copied into the packet, so you don't need to keep the original
+ * buffer.
+ * \param data The bytes.
+ * \param size The number of bytes.
+ */
+ Packet(const char* data, size_t size);
+ /**
+ * Insert a variable into the packet, serializing it. This usually
+ * increases the size of the packet by the size of the data type.
+ * \param value The value to insert.
+ * \return This.
+ */
Packet& operator<<(bool value);
Packet& operator<<(int8_t value);
Packet& operator<<(int16_t value);
Packet& operator<<(float value);
Packet& operator<<(double value);
+ /**
+ * Write some bytes to the packet.
+ * \param bytes The bytes.
+ * \param size The number of bytes.
+ * return The number of bytes actually written.
+ */
size_t write(const void* bytes, size_t size);
+
+ /**
+ * Extract a variable from the packet. This usually decreases the size
+ * of the packet by the size of the data type.
+ * \param value Reference to the variable to extract.
+ * \return This.
+ */
Packet& operator>>(bool& value);
Packet& operator>>(int8_t& value);
Packet& operator>>(int16_t& value);
Packet& operator>>(float& value);
Packet& operator>>(double& value);
+ /**
+ * Read some bytes from the packet.
+ * \param bytes The buffer to hold the bytes read.
+ * \param size The size of the read buffer.
+ * \return The number of bytes actually read.
+ */
size_t read(void* bytes, size_t size);
+ /**
+ * Clear the contents of the packet, setting the size of the packet to
+ * zero.
+ */
+ void clear();
+
+
+ /**
+ * Reset the read/write markers to their initial positions, putting the
+ * packet in the state it was at right after construction.
+ */
+ void reset();
+
+
+ /**
+ * Get a pointer to an internal structure holding the serialized bytes
+ * of the packet.
+ * return The pointer.
+ */
const char* bytes() const
{
return mBuffer + mR;
}
+ /**
+ * Get the size of the buffer holding the serialized bytes of the
+ * packet.
+ * \return The number of bytes.
+ */
size_t size() const
{
return mW - mR;
}
+ // The rest of this stuff is just to implement correct copy semantics.
+
+ Packet(const Packet& copy);
+ Packet& operator=(const Packet& copy);
+ ~Packet();
+
+
private:
char* mBuffer;
size_t mR;
size_t mW;
+ size_t mOriginalW;
size_t mBoolR;
size_t mBoolW;
{
uint16_t length = strlen(value);
packet << length;
- packet.write(value, length);
+ if (packet.write(value, length) != length)
+ {
+ throw std::length_error("out of memory");
+ }
return packet;
}
template <class T>
inline Packet& operator<<(Packet& packet, const std::basic_string<T>& value)
{
- packet << (uint16_t)value.length();
- packet.write(value.data(), value.length() * sizeof(T));
+ packet << static_cast<uint16_t>(value.length());
+ size_t numBytes = value.length() * sizeof(T);
+ if (packet.write(value.data(), numBytes) != numBytes)
+ {
+ throw std::length_error("out of memory");
+ }
return packet;
}
packet >> length;
T str[length];
- size_t charsRead = packet.read(str, length * sizeof(T));
- value.assign(str, charsRead);
+ size_t numBytes = length * sizeof(T);
+ if (packet.read(str, numBytes) != numBytes)
+ {
+ throw std::out_of_range("end of packet");
+ }
+ value.assign(str, length);
return packet;
}
template <class T>
inline Packet& operator<<(Packet& packet, const std::vector<T>& value)
{
- packet << (uint16_t)value.size();
+ packet << static_cast<uint16_t>(value.size());
typename std::vector<T>::const_iterator it;
for (it = value.begin(); it != value.end(); ++it)
{