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

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

Powered by Google App Engine
This is Rietveld 408576698