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.
8 #ifndef NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
9 #define NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
14 #include "native_client/src/include/portability.h"
15 #include "native_client/src/include/nacl_compiler_annotations.h"
16 #include "native_client/src/shared/platform/nacl_check.h"
18 // SerializationBuffer enables serializing basic types and vectors
22 class SerializationBuffer;
24 template<typename T> class SerializationTraits;
41 kRecursiveVector = 31,
45 class SerializationBuffer {
47 SerializationBuffer();
49 // This initializes the Serialization buffer from |data_buffer|
50 // containing |nbytes| of data. A copy of the data is made rather
51 // than transferring ownership, which is suboptimal.
52 SerializationBuffer(uint8_t const *data_buffer, size_t nbytes);
54 template<typename T> bool Serialize(T basic) NACL_WUR;
56 template<typename T> bool Serialize(std::vector<T> const& v) NACL_WUR;
58 bool Serialize(char const *cstr) NACL_WUR;
59 bool Serialize(char const *cstr, size_t char_count) NACL_WUR;
61 bool Serialize(std::string str) NACL_WUR;
64 if (bytes_unread() < kTagBytes) {
67 return buffer_[read_ix_++];
70 template<typename T> bool Deserialize(T *basic) NACL_WUR;
72 template<typename T> bool Deserialize(std::vector<T> *v) NACL_WUR;
74 // This function deserializes into the provided buffer at |cstr|.
75 // The parameter *buffer_size is an in-out parameter, initially
76 // containing the available space at |cstr|. If there are decoding
77 // errors, this function returns false. If it returns true, the
78 // caller should check *buffer_size -- if there were insufficient
79 // space, the read position is unchanged and *buffer_size is updated
80 // to reflect the amount of space that is required; otherwise
81 // *buffer_size is updated to reflect the actual number of bytes
83 bool Deserialize(char *cstr, size_t *buffer_size) NACL_WUR;
84 // caller provides buffer
86 // This method deserializes a NUL-terminated C-style string. The
87 // caller receives ownnership of the memory allocated via new[] and
88 // is responsible for delete[]ing it to release the storage.
89 bool Deserialize(char **cstr_out) NACL_WUR;
91 bool Deserialize(std::string *str) NACL_WUR;
93 size_t num_bytes() const {
97 uint8_t const *data() const {
98 // return buffer_.data(); // C++11 only, not available on windows
113 static const size_t kTagBytes = 1;
116 template<typename T> void AddTag();
118 template<typename T> bool CheckTag();
120 void AddUint8(uint8_t value);
121 void AddUint16(uint16_t value);
122 void AddUint32(uint32_t value);
123 void AddUint64(uint64_t value);
125 bool GetUint8(uint8_t *val);
126 bool GetUint16(uint16_t *val);
127 bool GetUint32(uint32_t *val);
128 bool GetUint64(uint64_t *val);
130 template<typename T> void AddVal(T value) {
131 int T_must_be_integral_type[static_cast<T>(1)];
132 UNREFERENCED_PARAMETER(T_must_be_integral_type);
133 if (sizeof(T) == 1) {
134 AddUint8(static_cast<uint8_t>(value));
135 } else if (sizeof(T) == 2) {
136 AddUint16(static_cast<uint16_t>(value));
137 } else if (sizeof(T) == 4) {
138 AddUint32(static_cast<uint32_t>(value));
139 } else if (sizeof(T) == 8) {
140 AddUint64(static_cast<uint64_t>(value));
144 template<typename T> bool GetVal(T *basic) {
145 int T_must_be_integral_type[static_cast<T>(1)];
146 UNREFERENCED_PARAMETER(T_must_be_integral_type);
147 if (sizeof(T) == 1) {
149 return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
150 } else if (sizeof(T) == 2) {
152 return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
153 } else if (sizeof(T) == 4) {
155 return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
156 } else if (sizeof(T) == 8) {
158 return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
163 template<typename T, bool nested_tagging>
164 bool Serialize(std::vector<T> const& v);
166 // Template metaprogramming to determine at compile time, based on
167 // whether the type T is a container type or not, whether to tag the
168 // elements with their own type tag, or to just write the elements
169 // sans type tag. For vector containers of simple types such as
170 // int8_t, tagging every byte is excessive overhead. NB: see the
171 // definition below of kTag for vectors.
172 template<typename T, bool nested_tagging> class SerializeHelper {
174 static bool DoSerialize(SerializationBuffer *buf,
175 std::vector<T> const& v) {
176 size_t orig = buf->cur_write_pos();
177 size_t num_elt = v.size();
178 if (num_elt > ~(uint32_t) 0) {
181 buf->AddTag<std::vector<T> >();
182 buf->AddVal(static_cast<uint32_t>(num_elt));
184 for (size_t ix = 0; ix < v.size(); ++ix) {
185 if (!buf->Serialize(v[ix])) {
186 buf->reset_write_pos(orig);
194 template<typename T> class SerializeHelper<T, false> {
196 static bool DoSerialize(SerializationBuffer *buf,
197 std::vector<T> const& v) {
198 size_t num_elt = v.size();
199 if (num_elt > ~(uint32_t) 0) {
202 buf->AddTag<std::vector<T> >();
203 buf->AddVal(static_cast<uint32_t>(num_elt));
205 for (size_t ix = 0; ix < v.size(); ++ix) {
212 template<typename T, bool b> friend class SerializeHelper;
214 template<typename T, bool nested_tagging> class DeserializeHelper {
216 static bool DoDeserialize(SerializationBuffer *buf,
218 size_t orig = buf->cur_read_pos();
219 if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
220 buf->reset_read_pos(orig);
224 if (!buf->GetVal(&num_elt)) {
225 buf->reset_read_pos(orig);
228 for (size_t ix = 0; ix < num_elt; ++ix) {
230 if (!buf->Deserialize(&val)) {
231 buf->reset_read_pos(orig);
240 template<typename T> class DeserializeHelper<T, false> {
242 static bool DoDeserialize(SerializationBuffer *buf,
244 size_t orig = buf->cur_read_pos();
245 if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
246 buf->reset_read_pos(orig);
250 if (!buf->GetVal(&num_elt)) {
251 buf->reset_read_pos(orig);
254 for (size_t ix = 0; ix < num_elt; ++ix) {
256 if (!buf->GetVal(&val)) {
257 buf->reset_read_pos(orig);
266 template<typename T, bool b> friend class DeserializeHelper;
268 // TODO(bsy): consider doing something along the lines of
270 // template<typename T> Serialize(T stl_container) {
271 // AddTag<T>(); // how?
272 // for (T::const_iterator it = stl_container.begin();
273 // it != stl_container.end();
276 // // Or AddVal, when SerializationTraits<T::value_type>::kNestedTag
281 // This means that the container type would probably be omitted or a
282 // generic stl_container type tag would be used -- or we'd have to
283 // enumerate all container types.
286 std::vector<uint8_t> buffer_;
291 void EnsureTotalSize(size_t req_size);
292 void EnsureAvailableSpace(size_t req_space);
294 size_t bytes_unread() const {
295 return in_use_ - read_ix_;
298 size_t cur_read_pos() const {
302 void reset_read_pos(size_t pos) {
306 size_t cur_write_pos() const {
310 void reset_write_pos(size_t pos) {
315 template<typename T> void SerializationBuffer::AddTag() {
316 AddUint8(SerializationTraits<T>::kTag);
319 template<typename T> bool SerializationBuffer::Serialize(T basic) {
325 template<typename T> bool SerializationBuffer::Serialize(
326 std::vector<T> const& v) {
327 return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
328 DoSerialize(this, v);
331 template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
332 size_t orig = cur_read_pos();
333 if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
337 if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
338 reset_read_pos(orig);
341 // if BytesAvail >= tag + serialization_size
342 (void) GetVal(basic);
346 template<typename T> bool SerializationBuffer::Deserialize(
348 return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
349 DoDeserialize(this, v);
352 template<> class SerializationTraits<uint8_t> {
354 static const int kTag = kUint8;
355 static const int kBytes = 1;
356 static const bool kNestedTag = false;
359 template<> class SerializationTraits<int8_t> {
361 static const int kTag = kInt8;
362 static const int kBytes = 1;
363 static const bool kNestedTag = false;
366 template<> class SerializationTraits<uint16_t> {
368 static const int kTag = kUint16;
369 static const int kBytes = 2;
370 static const bool kNestedTag = false;
373 template<> class SerializationTraits<int16_t> {
375 static const int kTag = kInt16;
376 static const int kBytes = 2;
377 static const bool kNestedTag = false;
380 template<> class SerializationTraits<uint32_t> {
382 static const int kTag = kUint32;
383 static const int kBytes = 4;
384 static const bool kNestedTag = false;
387 template<> class SerializationTraits<int32_t> {
389 static const int kTag = kInt32;
390 static const int kBytes = 4;
391 static const bool kNestedTag = false;
394 template<> class SerializationTraits<uint64_t> {
396 static const int kTag = kUint64;
397 static const int kBytes = 8;
398 static const bool kNestedTag = false;
401 template<> class SerializationTraits<int64_t> {
403 static const int kTag = kInt64;
404 static const int kBytes = 8;
405 static const bool kNestedTag = false;
408 template<> class SerializationTraits<char *> {
410 static const int kTag = kCString;
411 static const bool kNestedTag = true;
414 template<> class SerializationTraits<std::string> {
416 static const int kTag = kString;
417 static const bool kNestedTag = true;
420 // We want the type tag for vector<T>, when the type T is a basic
421 // type, to incorporate the type tag for T. This way, we do not tag
422 // each vector element (see SerializeHelper etc above), and yet the
423 // type information is present. When T is not a basic type (e.g., it
424 // is a string, a vector<U>, or some other container to be added), we
425 // don't want to just add the kVectorOffset to the type tag for T,
426 // since deep nesting of containers could cause the tag to overflow.
427 // Assuming that the type T nested containers are not empty, paying
428 // the cost of tagging each element of the vector is not a huge
430 template<typename T> class SerializationTraits<std::vector<T> > {
432 template<typename S, bool b> class RecursiveOrNotTag {
434 static const int kVectorTag = kRecursiveVector;
436 template<typename S> class RecursiveOrNotTag<S, false> {
438 static const int kVectorTag = kVectorOffset + SerializationTraits<S>::kTag;
441 static const int kTag =
442 RecursiveOrNotTag<T, SerializationTraits<T>::kNestedTag>::kVectorTag;
443 static const bool kNestedTag = true;