Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: src/shared/serialization/serialization.h

Issue 12316093: Serialization library. Useful for sending more complex data in RPCs. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: fixed conditional compilation control for fp support Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /* -*- c++ -*- */
2 /*
3 * Copyright (c) 2013 The Native Client Authors. All rights reserved.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #ifndef NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
9 #define NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
10
11 #if defined(__native_client__) || NACL_LINUX
12 # define NACL_HAS_IEEE_754
13 // Make sure fp is not dead code and is tested. DO NOT USE the fp
14 // interface until we have a portability version of ieee754.h!
15 #endif
16
17 #if defined(NACL_HAS_IEEE_754)
18 # include <ieee754.h>
19 #endif
20
21 #include <vector>
22 #include <string>
23
24 #include "native_client/src/include/portability.h"
25 #include "native_client/src/shared/platform/nacl_check.h"
26
27 // SerializationBuffer enables serializing basic types and vectors
28
29 namespace nacl {
30
31 class SerializationBuffer;
32
33 template<typename T> class SerializationTraits;
34
35 enum {
36 kIllegalTag = -1,
37
38 kUint8 = 0,
39 kInt8 = 1,
40 kUint16 = 2,
41 kInt16 = 3,
42 kUint32 = 4,
43 kInt32 = 5,
44 kUint64 = 6,
45 kInt64 = 7,
46
47 #if defined(NACL_HAS_IEEE_754)
48 kFloat = 8,
49 kDouble = 9,
50 kLongDouble = 10,
51 #endif
52
53 kCString = 11,
54 kString = 12,
55
56 kRecursiveVector = 31,
57 kVectorOffset = 32
58 };
59
60 class SerializationBuffer {
61 public:
62 SerializationBuffer();
63
64 // This passes initializes the Serialization buffer from
sehr 2013/02/26 00:57:58 s/passes //
bsy 2013/02/26 01:05:01 Done.
65 // |data_buffer| containing |nbytes| of data. A copy of the data is
66 // made rather than transferring ownership, which is suboptimal.
67 SerializationBuffer(uint8_t const *data_buffer, size_t nbytes);
68
69 template<typename T> bool Serialize(T basic);
70
71 template<typename T> bool Serialize(std::vector<T> const& v);
72
73 bool Serialize(char const *cstr);
74 bool Serialize(char const *cstr, size_t char_count);
75
76 bool Serialize(std::string str);
77
78 int ReadTag() {
79 if (bytes_unread() < 1) {
sehr 2013/02/26 00:57:58 kTagBytes rather than 1.
bsy 2013/02/26 01:05:01 Done.
80 return kIllegalTag;
81 }
82 return buffer_[read_ix_++];
83 }
84
85 template<typename T> bool Deserialize(T *basic);
86
87 template<typename T> bool Deserialize(std::vector<T> *v);
88
89 // This function deserializes into the provided buffer at |cstr|.
90 // The parameter *buffer_size is an in-out parameter, initially
91 // containing the available space at |cstr|. If there are decoding
92 // errors, this function returns false. If it returns true, the
93 // caller should check *buffer_size -- if there were insufficient
94 // space, the read position is unchanged and *buffer_size is updated
95 // to reflect the amount of space that is required; otherwise
96 // *buffer_size is updated to reflect the actual number of bytes
97 // written to |cstr|.
98 bool Deserialize(char *cstr, size_t *buffer_size); // caller provides buffer
99
100 // This method deserializes a NUL-terminated C-style string. The
101 // caller receives ownnership of the memory allocated via new[] and
102 // is responsible for delete[]ing it to release the storage.
103 bool Deserialize(char **cstr_out);
104
105 bool Deserialize(std::string *str);
106
107 size_t num_bytes() const {
108 return in_use_;
109 }
110
111 uint8_t const *data() const {
112 // return buffer_.data(); // C++11 only, not available on windows
113 return &buffer_[0];
114 }
115
116 void rewind() {
117 read_ix_ = 0;
118 }
119
120 void reset() {
121 in_use_ = 0;
122 buffer_.clear();
123 nbytes_ = 0;
124 read_ix_ = 0;
125 }
126
127 static const int kTagBytes = 1;
128
129 protected:
130 template<typename T> void AddTag();
131
132 template<typename T> bool CheckTag();
133
134 void AddUint8(uint8_t value);
135 void AddUint16(uint16_t value);
136 void AddUint32(uint32_t value);
137 void AddUint64(uint64_t value);
138 #if defined(NACL_HAS_IEEE_754)
139 void AddFloat(float value);
140 void AddDouble(double value);
141 void AddLongDouble(long double value);
142 #endif
143
144 bool GetUint8(uint8_t *val);
145 bool GetUint16(uint16_t *val);
146 bool GetUint32(uint32_t *val);
147 bool GetUint64(uint64_t *val);
148 #if defined(NACL_HAS_IEEE_754)
149 bool GetFloat(float *value);
150 bool GetDouble(double *value);
151 bool GetLongDouble(long double *value);
152 #endif
153
154 template<typename T> void AddVal(T value) {
155 int T_must_be_integral_type[static_cast<T>(1)];
156 UNREFERENCED_PARAMETER(T_must_be_integral_type);
157 if (sizeof(T) == 1) {
158 AddUint8(static_cast<uint8_t>(value));
159 } else if (sizeof(T) == 2) {
160 AddUint16(static_cast<uint16_t>(value));
161 } else if (sizeof(T) == 4) {
162 AddUint32(static_cast<uint32_t>(value));
163 } else if (sizeof(T) == 8) {
164 AddUint64(static_cast<uint64_t>(value));
165 }
166 }
167
168 template<typename T> bool GetVal(T *basic) {
169 int T_must_be_integral_type[static_cast<T>(1)];
170 UNREFERENCED_PARAMETER(T_must_be_integral_type);
171 if (sizeof(T) == 1) {
172 uint8_t val;
173 return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
174 } else if (sizeof(T) == 2) {
175 uint16_t val;
176 return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
177 } else if (sizeof(T) == 4) {
178 uint32_t val;
179 return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
180 } else if (sizeof(T) == 8) {
181 uint64_t val;
182 return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
183 }
184 return false;
185 }
186
187 #if defined(NACL_HAS_IEEE_754)
188 void AddVal(float value) {
189 AddFloat(value);
190 }
191
192 bool GetVal(float *value) {
193 return GetFloat(value);
194 }
195
196 void AddVal(double value) {
197 AddDouble(value);
198 }
199
200 bool GetVal(double *value) {
201 return GetDouble(value);
202 }
203
204 void AddVal(long double value) {
205 AddLongDouble(value);
206 }
207
208 bool GetVal(long double *value) {
209 return GetLongDouble(value);
210 }
211 #endif
212
213 template<typename T, bool nested_tagging>
214 bool Serialize(std::vector<T> const& v);
215
216 // Template metaprogramming to determine at compile time, based on
217 // whether the type T is a container type or not, whether to tag the
218 // elements with their own type tag, or to just write the elements
219 // sans type tag. For vector containers of simple types such as
220 // int8_t, tagging every byte is excessive overhead. NB: see the
221 // definition below of kTag for vectors.
222 template<typename T, bool nested_tagging> class SerializeHelper {
223 public:
224 static bool DoSerialize(SerializationBuffer *buf,
225 std::vector<T> const& v) {
226 size_t orig = buf->cur_write_pos();
227 size_t num_elt = v.size();
228 if (num_elt > ~(uint32_t) 0) {
229 return false;
230 }
231 buf->AddTag<std::vector<T> >();
232 buf->AddVal(static_cast<uint32_t>(num_elt));
233
234 for (size_t ix = 0; ix < v.size(); ++ix) {
235 if (!buf->Serialize(v[ix])) {
236 buf->reset_write_pos(orig);
237 return false;
238 }
239 }
240 return true;
241 }
242 };
243
244 template<typename T> class SerializeHelper<T, false> {
245 public:
246 static bool DoSerialize(SerializationBuffer *buf,
247 std::vector<T> const& v) {
248 size_t num_elt = v.size();
249 if (num_elt > ~(uint32_t) 0) {
250 return false;
251 }
252 buf->AddTag<std::vector<T> >();
253 buf->AddVal(static_cast<uint32_t>(num_elt));
254
255 for (size_t ix = 0; ix < v.size(); ++ix) {
256 buf->AddVal(v[ix]);
257 }
258 return true;
259 }
260 };
261
262 template<typename T, bool b> friend class SerializeHelper;
263
264 template<typename T, bool nested_tagging> class DeserializeHelper {
265 public:
266 static bool DoDeserialize(SerializationBuffer *buf,
267 std::vector<T> *v) {
268 size_t orig = buf->cur_read_pos();
269 if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
270 buf->reset_read_pos(orig);
271 return false;
272 }
273 uint32_t num_elt;
274 if (!buf->GetVal(&num_elt)) {
275 buf->reset_read_pos(orig);
276 return false;
277 }
278 for (size_t ix = 0; ix < num_elt; ++ix) {
279 T val;
280 if (!buf->Deserialize(&val)) {
281 buf->reset_read_pos(orig);
282 return false;
283 }
284 v->push_back(val);
285 }
286 return true;
287 }
288 };
289
290 template<typename T> class DeserializeHelper<T, false> {
291 public:
292 static bool DoDeserialize(SerializationBuffer *buf,
293 std::vector<T> *v) {
294 size_t orig = buf->cur_read_pos();
295 if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
296 buf->reset_read_pos(orig);
297 return false;
298 }
299 uint32_t num_elt;
300 if (!buf->GetVal(&num_elt)) {
301 buf->reset_read_pos(orig);
302 return false;
303 }
304 for (size_t ix = 0; ix < num_elt; ++ix) {
305 T val;
306 if (!buf->GetVal(&val)) {
307 buf->reset_read_pos(orig);
308 return false;
309 }
310 v->push_back(val);
311 }
312 return true;
313 }
314 };
315
316 template<typename T, bool b> friend class DeserializeHelper;
317
318 // TODO(bsy): consider doing something along the lines of
319 //
320 // template<typename T> Serialize(T stl_container) {
321 // AddTag<T>(); // how?
322 // for (T::const_iterator it = stl_container.begin();
323 // it != stl_container.end();
324 // ++it) {
325 // Serialize(*it);
326 // // Or AddVal, when SerializationTraits<T::value_type>::kNestedTag
327 // // is false.
328 // }
329 // }
330 //
331 // This means that the container type would probably be omitted or a
332 // generic stl_container type tag would be used -- or we'd have to
333 // enumerate all container types.
334
335 private:
336 std::vector<uint8_t> buffer_;
337 size_t nbytes_;
338 size_t in_use_;
339 size_t read_ix_;
340
341 void EnsureTotalSize(size_t req_size);
342 void EnsureAvailableSpace(size_t req_space);
343
344 size_t bytes_unread() const {
345 return in_use_ - read_ix_;
346 }
347
348 size_t cur_read_pos() const {
349 return read_ix_;
350 }
351
352 void reset_read_pos(size_t pos) {
353 read_ix_ = pos;
354 }
355
356 size_t cur_write_pos() const {
357 return in_use_;
358 }
359
360 void reset_write_pos(size_t pos) {
361 in_use_ = pos;
362 }
363 };
364
365 template<typename T> void SerializationBuffer::AddTag() {
366 AddUint8(SerializationTraits<T>::kTag);
367 }
368
369 template<typename T> bool SerializationBuffer::Serialize(T basic) {
370 AddTag<T>();
371 AddVal(basic);
372 return true;
373 }
374
375 template<typename T> bool SerializationBuffer::Serialize(
376 std::vector<T> const& v) {
377 return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
378 DoSerialize(this, v);
379 }
380
381 template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
382 size_t orig = cur_read_pos();
383 if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
384 return false;
385 }
386 uint8_t tag;
387 if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
388 reset_read_pos(orig);
389 return false;
390 }
391 // if BytesAvail >= tag + serialization_size
392 (void) GetVal(basic);
393 return true;
394 }
395
396 template<typename T> bool SerializationBuffer::Deserialize(
397 std::vector<T> *v) {
398 return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
399 DoDeserialize(this, v);
400 }
401
402 template<> class SerializationTraits<uint8_t> {
403 public:
404 static const int kTag = kUint8;
405 static const int kBytes = 1;
406 static const bool kNestedTag = false;
407 };
408
409 template<> class SerializationTraits<int8_t> {
410 public:
411 static const int kTag = kInt8;
412 static const int kBytes = 1;
413 static const bool kNestedTag = false;
414 };
415
416 template<> class SerializationTraits<uint16_t> {
417 public:
418 static const int kTag = kUint16;
419 static const int kBytes = 2;
420 static const bool kNestedTag = false;
421 };
422
423 template<> class SerializationTraits<int16_t> {
424 public:
425 static const int kTag = kInt16;
426 static const int kBytes = 2;
427 static const bool kNestedTag = false;
428 };
429
430 template<> class SerializationTraits<uint32_t> {
431 public:
432 static const int kTag = kUint32;
433 static const int kBytes = 4;
434 static const bool kNestedTag = false;
435 };
436
437 template<> class SerializationTraits<int32_t> {
438 public:
439 static const int kTag = kInt32;
440 static const int kBytes = 4;
441 static const bool kNestedTag = false;
442 };
443
444 template<> class SerializationTraits<uint64_t> {
445 public:
446 static const int kTag = kUint64;
447 static const int kBytes = 8;
448 static const bool kNestedTag = false;
449 };
450
451 template<> class SerializationTraits<int64_t> {
452 public:
453 static const int kTag = kInt64;
454 static const int kBytes = 8;
455 static const bool kNestedTag = false;
456 };
457
458 #if defined(NACL_HAS_IEEE_754)
459 template<> class SerializationTraits<float> {
460 public:
461 static const int kTag = kFloat;
462 static const int kBytes = 4;
463 static const bool kNestedTag = false;
464 };
465
466 template<> class SerializationTraits<double> {
467 public:
468 static const int kTag = kDouble;
469 static const int kBytes = 8;
470 static const bool kNestedTag = false;
471 };
472
473 template<> class SerializationTraits<long double> {
474 public:
475 static const int kTag = kLongDouble;
476 static const int kBytes = 10;
477 static const bool kNestedTag = false;
478 };
479 #endif
480
481 template<> class SerializationTraits<char *> {
482 public:
483 static const int kTag = kCString;
484 static const bool kNestedTag = true;
485 };
486
487 template<> class SerializationTraits<std::string> {
488 public:
489 static const int kTag = kString;
490 static const bool kNestedTag = true;
491 };
492
493 // We want the type tag for vector<T>, when the type T is a basic
494 // type, to incorporate the type tag for T. This way, we do not tag
495 // each vector element (see SerializeHelper etc above), and yet the
496 // type information is present. When T is not a basic type (e.g., it
497 // is a string, a vector<U>, or some other container to be added), we
498 // don't want to just add the kVectorOffset to the type tag for T,
499 // since deep nesting of containers could cause the tag to overflow.
500 // Assuming that the type T nested containers are not empty, paying
501 // the cost of tagging each element of the vector is not a huge
502 // overhead.
503 template<typename T> class SerializationTraits<std::vector<T> > {
504 private:
505 template<typename S, bool b> class RecursiveOrNotTag {
506 public:
507 static const int kVectorTag = kRecursiveVector;
508 };
509 template<typename S> class RecursiveOrNotTag<S, false> {
510 public:
511 static const int kVectorTag = kVectorOffset + SerializationTraits<S>::kTag;
512 };
513 public:
514 static const int kTag =
515 RecursiveOrNotTag<T, SerializationTraits<T>::kNestedTag>::kVectorTag;
516 static const bool kNestedTag = true;
517 };
518
519 } // namespace nacl
520
521 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698