*
**************************************************************************/
+/**
+ * \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>
-#include <boost/shared_array.hpp>
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
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:
- Packet(size_t size = 1024);
+ /**
+ * Construct a packet with an initial capacity.
+ * \param capacity Initial capacity of the packet.
+ */
+ Packet(size_t size = PAGE_SIZE);
+
+ /**
+ * 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<<(uint16_t value);
Packet& operator<<(uint32_t value);
Packet& operator<<(uint64_t value);
- //Packet& operator<<(float value);
- //Packet& operator<<(double value);
- //Packet& operator<<(long double 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>>(uint16_t& value);
Packet& operator>>(uint32_t& value);
Packet& operator>>(uint64_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.get()[mR];
+ 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:
- boost::shared_array<char> mBuffer;
- size_t mSize;
+ char* mBuffer;
+ size_t mSize;
- size_t mR;
- size_t mW;
+ size_t mR;
+ size_t mW;
+ size_t mOriginalW;
- size_t mBoolR;
- size_t mBoolW;
- size_t mBoolNumR;
- size_t mBoolNumW;
+ size_t mBoolR;
+ size_t mBoolW;
+ size_t mBoolNumR;
+ size_t mBoolNumW;
};
inline Packet& operator<<(Packet& packet, const char* value)
{
- uint8_t length = strnlen(value, 255);
+ 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;
}
-inline Packet& operator<<(Packet& packet, const std::string& value)
+template <class T>
+inline Packet& operator<<(Packet& packet, const std::basic_string<T>& value)
{
- packet << (uint8_t)value.length();
- packet.write(value.c_str(), value.length());
+ 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;
}
template <class T>
-inline Packet& operator<<(Packet& packet, const std::vector<T>& value)
+inline Packet& operator>>(Packet& packet, std::basic_string<T>& value)
{
- packet << (uint8_t)value.size();
- typename std::vector<T>::const_iterator it;
- for (it = value.begin(); it != value.end(); ++it)
+ uint16_t length = 0;
+ packet >> length;
+
+ T str[length];
+ size_t numBytes = length * sizeof(T);
+ if (packet.read(str, numBytes) != numBytes)
{
- packet << *it;
+ throw std::out_of_range("end of packet");
}
+ value.assign(str, length);
return packet;
}
-inline Packet& operator>>(Packet& packet, std::string& value)
+template <class T>
+inline Packet& operator<<(Packet& packet, const std::vector<T>& value)
{
- uint8_t length = 0;
- packet >> length;
-
- char str[256];
- size_t charsRead = packet.read(str, length);
- value.assign(str, charsRead);
+ packet << static_cast<uint16_t>(value.size());
+ typename std::vector<T>::const_iterator it;
+ for (it = value.begin(); it != value.end(); ++it)
+ {
+ packet << *it;
+ }
return packet;
}
template <class T>
inline Packet& operator>>(Packet& packet, std::vector<T>& value)
{
- uint8_t size = 0;
+ uint16_t size = 0;
packet >> size;
value.clear();
- for (uint8_t i = 0; i < size; ++i)
+ for (uint16_t i = 0; i < size; ++i)
{
T item;
packet >> item;
}
-
} // namespace Mf
#endif // _MOOF_PACKET_HH_