/*] Copyright (c) 2009-2010, Charles McGarvey [************************** **] All rights reserved. * * vi:ts=4 sw=4 tw=75 * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * **************************************************************************/ /** * \file Packet.hh * Classes for building and interpreting datagram packets. */ #ifndef _MOOF_PACKET_HH_ #define _MOOF_PACKET_HH_ #include #include #include #include #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: /** * Construct a packet with an initial capacity. * \param capacity Initial capacity of the packet. */ explicit 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<<(int32_t value); Packet& operator<<(int64_t value); Packet& operator<<(uint8_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); /** * 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>>(int32_t& value); Packet& operator>>(int64_t& value); Packet& operator>>(uint8_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 + 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 mSize; size_t mR; size_t mW; size_t mOriginalW; size_t mBoolR; size_t mBoolW; size_t mBoolNumR; size_t mBoolNumW; }; inline Packet& operator<<(Packet& packet, const char* value) { uint16_t length = strlen(value); packet << length; if (packet.write(value, length) != length) { throw std::length_error("out of memory"); } return packet; } template inline Packet& operator<<(Packet& packet, const std::basic_string& value) { packet << static_cast(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 inline Packet& operator>>(Packet& packet, std::basic_string& value) { uint16_t length = 0; packet >> length; T str[length]; 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 inline Packet& operator<<(Packet& packet, const std::vector& value) { packet << static_cast(value.size()); typename std::vector::const_iterator it; for (it = value.begin(); it != value.end(); ++it) { packet << *it; } return packet; } template inline Packet& operator>>(Packet& packet, std::vector& value) { uint16_t size = 0; packet >> size; value.clear(); for (uint16_t i = 0; i < size; ++i) { T item; packet >> item; value.push_back(item); } return packet; } } // namespace Mf #endif // _MOOF_PACKET_HH_