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

Unified 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, 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/shared/serialization/build.scons ('k') | src/shared/serialization/serialization.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/shared/serialization/serialization.h
diff --git a/src/shared/serialization/serialization.h b/src/shared/serialization/serialization.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef420367e1d529915594270f2bb1b4b685f9e6c8
--- /dev/null
+++ b/src/shared/serialization/serialization.h
@@ -0,0 +1,523 @@
+/* -*- c++ -*- */
+/*
+ * Copyright (c) 2013 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
+#define NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
+
+#if defined(__native_client__) || NACL_LINUX
+# define NACL_HAS_IEEE_754
+// Make sure fp is not dead code and is tested. DO NOT USE the fp
+// interface until we have a portability version of ieee754.h!
+#endif
+
+#if defined(NACL_HAS_IEEE_754)
+# include <ieee754.h>
+#endif
+
+#include <vector>
+#include <string>
+
+#include "native_client/src/include/portability.h"
+#include "native_client/src/include/nacl_compiler_annotations.h"
+#include "native_client/src/shared/platform/nacl_check.h"
+
+// SerializationBuffer enables serializing basic types and vectors
+
+namespace nacl {
+
+class SerializationBuffer;
+
+template<typename T> class SerializationTraits;
+
+enum {
+ kIllegalTag = -1,
+
+ kUint8 = 0,
+ kInt8 = 1,
+ kUint16 = 2,
+ kInt16 = 3,
+ kUint32 = 4,
+ kInt32 = 5,
+ kUint64 = 6,
+ kInt64 = 7,
+
+#if defined(NACL_HAS_IEEE_754)
+ kFloat = 8,
+ kDouble = 9,
+ kLongDouble = 10,
+#endif
+
+ kCString = 11,
+ kString = 12,
+
+ kRecursiveVector = 31,
+ kVectorOffset = 32
+};
+
+class SerializationBuffer {
+ public:
+ SerializationBuffer();
+
+ // This initializes the Serialization buffer from |data_buffer|
+ // containing |nbytes| of data. A copy of the data is made rather
+ // than transferring ownership, which is suboptimal.
+ SerializationBuffer(uint8_t const *data_buffer, size_t nbytes);
+
+ template<typename T> bool Serialize(T basic) NACL_WUR;
+
+ template<typename T> bool Serialize(std::vector<T> const& v) NACL_WUR;
+
+ bool Serialize(char const *cstr) NACL_WUR;
+ bool Serialize(char const *cstr, size_t char_count) NACL_WUR;
+
+ bool Serialize(std::string str) NACL_WUR;
+
+ int ReadTag() {
+ if (bytes_unread() < kTagBytes) {
+ return kIllegalTag;
+ }
+ return buffer_[read_ix_++];
+ }
+
+ template<typename T> bool Deserialize(T *basic) NACL_WUR;
+
+ template<typename T> bool Deserialize(std::vector<T> *v) NACL_WUR;
+
+ // This function deserializes into the provided buffer at |cstr|.
+ // The parameter *buffer_size is an in-out parameter, initially
+ // containing the available space at |cstr|. If there are decoding
+ // errors, this function returns false. If it returns true, the
+ // caller should check *buffer_size -- if there were insufficient
+ // space, the read position is unchanged and *buffer_size is updated
+ // to reflect the amount of space that is required; otherwise
+ // *buffer_size is updated to reflect the actual number of bytes
+ // written to |cstr|.
+ bool Deserialize(char *cstr, size_t *buffer_size) NACL_WUR;
+ // caller provides buffer
+
+ // This method deserializes a NUL-terminated C-style string. The
+ // caller receives ownnership of the memory allocated via new[] and
+ // is responsible for delete[]ing it to release the storage.
+ bool Deserialize(char **cstr_out) NACL_WUR;
+
+ bool Deserialize(std::string *str) NACL_WUR;
+
+ size_t num_bytes() const {
+ return in_use_;
+ }
+
+ uint8_t const *data() const {
+ // return buffer_.data(); // C++11 only, not available on windows
+ return &buffer_[0];
+ }
+
+ void rewind() {
+ read_ix_ = 0;
+ }
+
+ void reset() {
+ in_use_ = 0;
+ buffer_.clear();
+ nbytes_ = 0;
+ read_ix_ = 0;
+ }
+
+ static const size_t kTagBytes = 1;
+
+ protected:
+ template<typename T> void AddTag();
+
+ template<typename T> bool CheckTag();
+
+ void AddUint8(uint8_t value);
+ void AddUint16(uint16_t value);
+ void AddUint32(uint32_t value);
+ void AddUint64(uint64_t value);
+#if defined(NACL_HAS_IEEE_754)
+ void AddFloat(float value);
+ void AddDouble(double value);
+ void AddLongDouble(long double value);
+#endif
+
+ bool GetUint8(uint8_t *val);
+ bool GetUint16(uint16_t *val);
+ bool GetUint32(uint32_t *val);
+ bool GetUint64(uint64_t *val);
+#if defined(NACL_HAS_IEEE_754)
+ bool GetFloat(float *value);
+ bool GetDouble(double *value);
+ bool GetLongDouble(long double *value);
+#endif
+
+ template<typename T> void AddVal(T value) {
+ int T_must_be_integral_type[static_cast<T>(1)];
+ UNREFERENCED_PARAMETER(T_must_be_integral_type);
+ if (sizeof(T) == 1) {
+ AddUint8(static_cast<uint8_t>(value));
+ } else if (sizeof(T) == 2) {
+ AddUint16(static_cast<uint16_t>(value));
+ } else if (sizeof(T) == 4) {
+ AddUint32(static_cast<uint32_t>(value));
+ } else if (sizeof(T) == 8) {
+ AddUint64(static_cast<uint64_t>(value));
+ }
+ }
+
+ template<typename T> bool GetVal(T *basic) {
+ int T_must_be_integral_type[static_cast<T>(1)];
+ UNREFERENCED_PARAMETER(T_must_be_integral_type);
+ if (sizeof(T) == 1) {
+ uint8_t val;
+ return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
+ } else if (sizeof(T) == 2) {
+ uint16_t val;
+ return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
+ } else if (sizeof(T) == 4) {
+ uint32_t val;
+ return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
+ } else if (sizeof(T) == 8) {
+ uint64_t val;
+ return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
+ }
+ return false;
+ }
+
+#if defined(NACL_HAS_IEEE_754)
+ void AddVal(float value) {
+ AddFloat(value);
+ }
+
+ bool GetVal(float *value) {
+ return GetFloat(value);
+ }
+
+ void AddVal(double value) {
+ AddDouble(value);
+ }
+
+ bool GetVal(double *value) {
+ return GetDouble(value);
+ }
+
+ void AddVal(long double value) {
+ AddLongDouble(value);
+ }
+
+ bool GetVal(long double *value) {
+ return GetLongDouble(value);
+ }
+#endif
+
+ template<typename T, bool nested_tagging>
+ bool Serialize(std::vector<T> const& v);
+
+ // Template metaprogramming to determine at compile time, based on
+ // whether the type T is a container type or not, whether to tag the
+ // elements with their own type tag, or to just write the elements
+ // sans type tag. For vector containers of simple types such as
+ // int8_t, tagging every byte is excessive overhead. NB: see the
+ // definition below of kTag for vectors.
+ template<typename T, bool nested_tagging> class SerializeHelper {
+ public:
+ static bool DoSerialize(SerializationBuffer *buf,
+ std::vector<T> const& v) {
+ size_t orig = buf->cur_write_pos();
+ size_t num_elt = v.size();
+ if (num_elt > ~(uint32_t) 0) {
+ return false;
+ }
+ buf->AddTag<std::vector<T> >();
+ buf->AddVal(static_cast<uint32_t>(num_elt));
+
+ for (size_t ix = 0; ix < v.size(); ++ix) {
+ if (!buf->Serialize(v[ix])) {
+ buf->reset_write_pos(orig);
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ template<typename T> class SerializeHelper<T, false> {
+ public:
+ static bool DoSerialize(SerializationBuffer *buf,
+ std::vector<T> const& v) {
+ size_t num_elt = v.size();
+ if (num_elt > ~(uint32_t) 0) {
+ return false;
+ }
+ buf->AddTag<std::vector<T> >();
+ buf->AddVal(static_cast<uint32_t>(num_elt));
+
+ for (size_t ix = 0; ix < v.size(); ++ix) {
+ buf->AddVal(v[ix]);
+ }
+ return true;
+ }
+ };
+
+ template<typename T, bool b> friend class SerializeHelper;
+
+ template<typename T, bool nested_tagging> class DeserializeHelper {
+ public:
+ static bool DoDeserialize(SerializationBuffer *buf,
+ std::vector<T> *v) {
+ size_t orig = buf->cur_read_pos();
+ if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
+ buf->reset_read_pos(orig);
+ return false;
+ }
+ uint32_t num_elt;
+ if (!buf->GetVal(&num_elt)) {
+ buf->reset_read_pos(orig);
+ return false;
+ }
+ for (size_t ix = 0; ix < num_elt; ++ix) {
+ T val;
+ if (!buf->Deserialize(&val)) {
+ buf->reset_read_pos(orig);
+ return false;
+ }
+ v->push_back(val);
+ }
+ return true;
+ }
+ };
+
+ template<typename T> class DeserializeHelper<T, false> {
+ public:
+ static bool DoDeserialize(SerializationBuffer *buf,
+ std::vector<T> *v) {
+ size_t orig = buf->cur_read_pos();
+ if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
+ buf->reset_read_pos(orig);
+ return false;
+ }
+ uint32_t num_elt;
+ if (!buf->GetVal(&num_elt)) {
+ buf->reset_read_pos(orig);
+ return false;
+ }
+ for (size_t ix = 0; ix < num_elt; ++ix) {
+ T val;
+ if (!buf->GetVal(&val)) {
+ buf->reset_read_pos(orig);
+ return false;
+ }
+ v->push_back(val);
+ }
+ return true;
+ }
+ };
+
+ template<typename T, bool b> friend class DeserializeHelper;
+
+ // TODO(bsy): consider doing something along the lines of
+ //
+ // template<typename T> Serialize(T stl_container) {
+ // AddTag<T>(); // how?
+ // for (T::const_iterator it = stl_container.begin();
+ // it != stl_container.end();
+ // ++it) {
+ // Serialize(*it);
+ // // Or AddVal, when SerializationTraits<T::value_type>::kNestedTag
+ // // is false.
+ // }
+ // }
+ //
+ // This means that the container type would probably be omitted or a
+ // generic stl_container type tag would be used -- or we'd have to
+ // enumerate all container types.
+
+ private:
+ std::vector<uint8_t> buffer_;
+ size_t nbytes_;
+ size_t in_use_;
+ size_t read_ix_;
+
+ void EnsureTotalSize(size_t req_size);
+ void EnsureAvailableSpace(size_t req_space);
+
+ size_t bytes_unread() const {
+ return in_use_ - read_ix_;
+ }
+
+ size_t cur_read_pos() const {
+ return read_ix_;
+ }
+
+ void reset_read_pos(size_t pos) {
+ read_ix_ = pos;
+ }
+
+ size_t cur_write_pos() const {
+ return in_use_;
+ }
+
+ void reset_write_pos(size_t pos) {
+ in_use_ = pos;
+ }
+};
+
+template<typename T> void SerializationBuffer::AddTag() {
+ AddUint8(SerializationTraits<T>::kTag);
+}
+
+template<typename T> bool SerializationBuffer::Serialize(T basic) {
+ AddTag<T>();
+ AddVal(basic);
+ return true;
+}
+
+template<typename T> bool SerializationBuffer::Serialize(
+ std::vector<T> const& v) {
+ return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
+ DoSerialize(this, v);
+}
+
+template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
+ size_t orig = cur_read_pos();
+ if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
+ return false;
+ }
+ uint8_t tag;
+ if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
+ reset_read_pos(orig);
+ return false;
+ }
+ // if BytesAvail >= tag + serialization_size
+ (void) GetVal(basic);
+ return true;
+}
+
+template<typename T> bool SerializationBuffer::Deserialize(
+ std::vector<T> *v) {
+ return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
+ DoDeserialize(this, v);
+}
+
+template<> class SerializationTraits<uint8_t> {
+ public:
+ static const int kTag = kUint8;
+ static const int kBytes = 1;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<int8_t> {
+ public:
+ static const int kTag = kInt8;
+ static const int kBytes = 1;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<uint16_t> {
+ public:
+ static const int kTag = kUint16;
+ static const int kBytes = 2;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<int16_t> {
+ public:
+ static const int kTag = kInt16;
+ static const int kBytes = 2;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<uint32_t> {
+ public:
+ static const int kTag = kUint32;
+ static const int kBytes = 4;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<int32_t> {
+ public:
+ static const int kTag = kInt32;
+ static const int kBytes = 4;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<uint64_t> {
+ public:
+ static const int kTag = kUint64;
+ static const int kBytes = 8;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<int64_t> {
+ public:
+ static const int kTag = kInt64;
+ static const int kBytes = 8;
+ static const bool kNestedTag = false;
+};
+
+#if defined(NACL_HAS_IEEE_754)
+template<> class SerializationTraits<float> {
+ public:
+ static const int kTag = kFloat;
+ static const int kBytes = 4;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<double> {
+ public:
+ static const int kTag = kDouble;
+ static const int kBytes = 8;
+ static const bool kNestedTag = false;
+};
+
+template<> class SerializationTraits<long double> {
+ public:
+ static const int kTag = kLongDouble;
+ static const int kBytes = 10;
+ static const bool kNestedTag = false;
+};
+#endif
+
+template<> class SerializationTraits<char *> {
+ public:
+ static const int kTag = kCString;
+ static const bool kNestedTag = true;
+};
+
+template<> class SerializationTraits<std::string> {
+ public:
+ static const int kTag = kString;
+ static const bool kNestedTag = true;
+};
+
+// We want the type tag for vector<T>, when the type T is a basic
+// type, to incorporate the type tag for T. This way, we do not tag
+// each vector element (see SerializeHelper etc above), and yet the
+// type information is present. When T is not a basic type (e.g., it
+// is a string, a vector<U>, or some other container to be added), we
+// don't want to just add the kVectorOffset to the type tag for T,
+// since deep nesting of containers could cause the tag to overflow.
+// Assuming that the type T nested containers are not empty, paying
+// the cost of tagging each element of the vector is not a huge
+// overhead.
+template<typename T> class SerializationTraits<std::vector<T> > {
+ private:
+ template<typename S, bool b> class RecursiveOrNotTag {
+ public:
+ static const int kVectorTag = kRecursiveVector;
+ };
+ template<typename S> class RecursiveOrNotTag<S, false> {
+ public:
+ static const int kVectorTag = kVectorOffset + SerializationTraits<S>::kTag;
+ };
+ public:
+ static const int kTag =
+ RecursiveOrNotTag<T, SerializationTraits<T>::kNestedTag>::kVectorTag;
+ static const bool kNestedTag = true;
+};
+
+} // namespace nacl
+
+#endif
« 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