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 |