]> Dogcows Code - chaz/yoink/blobdiff - src/moof/packet.hh
the massive refactoring effort
[chaz/yoink] / src / moof / packet.hh
diff --git a/src/moof/packet.hh b/src/moof/packet.hh
new file mode 100644 (file)
index 0000000..03c519f
--- /dev/null
@@ -0,0 +1,283 @@
+
+/*]  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.
+*
+**************************************************************************/
+
+#ifndef _MOOF_PACKET_HH_
+#define _MOOF_PACKET_HH_
+
+/**
+ * \file packet.hh
+ * Classes for building and interpreting datagram packets.
+ */
+
+#include <cstring>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+
+namespace moof {
+       
+
+/**
+ * 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();
+
+
+       /**
+        * Save the current state internally, allowing it to be reverted to
+        * later using revert().
+        */
+       void save();
+
+       /**
+        * Revert the packet to a previously saved state, or to that state
+        * immediately after construction if none other state has been
+        * explicitly saved using save().
+        */
+       void revert();
+
+
+       /**
+        * Get a pointer to an internal structure holding the serialized bytes
+        * of the packet.
+        * return The pointer.
+        */
+       const char* bytes() const
+       {
+               return buffer_ + state_.read_mark;
+       }
+
+       /**
+        * Get the size of the buffer holding the serialized bytes of the
+        * packet.
+        * \return The number of bytes.
+        */
+       size_t size() const
+       {
+               return state_.write_mark - state_.read_mark;
+       }
+
+
+       // The rest of this stuff is just to implement correct copy semantics.
+
+       packet(const packet& copy);
+       packet& operator = (const packet& copy);
+       ~packet();
+
+
+private:
+
+       char*   buffer_;
+       size_t  size_;
+
+       struct state
+       {
+               size_t read_mark;
+               size_t read_bool_mark;
+               size_t read_bool_num;
+               size_t write_mark;
+               size_t write_bool_mark;
+               size_t write_bool_num;
+
+               state(size_t size = 0) :
+                       read_mark(0),
+                       read_bool_mark(0),
+                       read_bool_num(0),
+                       write_mark(size),
+                       write_bool_mark(0),
+                       write_bool_num(0) {}
+       };
+
+       state   state_;
+       state   saved_;
+};
+
+
+template <class T>
+inline packet& operator << (packet& packet, const T& value)
+{
+       value.pack(packet);
+       return packet;
+}
+
+template <class T>
+inline packet& operator >> (packet& packet, T& value)
+{
+       value.unpack(packet);
+       return packet;
+}
+
+
+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 <class T>
+inline packet& operator << (packet& packet, const std::basic_string<T>& value)
+{
+       packet << static_cast<uint16_t>(value.length());
+       size_t num_bytes = value.length() * sizeof(T);
+       if (packet.write(value.data(), num_bytes) != num_bytes)
+       {
+               throw std::length_error("out of memory");
+       }
+       return packet;
+}
+
+template <class T>
+inline packet& operator >> (packet& packet, std::basic_string<T>& value)
+{
+       uint16_t length = 0;
+       packet >> length;
+
+       T str[length];
+       size_t num_bytes = length * sizeof(T);
+       if (packet.read(str, num_bytes) != num_bytes)
+       {
+               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 << 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)
+{
+       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 moof
+
+#endif // _MOOF_PACKET_HH_
+
This page took 0.024907 seconds and 4 git commands to generate.