| OLD | NEW |
| 1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
| 2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
| 3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
| 4 // | 4 // |
| 5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
| 7 // met: | 7 // met: |
| 8 // | 8 // |
| 9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | 30 |
| 31 #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ | 31 #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ |
| 32 #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ | 32 #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ |
| 33 | 33 |
| 34 #include <assert.h> | |
| 35 #include <google/protobuf/map_type_handler.h> | 34 #include <google/protobuf/map_type_handler.h> |
| 36 #include <google/protobuf/wire_format_lite_inl.h> | 35 #include <google/protobuf/wire_format_lite_inl.h> |
| 37 | 36 |
| 38 namespace google { | 37 namespace google { |
| 39 namespace protobuf { | 38 namespace protobuf { |
| 40 class Arena; | 39 class Arena; |
| 41 namespace internal { | 40 namespace internal { |
| 42 template <typename Key, typename Value, | 41 template <typename Key, typename Value, |
| 43 WireFormatLite::FieldType kKeyFieldType, | 42 WireFormatLite::FieldType kKeyFieldType, |
| 44 WireFormatLite::FieldType kValueFieldType, | 43 WireFormatLite::FieldType kValueFieldType, |
| 45 int default_enum_value> | 44 int default_enum_value> |
| 46 class MapEntry; | 45 class MapEntry; |
| 47 template <typename Key, typename Value, | 46 template <typename Key, typename Value, |
| 48 WireFormatLite::FieldType kKeyFieldType, | 47 WireFormatLite::FieldType kKeyFieldType, |
| 49 WireFormatLite::FieldType kValueFieldType, | 48 WireFormatLite::FieldType kValueFieldType, |
| 50 int default_enum_value> | 49 int default_enum_value> |
| 51 class MapFieldLite; | 50 class MapFieldLite; |
| 52 } // namespace internal | 51 } // namespace internal |
| 53 } // namespace protobuf | 52 } // namespace protobuf |
| 54 | 53 |
| 55 namespace protobuf { | 54 namespace protobuf { |
| 56 namespace internal { | 55 namespace internal { |
| 57 | 56 |
| 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 | |
| 63 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 | 57 // MapEntryLite is used to implement parsing and serialization of map for lite |
| 91 // runtime. | 58 // runtime. |
| 92 template <typename Key, typename Value, | 59 template <typename Key, typename Value, |
| 93 WireFormatLite::FieldType kKeyFieldType, | 60 WireFormatLite::FieldType kKeyFieldType, |
| 94 WireFormatLite::FieldType kValueFieldType, | 61 WireFormatLite::FieldType kValueFieldType, |
| 95 int default_enum_value> | 62 int default_enum_value> |
| 96 class MapEntryLite : public MessageLite { | 63 class MapEntryLite : public MessageLite { |
| 97 // Provide utilities to parse/serialize key/value. Provide utilities to | 64 // Provide utilities to parse/serialize key/value. Provide utilities to |
| 98 // manipulate internal stored type. | 65 // manipulate internal stored type. |
| 99 typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; | 66 typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 112 | 79 |
| 113 // Constants for field number. | 80 // Constants for field number. |
| 114 static const int kKeyFieldNumber = 1; | 81 static const int kKeyFieldNumber = 1; |
| 115 static const int kValueFieldNumber = 2; | 82 static const int kValueFieldNumber = 2; |
| 116 | 83 |
| 117 // Constants for field tag. | 84 // Constants for field tag. |
| 118 static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( | 85 static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( |
| 119 kKeyFieldNumber, KeyTypeHandler::kWireType); | 86 kKeyFieldNumber, KeyTypeHandler::kWireType); |
| 120 static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( | 87 static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( |
| 121 kValueFieldNumber, ValueTypeHandler::kWireType); | 88 kValueFieldNumber, ValueTypeHandler::kWireType); |
| 122 static const size_t kTagSize = 1; | 89 static const int kTagSize = 1; |
| 123 | 90 |
| 124 public: | 91 public: |
| 125 ~MapEntryLite() { | 92 ~MapEntryLite() { |
| 126 if (this != default_instance_) { | 93 if (this != default_instance_) { |
| 127 if (GetArenaNoVirtual() != NULL) return; | 94 if (GetArenaNoVirtual() != NULL) return; |
| 128 KeyTypeHandler::DeleteNoArena(key_); | 95 KeyTypeHandler::DeleteNoArena(key_); |
| 129 ValueTypeHandler::DeleteNoArena(value_); | 96 ValueTypeHandler::DeleteNoArena(value_); |
| 130 } | 97 } |
| 131 } | 98 } |
| 132 | 99 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 | 131 |
| 165 for (;;) { | 132 for (;;) { |
| 166 // 1) corrupted data: return false; | 133 // 1) corrupted data: return false; |
| 167 // 2) unknown field: skip without putting into unknown field set; | 134 // 2) unknown field: skip without putting into unknown field set; |
| 168 // 3) unknown enum value: keep it in parsing. In proto2, caller should | 135 // 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 | 136 // 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 | 137 // field set if the value is an unknown enum. In proto3, caller doesn't |
| 171 // need to care whether the value is unknown enum; | 138 // need to care whether the value is unknown enum; |
| 172 // 4) missing key/value: missed key/value will have default value. caller | 139 // 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. | 140 // should take this entry as if key/value is set to default value. |
| 174 tag = input->ReadTagNoLastTag(); | 141 tag = input->ReadTag(); |
| 175 switch (tag) { | 142 switch (tag) { |
| 176 case kKeyTag: | 143 case kKeyTag: |
| 177 if (!KeyTypeHandler::Read(input, mutable_key())) { | 144 if (!KeyTypeHandler::Read(input, mutable_key())) { |
| 178 return false; | 145 return false; |
| 179 } | 146 } |
| 180 set_has_key(); | 147 set_has_key(); |
| 181 if (!input->ExpectTag(kValueTag)) break; | 148 if (!input->ExpectTag(kValueTag)) break; |
| 182 GOOGLE_FALLTHROUGH_INTENDED; | 149 GOOGLE_FALLTHROUGH_INTENDED; |
| 183 | 150 |
| 184 case kValueTag: | 151 case kValueTag: |
| 185 if (!ValueTypeHandler::Read(input, mutable_value())) { | 152 if (!ValueTypeHandler::Read(input, mutable_value())) { |
| 186 return false; | 153 return false; |
| 187 } | 154 } |
| 188 set_has_value(); | 155 set_has_value(); |
| 189 if (input->ExpectAtEnd()) return true; | 156 if (input->ExpectAtEnd()) return true; |
| 190 break; | 157 break; |
| 191 | 158 |
| 192 default: | 159 default: |
| 193 if (tag == 0 || | 160 if (tag == 0 || |
| 194 WireFormatLite::GetTagWireType(tag) == | 161 WireFormatLite::GetTagWireType(tag) == |
| 195 WireFormatLite::WIRETYPE_END_GROUP) { | 162 WireFormatLite::WIRETYPE_END_GROUP) { |
| 196 return true; | 163 return true; |
| 197 } | 164 } |
| 198 if (!WireFormatLite::SkipField(input, tag)) return false; | 165 if (!WireFormatLite::SkipField(input, tag)) return false; |
| 199 break; | 166 break; |
| 200 } | 167 } |
| 201 } | 168 } |
| 202 } | 169 } |
| 203 | 170 |
| 204 size_t ByteSizeLong() const { | 171 int ByteSize() const { |
| 205 size_t size = 0; | 172 int size = 0; |
| 206 size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; | 173 size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; |
| 207 size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; | 174 size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; |
| 208 return size; | 175 return size; |
| 209 } | 176 } |
| 210 | 177 |
| 211 void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* outpu
t) const { | 178 void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* outpu
t) const { |
| 212 KeyTypeHandler::Write(kKeyFieldNumber, key(), output); | 179 KeyTypeHandler::Write(kKeyFieldNumber, key(), output); |
| 213 ValueTypeHandler::Write(kValueFieldNumber, value(), output); | 180 ValueTypeHandler::Write(kValueFieldNumber, value(), output); |
| 214 } | 181 } |
| 215 | 182 |
| 216 ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool determ
inistic, | 183 ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf:
:uint8* output) const { |
| 217 ::google::protobuf::uint8* ou
tput) const { | 184 output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output); |
| 218 output = KeyTypeHandler::InternalWriteToArray(kKeyFieldNumber, key(), | 185 output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output); |
| 219 deterministic, output); | |
| 220 output = ValueTypeHandler::InternalWriteToArray(kValueFieldNumber, value(), | |
| 221 deterministic, output); | |
| 222 return output; | 186 return output; |
| 223 } | 187 } |
| 224 ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf:
:uint8* output) const { | |
| 225 return InternalSerializeWithCachedSizesToArray(false, output); | |
| 226 } | |
| 227 | 188 |
| 228 int GetCachedSize() const { | 189 int GetCachedSize() const { |
| 229 int size = 0; | 190 int size = 0; |
| 230 size += has_key() | 191 size += has_key() |
| 231 ? kTagSize + KeyTypeHandler::GetCachedSize(key()) | 192 ? kTagSize + KeyTypeHandler::GetCachedSize(key()) |
| 232 : 0; | 193 : 0; |
| 233 size += has_value() | 194 size += has_value() |
| 234 ? kTagSize + ValueTypeHandler::GetCachedSize( | 195 ? kTagSize + ValueTypeHandler::GetCachedSize( |
| 235 value()) | 196 value()) |
| 236 : 0; | 197 : 0; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 | 264 |
| 304 // Like above, but for all the other types. This avoids value copy to create | 265 // Like above, but for all the other types. This avoids value copy to create |
| 305 // MapEntryLite from google::protobuf::Map in serialization. | 266 // MapEntryLite from google::protobuf::Map in serialization. |
| 306 static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) { | 267 static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) { |
| 307 return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType, | 268 return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType, |
| 308 kValueFieldType, | 269 kValueFieldType, |
| 309 default_enum_value> >( | 270 default_enum_value> >( |
| 310 arena, key, value); | 271 arena, key, value); |
| 311 } | 272 } |
| 312 | 273 |
| 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* i
nput) { | |
| 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 GOOGLE_COMPILE_ASSERT(kTagSize == 1, tag_size_error); | |
| 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 const bool result = entry_->MergePartialFromCodedStream(input); | |
| 361 if (result) UseKeyAndValueFromEntry(); | |
| 362 if (entry_->GetArena() != NULL) entry_.release(); | |
| 363 return result; | |
| 364 } | |
| 365 | |
| 366 const Key& key() const { return key_; } | |
| 367 const Value& value() const { return *value_ptr_; } | |
| 368 | |
| 369 private: | |
| 370 void UseKeyAndValueFromEntry() GOOGLE_ATTRIBUTE_COLD { | |
| 371 // Update key_ in case we need it later (because key() is called). | |
| 372 // This is potentially inefficient, especially if the key is | |
| 373 // expensive to copy (e.g., a long string), but this is a cold | |
| 374 // path, so it's not a big deal. | |
| 375 key_ = entry_->key(); | |
| 376 value_ptr_ = &(*map_)[key_]; | |
| 377 MoveHelper<ValueTypeHandler::kIsEnum, | |
| 378 ValueTypeHandler::kIsMessage, | |
| 379 ValueTypeHandler::kWireType == | |
| 380 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, | |
| 381 Value>::Move(entry_->mutable_value(), value_ptr_); | |
| 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 const bool result = entry_->MergePartialFromCodedStream(input); | |
| 404 if (result) UseKeyAndValueFromEntry(); | |
| 405 if (entry_->GetArena() != NULL) entry_.release(); | |
| 406 return result; | |
| 407 } | |
| 408 | |
| 409 MapField* const mf_; | |
| 410 Map* const map_; | |
| 411 Key key_; | |
| 412 Value* value_ptr_; | |
| 413 // On the fast path entry_ is not used. And, when entry_ is used, it's set | |
| 414 // to mf_->NewEntry(), so in the arena case we must call entry_.release. | |
| 415 google::protobuf::scoped_ptr<MapEntryLite> entry_; | |
| 416 }; | |
| 417 | |
| 418 protected: | 274 protected: |
| 419 void set_has_key() { _has_bits_[0] |= 0x00000001u; } | 275 void set_has_key() { _has_bits_[0] |= 0x00000001u; } |
| 420 bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; } | 276 bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; } |
| 421 void clear_has_key() { _has_bits_[0] &= ~0x00000001u; } | 277 void clear_has_key() { _has_bits_[0] &= ~0x00000001u; } |
| 422 void set_has_value() { _has_bits_[0] |= 0x00000002u; } | 278 void set_has_value() { _has_bits_[0] |= 0x00000002u; } |
| 423 bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } | 279 bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } |
| 424 void clear_has_value() { _has_bits_[0] &= ~0x00000002u; } | 280 void clear_has_value() { _has_bits_[0] &= ~0x00000002u; } |
| 425 | 281 |
| 426 private: | 282 private: |
| 427 // Serializing a generated message containing map field involves serializing | 283 // Serializing a generated message containing map field involves serializing |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 template <typename K, typename V, WireFormatLite::FieldType, | 387 template <typename K, typename V, WireFormatLite::FieldType, |
| 532 WireFormatLite::FieldType, int> | 388 WireFormatLite::FieldType, int> |
| 533 friend class internal::MapEntry; | 389 friend class internal::MapEntry; |
| 534 template <typename K, typename V, WireFormatLite::FieldType, | 390 template <typename K, typename V, WireFormatLite::FieldType, |
| 535 WireFormatLite::FieldType, int> | 391 WireFormatLite::FieldType, int> |
| 536 friend class internal::MapFieldLite; | 392 friend class internal::MapFieldLite; |
| 537 | 393 |
| 538 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite); | 394 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite); |
| 539 }; | 395 }; |
| 540 | 396 |
| 541 // Helpers for deterministic serialization ============================= | |
| 542 | |
| 543 // This struct can be used with any generic sorting algorithm. If the Key | |
| 544 // type is relatively small and easy to copy then copying Keys into an | |
| 545 // array of SortItems can be beneficial. Then all the data the sorting | |
| 546 // algorithm needs to touch is in that one array. | |
| 547 template <typename Key, typename PtrToKeyValuePair> struct SortItem { | |
| 548 SortItem() {} | |
| 549 explicit SortItem(PtrToKeyValuePair p) : first(p->first), second(p) {} | |
| 550 | |
| 551 Key first; | |
| 552 PtrToKeyValuePair second; | |
| 553 }; | |
| 554 | |
| 555 template <typename T> struct CompareByFirstField { | |
| 556 bool operator()(const T& a, const T& b) const { | |
| 557 return a.first < b.first; | |
| 558 } | |
| 559 }; | |
| 560 | |
| 561 template <typename T> struct CompareByDerefFirst { | |
| 562 bool operator()(const T& a, const T& b) const { | |
| 563 return a->first < b->first; | |
| 564 } | |
| 565 }; | |
| 566 | |
| 567 } // namespace internal | 397 } // namespace internal |
| 568 } // namespace protobuf | 398 } // namespace protobuf |
| 569 | 399 |
| 570 } // namespace google | 400 } // namespace google |
| 571 #endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ | 401 #endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ |
| OLD | NEW |