1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ 32 #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ 33 34 #include <assert.h> 35 #include <google/protobuf/map_type_handler.h> 36 #include <google/protobuf/wire_format_lite_inl.h> 37 38 namespace google { 39 namespace protobuf { 40 class Arena; 41 namespace internal { 42 template <typename Key, typename Value, 43 WireFormatLite::FieldType kKeyFieldType, 44 WireFormatLite::FieldType kValueFieldType, 45 int default_enum_value> 46 class MapEntry; 47 template <typename Key, typename Value, 48 WireFormatLite::FieldType kKeyFieldType, 49 WireFormatLite::FieldType kValueFieldType, 50 int default_enum_value> 51 class MapFieldLite; 52 } // namespace internal 53 } // namespace protobuf 54 55 namespace protobuf { 56 namespace internal { 57 58 // MoveHelper::Move is used to set *dest. It copies *src, or moves it (in 59 // the C++11 sense), or swaps it. *src is left in a sane state for 60 // subsequent destruction, but shouldn't be used for anything. 61 template <bool is_enum, bool is_message, bool is_stringlike, typename T> 62 struct MoveHelper { // primitives MoveMoveHelper63 static void Move(T* src, T* dest) { *dest = *src; } 64 }; 65 66 template <bool is_message, bool is_stringlike, typename T> 67 struct MoveHelper<true, is_message, is_stringlike, T> { // enums 68 static void Move(T* src, T* dest) { *dest = *src; } 69 // T is an enum here, so allow conversions to and from int. 70 static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); } 71 static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); } 72 }; 73 74 template <bool is_stringlike, typename T> 75 struct MoveHelper<false, true, is_stringlike, T> { // messages 76 static void Move(T* src, T* dest) { dest->Swap(src); } 77 }; 78 79 template <typename T> 80 struct MoveHelper<false, false, true, T> { // strings and similar 81 static void Move(T* src, T* dest) { 82 #if __cplusplus >= 201103L 83 *dest = std::move(*src); 84 #else 85 dest->swap(*src); 86 #endif 87 } 88 }; 89 90 // MapEntryLite is used to implement parsing and serialization of map for lite 91 // runtime. 92 template <typename Key, typename Value, 93 WireFormatLite::FieldType kKeyFieldType, 94 WireFormatLite::FieldType kValueFieldType, 95 int default_enum_value> 96 class MapEntryLite : public MessageLite { 97 // Provide utilities to parse/serialize key/value. Provide utilities to 98 // manipulate internal stored type. 99 typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; 100 typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler; 101 102 // Define internal memory layout. Strings and messages are stored as 103 // pointers, while other types are stored as values. 104 typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory; 105 typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory; 106 107 // Enum type cannot be used for MapTypeHandler::Read. Define a type 108 // which will replace Enum with int. 109 typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType; 110 typedef typename ValueTypeHandler::MapEntryAccessorType 111 ValueMapEntryAccessorType; 112 113 // Constants for field number. 114 static const int kKeyFieldNumber = 1; 115 static const int kValueFieldNumber = 2; 116 117 // Constants for field tag. 118 static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( 119 kKeyFieldNumber, KeyTypeHandler::kWireType); 120 static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( 121 kValueFieldNumber, ValueTypeHandler::kWireType); 122 static const int kTagSize = 1; 123 124 public: 125 ~MapEntryLite() { 126 if (this != default_instance_) { 127 if (GetArenaNoVirtual() != NULL) return; 128 KeyTypeHandler::DeleteNoArena(key_); 129 ValueTypeHandler::DeleteNoArena(value_); 130 } 131 } 132 133 // accessors ====================================================== 134 135 virtual inline const KeyMapEntryAccessorType& key() const { 136 return KeyTypeHandler::GetExternalReference(key_); 137 } 138 virtual inline const ValueMapEntryAccessorType& value() const { 139 GOOGLE_CHECK(default_instance_ != NULL); 140 return ValueTypeHandler::DefaultIfNotInitialized(value_, 141 default_instance_->value_); 142 } 143 inline KeyMapEntryAccessorType* mutable_key() { 144 set_has_key(); 145 return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual()); 146 } 147 inline ValueMapEntryAccessorType* mutable_value() { 148 set_has_value(); 149 return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual()); 150 } 151 152 // implements MessageLite ========================================= 153 154 // MapEntryLite is for implementation only and this function isn't called 155 // anywhere. Just provide a fake implementation here for MessageLite. 156 string GetTypeName() const { return ""; } 157 158 void CheckTypeAndMergeFrom(const MessageLite& other) { 159 MergeFrom(*::google::protobuf::down_cast<const MapEntryLite*>(&other)); 160 } 161 162 bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) { 163 uint32 tag; 164 165 for (;;) { 166 // 1) corrupted data: return false; 167 // 2) unknown field: skip without putting into unknown field set; 168 // 3) unknown enum value: keep it in parsing. In proto2, caller should 169 // check the value and put this entry into containing message's unknown 170 // field set if the value is an unknown enum. In proto3, caller doesn't 171 // need to care whether the value is unknown enum; 172 // 4) missing key/value: missed key/value will have default value. caller 173 // should take this entry as if key/value is set to default value. 174 tag = input->ReadTag(); 175 switch (tag) { 176 case kKeyTag: 177 if (!KeyTypeHandler::Read(input, mutable_key())) { 178 return false; 179 } 180 set_has_key(); 181 if (!input->ExpectTag(kValueTag)) break; 182 GOOGLE_FALLTHROUGH_INTENDED; 183 184 case kValueTag: 185 if (!ValueTypeHandler::Read(input, mutable_value())) { 186 return false; 187 } 188 set_has_value(); 189 if (input->ExpectAtEnd()) return true; 190 break; 191 192 default: 193 if (tag == 0 || 194 WireFormatLite::GetTagWireType(tag) == 195 WireFormatLite::WIRETYPE_END_GROUP) { 196 return true; 197 } 198 if (!WireFormatLite::SkipField(input, tag)) return false; 199 break; 200 } 201 } 202 } 203 204 int ByteSize() const { 205 int size = 0; 206 size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; 207 size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; 208 return size; 209 } 210 211 void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const { 212 KeyTypeHandler::Write(kKeyFieldNumber, key(), output); 213 ValueTypeHandler::Write(kValueFieldNumber, value(), output); 214 } 215 216 ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool deterministic, 217 ::google::protobuf::uint8* output) const { 218 output = KeyTypeHandler::InternalWriteToArray(kKeyFieldNumber, key(), 219 deterministic, output); 220 output = ValueTypeHandler::InternalWriteToArray(kValueFieldNumber, value(), 221 deterministic, output); 222 return output; 223 } 224 ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { 225 return InternalSerializeWithCachedSizesToArray(false, output); 226 } 227 228 int GetCachedSize() const { 229 int size = 0; 230 size += has_key() 231 ? kTagSize + KeyTypeHandler::GetCachedSize(key()) 232 : 0; 233 size += has_value() 234 ? kTagSize + ValueTypeHandler::GetCachedSize( 235 value()) 236 : 0; 237 return size; 238 } 239 240 bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); } 241 242 MessageLite* New() const { 243 MapEntryLite* entry = new MapEntryLite; 244 entry->default_instance_ = default_instance_; 245 return entry; 246 } 247 248 MessageLite* New(Arena* arena) const { 249 MapEntryLite* entry = Arena::CreateMessage<MapEntryLite>(arena); 250 entry->default_instance_ = default_instance_; 251 return entry; 252 } 253 254 int SpaceUsed() const { 255 int size = sizeof(MapEntryLite); 256 size += KeyTypeHandler::SpaceUsedInMapEntry(key_); 257 size += ValueTypeHandler::SpaceUsedInMapEntry(value_); 258 return size; 259 } 260 261 void MergeFrom(const MapEntryLite& from) { 262 if (from._has_bits_[0]) { 263 if (from.has_key()) { 264 KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual()); 265 KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual()); 266 set_has_key(); 267 } 268 if (from.has_value()) { 269 ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual()); 270 ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual()); 271 set_has_value(); 272 } 273 } 274 } 275 276 void Clear() { 277 KeyTypeHandler::Clear(&key_, GetArenaNoVirtual()); 278 ValueTypeHandler::ClearMaybeByDefaultEnum( 279 &value_, GetArenaNoVirtual(), default_enum_value); 280 clear_has_key(); 281 clear_has_value(); 282 } 283 284 void InitAsDefaultInstance() { 285 KeyTypeHandler::AssignDefaultValue(&key_); 286 ValueTypeHandler::AssignDefaultValue(&value_); 287 } 288 289 Arena* GetArena() const { 290 return GetArenaNoVirtual(); 291 } 292 293 // Create a MapEntryLite for given key and value from google::protobuf::Map in 294 // serialization. This function is only called when value is enum. Enum is 295 // treated differently because its type in MapEntry is int and its type in 296 // google::protobuf::Map is enum. We cannot create a reference to int from an enum. 297 static MapEntryLite* EnumWrap(const Key& key, const Value value, 298 Arena* arena) { 299 return Arena::CreateMessage<MapEnumEntryWrapper< 300 Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> >( 301 arena, key, value); 302 } 303 304 // Like above, but for all the other types. This avoids value copy to create 305 // MapEntryLite from google::protobuf::Map in serialization. 306 static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) { 307 return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType, 308 kValueFieldType, 309 default_enum_value> >( 310 arena, key, value); 311 } 312 313 // Parsing using MergePartialFromCodedStream, above, is not as 314 // efficient as it could be. This helper class provides a speedier way. 315 template <typename MapField, typename Map> 316 class Parser { 317 public: 318 explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {} 319 320 // This does what the typical MergePartialFromCodedStream() is expected to 321 // do, with the additional side-effect that if successful (i.e., if true is 322 // going to be its return value) it inserts the key-value pair into map_. 323 bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) { 324 // Look for the expected thing: a key and then a value. If it fails, 325 // invoke the enclosing class's MergePartialFromCodedStream, or return 326 // false if that would be pointless. 327 if (input->ExpectTag(kKeyTag)) { 328 if (!KeyTypeHandler::Read(input, &key_)) { 329 return false; 330 } 331 // Peek at the next byte to see if it is kValueTag. If not, bail out. 332 const void* data; 333 int size; 334 input->GetDirectBufferPointerInline(&data, &size); 335 // We could use memcmp here, but we don't bother. The tag is one byte. 336 assert(kTagSize == 1); 337 if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) { 338 typename Map::size_type size = map_->size(); 339 value_ptr_ = &(*map_)[key_]; 340 if (GOOGLE_PREDICT_TRUE(size != map_->size())) { 341 // We created a new key-value pair. Fill in the value. 342 typedef 343 typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T; 344 input->Skip(kTagSize); // Skip kValueTag. 345 if (!ValueTypeHandler::Read(input, 346 reinterpret_cast<T>(value_ptr_))) { 347 map_->erase(key_); // Failure! Undo insertion. 348 return false; 349 } 350 if (input->ExpectAtEnd()) return true; 351 return ReadBeyondKeyValuePair(input); 352 } 353 } 354 } else { 355 key_ = Key(); 356 } 357 358 entry_.reset(mf_->NewEntry()); 359 *entry_->mutable_key() = key_; 360 if (!entry_->MergePartialFromCodedStream(input)) return false; 361 return UseKeyAndValueFromEntry(); 362 } 363 364 const Key& key() const { return key_; } 365 const Value& value() const { return *value_ptr_; } 366 367 private: 368 bool UseKeyAndValueFromEntry() GOOGLE_ATTRIBUTE_COLD { 369 // Update key_ in case we need it later (because key() is called). 370 // This is potentially inefficient, especially if the key is 371 // expensive to copy (e.g., a long string), but this is a cold 372 // path, so it's not a big deal. 373 key_ = entry_->key(); 374 value_ptr_ = &(*map_)[key_]; 375 MoveHelper<ValueTypeHandler::kIsEnum, 376 ValueTypeHandler::kIsMessage, 377 ValueTypeHandler::kWireType == 378 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, 379 Value>::Move(entry_->mutable_value(), value_ptr_); 380 if (entry_->GetArena() != NULL) entry_.release(); 381 return true; 382 } 383 384 // After reading a key and value successfully, and inserting that data 385 // into map_, we are not at the end of the input. This is unusual, but 386 // allowed by the spec. 387 bool ReadBeyondKeyValuePair(::google::protobuf::io::CodedInputStream* input) 388 GOOGLE_ATTRIBUTE_COLD { 389 typedef MoveHelper<KeyTypeHandler::kIsEnum, 390 KeyTypeHandler::kIsMessage, 391 KeyTypeHandler::kWireType == 392 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, 393 Key> KeyMover; 394 typedef MoveHelper<ValueTypeHandler::kIsEnum, 395 ValueTypeHandler::kIsMessage, 396 ValueTypeHandler::kWireType == 397 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, 398 Value> ValueMover; 399 entry_.reset(mf_->NewEntry()); 400 ValueMover::Move(value_ptr_, entry_->mutable_value()); 401 map_->erase(key_); 402 KeyMover::Move(&key_, entry_->mutable_key()); 403 if (!entry_->MergePartialFromCodedStream(input)) return false; 404 return UseKeyAndValueFromEntry(); 405 } 406 407 MapField* const mf_; 408 Map* const map_; 409 Key key_; 410 Value* value_ptr_; 411 // On the fast path entry_ is not used. 412 google::protobuf::scoped_ptr<MapEntryLite> entry_; 413 }; 414 415 protected: 416 void set_has_key() { _has_bits_[0] |= 0x00000001u; } 417 bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; } 418 void clear_has_key() { _has_bits_[0] &= ~0x00000001u; } 419 void set_has_value() { _has_bits_[0] |= 0x00000002u; } 420 bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } 421 void clear_has_value() { _has_bits_[0] &= ~0x00000002u; } 422 423 private: 424 // Serializing a generated message containing map field involves serializing 425 // key-value pairs from google::protobuf::Map. The wire format of each key-value pair 426 // after serialization should be the same as that of a MapEntry message 427 // containing the same key and value inside it. However, google::protobuf::Map doesn't 428 // store key and value as MapEntry message, which disables us to use existing 429 // code to serialize message. In order to use existing code to serialize 430 // message, we need to construct a MapEntry from key-value pair. But it 431 // involves copy of key and value to construct a MapEntry. In order to avoid 432 // this copy in constructing a MapEntry, we need the following class which 433 // only takes references of given key and value. 434 template <typename K, typename V, WireFormatLite::FieldType k_wire_type, 435 WireFormatLite::FieldType v_wire_type, int default_enum> 436 class MapEntryWrapper 437 : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> { 438 typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base; 439 typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; 440 typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; 441 442 public: 443 MapEntryWrapper(Arena* arena, const K& key, const V& value) 444 : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena), 445 key_(key), 446 value_(value) { 447 Base::set_has_key(); 448 Base::set_has_value(); 449 } 450 inline const KeyMapEntryAccessorType& key() const { return key_; } 451 inline const ValueMapEntryAccessorType& value() const { return value_; } 452 453 private: 454 const Key& key_; 455 const Value& value_; 456 457 friend class ::google::protobuf::Arena; 458 typedef void InternalArenaConstructable_; 459 typedef void DestructorSkippable_; 460 }; 461 462 // Like above, but for enum value only, which stores value instead of 463 // reference of value field inside. This is needed because the type of value 464 // field in constructor is an enum, while we need to store it as an int. If we 465 // initialize a reference to int with a reference to enum, compiler will 466 // generate a temporary int from enum and initialize the reference to int with 467 // the temporary. 468 template <typename K, typename V, WireFormatLite::FieldType k_wire_type, 469 WireFormatLite::FieldType v_wire_type, int default_enum> 470 class MapEnumEntryWrapper 471 : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> { 472 typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base; 473 typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; 474 typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; 475 476 public: 477 MapEnumEntryWrapper(Arena* arena, const K& key, const V& value) 478 : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena), 479 key_(key), 480 value_(value) { 481 Base::set_has_key(); 482 Base::set_has_value(); 483 } 484 inline const KeyMapEntryAccessorType& key() const { return key_; } 485 inline const ValueMapEntryAccessorType& value() const { return value_; } 486 487 private: 488 const KeyMapEntryAccessorType& key_; 489 const ValueMapEntryAccessorType value_; 490 491 friend class google::protobuf::Arena; 492 typedef void DestructorSkippable_; 493 }; 494 495 MapEntryLite() : default_instance_(NULL), arena_(NULL) { 496 KeyTypeHandler::Initialize(&key_, NULL); 497 ValueTypeHandler::InitializeMaybeByDefaultEnum( 498 &value_, default_enum_value, NULL); 499 _has_bits_[0] = 0; 500 } 501 502 explicit MapEntryLite(Arena* arena) 503 : default_instance_(NULL), arena_(arena) { 504 KeyTypeHandler::Initialize(&key_, arena); 505 ValueTypeHandler::InitializeMaybeByDefaultEnum( 506 &value_, default_enum_value, arena); 507 _has_bits_[0] = 0; 508 } 509 510 inline Arena* GetArenaNoVirtual() const { 511 return arena_; 512 } 513 514 void set_default_instance(MapEntryLite* default_instance) { 515 default_instance_ = default_instance; 516 } 517 518 MapEntryLite* default_instance_; 519 520 KeyOnMemory key_; 521 ValueOnMemory value_; 522 Arena* arena_; 523 uint32 _has_bits_[1]; 524 525 friend class ::google::protobuf::Arena; 526 typedef void InternalArenaConstructable_; 527 typedef void DestructorSkippable_; 528 template <typename K, typename V, WireFormatLite::FieldType, 529 WireFormatLite::FieldType, int> 530 friend class internal::MapEntry; 531 template <typename K, typename V, WireFormatLite::FieldType, 532 WireFormatLite::FieldType, int> 533 friend class internal::MapFieldLite; 534 535 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite); 536 }; 537 538 // Helpers for deterministic serialization ============================= 539 540 // This struct can be used with any generic sorting algorithm. If the Key 541 // type is relatively small and easy to copy then copying Keys into an 542 // array of SortItems can be beneficial. Then all the data the sorting 543 // algorithm needs to touch is in that one array. 544 template <typename Key, typename PtrToKeyValuePair> struct SortItem { 545 SortItem() {} 546 explicit SortItem(PtrToKeyValuePair p) : first(p->first), second(p) {} 547 548 Key first; 549 PtrToKeyValuePair second; 550 }; 551 552 template <typename T> struct CompareByFirstField { 553 bool operator()(const T& a, const T& b) const { 554 return a.first < b.first; 555 } 556 }; 557 558 template <typename T> struct CompareByDerefFirst { 559 bool operator()(const T& a, const T& b) const { 560 return a->first < b->first; 561 } 562 }; 563 564 } // namespace internal 565 } // namespace protobuf 566 567 } // namespace google 568 #endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ 569