Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |