]> Dogcows Code - chaz/yoink/blob - src/moof/packet.hh
begin cleaning up resource management
[chaz/yoink] / src / moof / packet.hh
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #ifndef _MOOF_PACKET_HH_
13 #define _MOOF_PACKET_HH_
14
15 /**
16 * \file packet.hh
17 * Classes for building and interpreting datagram packets.
18 */
19
20 #include <cstring>
21 #include <stdexcept>
22 #include <string>
23 #include <vector>
24
25
26 #ifndef PAGE_SIZE
27 #define PAGE_SIZE 4096
28 #endif
29
30
31 namespace moof {
32
33
34 /**
35 * Represents a packet of serialized variables ready for transfer over the
36 * network. This method is most suitable for representing datagram
37 * packets, but it may also be useful for seralizing data for persistent
38 * state storage. The semantics are similar to that of a FIFO queue or
39 * stream where packets are written and read by inserting and extracting
40 * variables to and from the packet, although the actual order of the
41 * variables in the buffer may be different. At any time, a pointer to a
42 * buffer and the size of the buffer can be retrieved. This class also
43 * handles endian differences by serializing variables in network byte
44 * order (big endian).
45 */
46 class packet
47 {
48 public:
49
50 /**
51 * Construct a packet with an initial capacity.
52 * \param capacity Initial capacity of the packet.
53 */
54 explicit packet(size_t size = PAGE_SIZE);
55
56 /**
57 * Construct a packet with some bytes from a buffer. The bytes will be
58 * copied into the packet, so you don't need to keep the original
59 * buffer.
60 * \param data The bytes.
61 * \param size The number of bytes.
62 */
63 packet(const char* data, size_t size);
64
65 /**
66 * Insert a variable into the packet, serializing it. This usually
67 * increases the size of the packet by the size of the data type.
68 * \param value The value to insert.
69 * \return This.
70 */
71 packet& operator << (bool value);
72 packet& operator << (int8_t value);
73 packet& operator << (int16_t value);
74 packet& operator << (int32_t value);
75 packet& operator << (int64_t value);
76 packet& operator << (uint8_t value);
77 packet& operator << (uint16_t value);
78 packet& operator << (uint32_t value);
79 packet& operator << (uint64_t value);
80 packet& operator << (float value);
81 packet& operator << (double value);
82
83 /**
84 * Write some bytes to the packet.
85 * \param bytes The bytes.
86 * \param size The number of bytes.
87 * \return The number of bytes actually written.
88 */
89 size_t write(const void* bytes, size_t size);
90
91
92 /**
93 * Extract a variable from the packet. This usually decreases the size
94 * of the packet by the size of the data type.
95 * \param value Reference to the variable to extract.
96 * \return This.
97 */
98 packet& operator >> (bool& value);
99 packet& operator >> (int8_t& value);
100 packet& operator >> (int16_t& value);
101 packet& operator >> (int32_t& value);
102 packet& operator >> (int64_t& value);
103 packet& operator >> (uint8_t& value);
104 packet& operator >> (uint16_t& value);
105 packet& operator >> (uint32_t& value);
106 packet& operator >> (uint64_t& value);
107 packet& operator >> (float& value);
108 packet& operator >> (double& value);
109
110 /**
111 * Read some bytes from the packet.
112 * \param bytes The buffer to hold the bytes read.
113 * \param size The size of the read buffer.
114 * \return The number of bytes actually read.
115 */
116 size_t read(void* bytes, size_t size);
117
118
119 /**
120 * Clear the contents of the packet, setting the size of the packet to
121 * zero.
122 */
123 void clear();
124
125
126 /**
127 * Save the current state internally, allowing it to be reverted to
128 * later using revert().
129 */
130 void save();
131
132 /**
133 * Revert the packet to a previously saved state, or to that state
134 * immediately after construction if none other state has been
135 * explicitly saved using save().
136 */
137 void revert();
138
139
140 /**
141 * Get a pointer to an internal structure holding the serialized bytes
142 * of the packet.
143 * \return The pointer.
144 */
145 const char* bytes() const
146 {
147 return buffer_ + state_.read_mark;
148 }
149
150 /**
151 * Get the size of the buffer holding the serialized bytes of the
152 * packet.
153 * \return The number of bytes.
154 */
155 size_t size() const
156 {
157 return state_.write_mark - state_.read_mark;
158 }
159
160
161 // The rest of this stuff is just to implement correct copy semantics.
162
163 packet(const packet& copy);
164 packet& operator = (const packet& copy);
165 ~packet();
166
167
168 private:
169
170 char* buffer_;
171 size_t size_;
172
173 struct state
174 {
175 size_t read_mark;
176 size_t read_bool_mark;
177 size_t read_bool_num;
178 size_t write_mark;
179 size_t write_bool_mark;
180 size_t write_bool_num;
181
182 state(size_t size = 0) :
183 read_mark(0),
184 read_bool_mark(0),
185 read_bool_num(0),
186 write_mark(size),
187 write_bool_mark(0),
188 write_bool_num(0) {}
189 };
190
191 state state_;
192 state saved_;
193 };
194
195
196 template <class T>
197 inline packet& operator << (packet& packet, const T& value)
198 {
199 value.pack(packet);
200 return packet;
201 }
202
203 template <class T>
204 inline packet& operator >> (packet& packet, T& value)
205 {
206 value.unpack(packet);
207 return packet;
208 }
209
210
211 inline packet& operator << (packet& packet, const char* value)
212 {
213 uint16_t length = strlen(value);
214 packet << length;
215 if (packet.write(value, length) != length)
216 {
217 throw std::length_error("out of memory");
218 }
219 return packet;
220 }
221
222 template <class T>
223 inline packet& operator << (packet& packet, const std::basic_string<T>& value)
224 {
225 packet << static_cast<uint16_t>(value.length());
226 size_t num_bytes = value.length() * sizeof(T);
227 if (packet.write(value.data(), num_bytes) != num_bytes)
228 {
229 throw std::length_error("out of memory");
230 }
231 return packet;
232 }
233
234 template <class T>
235 inline packet& operator >> (packet& packet, std::basic_string<T>& value)
236 {
237 uint16_t length = 0;
238 packet >> length;
239
240 T str[length];
241 size_t num_bytes = length * sizeof(T);
242 if (packet.read(str, num_bytes) != num_bytes)
243 {
244 throw std::out_of_range("end of packet");
245 }
246 value.assign(str, length);
247 return packet;
248 }
249
250
251 template <class T>
252 inline packet& operator << (packet& packet, const std::vector<T>& value)
253 {
254 packet << static_cast<uint16_t>(value.size());
255 typename std::vector<T>::const_iterator it;
256 for (it = value.begin(); it != value.end(); ++it)
257 {
258 packet << *it;
259 }
260 return packet;
261 }
262
263 template <class T>
264 inline packet& operator >> (packet& packet, std::vector<T>& value)
265 {
266 uint16_t size = 0;
267 packet >> size;
268
269 value.clear();
270 for (uint16_t i = 0; i < size; ++i)
271 {
272 T item;
273 packet >> item;
274 value.push_back(item);
275 }
276 return packet;
277 }
278
279
280 } // namespace moof
281
282 #endif // _MOOF_PACKET_HH_
283
This page took 0.040615 seconds and 4 git commands to generate.