• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 #include <algorithm>
37 #include <string>
38 #include <utility>
39 
40 #include <google/protobuf/stubs/casts.h>
41 #include <google/protobuf/io/coded_stream.h>
42 #include <google/protobuf/arena.h>
43 #include <google/protobuf/port.h>
44 #include <google/protobuf/arenastring.h>
45 #include <google/protobuf/generated_message_util.h>
46 #include <google/protobuf/map.h>
47 #include <google/protobuf/map_type_handler.h>
48 #include <google/protobuf/parse_context.h>
49 #include <google/protobuf/wire_format_lite.h>
50 
51 // Must be included last.
52 #include <google/protobuf/port_def.inc>
53 #ifdef SWIG
54 #error "You cannot SWIG proto headers"
55 #endif
56 
57 namespace google {
58 namespace protobuf {
59 namespace internal {
60 template <typename Derived, typename Key, typename Value,
61           WireFormatLite::FieldType kKeyFieldType,
62           WireFormatLite::FieldType kValueFieldType>
63 class MapEntry;
64 template <typename Derived, typename Key, typename Value,
65           WireFormatLite::FieldType kKeyFieldType,
66           WireFormatLite::FieldType kValueFieldType>
67 class MapFieldLite;
68 }  // namespace internal
69 }  // namespace protobuf
70 }  // namespace google
71 
72 namespace google {
73 namespace protobuf {
74 namespace internal {
75 
76 // MoveHelper::Move is used to set *dest.  It copies *src, or moves it (in
77 // the C++11 sense), or swaps it. *src is left in a sane state for
78 // subsequent destruction, but shouldn't be used for anything.
79 template <bool is_enum, bool is_message, bool is_stringlike, typename T>
80 struct MoveHelper {  // primitives
MoveMoveHelper81   static void Move(T* src, T* dest) { *dest = *src; }
82 };
83 
84 template <bool is_message, bool is_stringlike, typename T>
85 struct MoveHelper<true, is_message, is_stringlike, T> {  // enums
86   static void Move(T* src, T* dest) { *dest = *src; }
87   // T is an enum here, so allow conversions to and from int.
88   static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); }
89   static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); }
90 };
91 
92 template <bool is_stringlike, typename T>
93 struct MoveHelper<false, true, is_stringlike, T> {  // messages
94   static void Move(T* src, T* dest) { dest->Swap(src); }
95 };
96 
97 template <typename T>
98 struct MoveHelper<false, false, true, T> {  // strings and similar
99   static void Move(T* src, T* dest) {
100     *dest = std::move(*src);
101   }
102 };
103 
104 // MapEntryImpl is used to implement parsing and serialization of map entries.
105 // It uses Curious Recursive Template Pattern (CRTP) to provide the type of
106 // the eventual code to the template code.
107 template <typename Derived, typename Base, typename Key, typename Value,
108           WireFormatLite::FieldType kKeyFieldType,
109           WireFormatLite::FieldType kValueFieldType>
110 class MapEntryImpl : public Base {
111  public:
112   typedef MapEntryFuncs<Key, Value, kKeyFieldType, kValueFieldType> Funcs;
113 
114  protected:
115   // Provide utilities to parse/serialize key/value.  Provide utilities to
116   // manipulate internal stored type.
117   typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
118   typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
119 
120   // Define internal memory layout. Strings and messages are stored as
121   // pointers, while other types are stored as values.
122   typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
123   typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
124 
125   // Enum type cannot be used for MapTypeHandler::Read. Define a type
126   // which will replace Enum with int.
127   typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
128   typedef
129       typename ValueTypeHandler::MapEntryAccessorType ValueMapEntryAccessorType;
130 
131   // Constants for field number.
132   static const int kKeyFieldNumber = 1;
133   static const int kValueFieldNumber = 2;
134 
135   // Constants for field tag.
136   static const uint8_t kKeyTag =
137       GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kKeyFieldNumber, KeyTypeHandler::kWireType);
138   static const uint8_t kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
139       kValueFieldNumber, ValueTypeHandler::kWireType);
140   static const size_t kTagSize = 1;
141 
142  public:
143   // Work-around for a compiler bug (see repeated_field.h).
144   typedef void MapEntryHasMergeTypeTrait;
145   typedef Derived EntryType;
146   typedef Key EntryKeyType;
147   typedef Value EntryValueType;
148   static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType;
149   static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType;
150 
151   constexpr MapEntryImpl()
152       : key_(KeyTypeHandler::Constinit()),
153         value_(ValueTypeHandler::Constinit()),
154         _has_bits_{} {}
155 
156   explicit MapEntryImpl(Arena* arena)
157       : Base(arena),
158         key_(KeyTypeHandler::Constinit()),
159         value_(ValueTypeHandler::Constinit()),
160         _has_bits_{} {}
161 
162   ~MapEntryImpl() override {
163     if (Base::GetArenaForAllocation() != nullptr) return;
164     KeyTypeHandler::DeleteNoArena(key_);
165     ValueTypeHandler::DeleteNoArena(value_);
166   }
167 
168   // accessors ======================================================
169 
170   virtual inline const KeyMapEntryAccessorType& key() const {
171     return KeyTypeHandler::GetExternalReference(key_);
172   }
173   virtual inline const ValueMapEntryAccessorType& value() const {
174     return ValueTypeHandler::DefaultIfNotInitialized(value_);
175   }
176   inline KeyMapEntryAccessorType* mutable_key() {
177     set_has_key();
178     return KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
179   }
180   inline ValueMapEntryAccessorType* mutable_value() {
181     set_has_value();
182     return ValueTypeHandler::EnsureMutable(&value_,
183                                            Base::GetArenaForAllocation());
184   }
185 
186   // implements MessageLite =========================================
187 
188   // MapEntryImpl is for implementation only and this function isn't called
189   // anywhere. Just provide a fake implementation here for MessageLite.
190   std::string GetTypeName() const override { return ""; }
191 
192   void CheckTypeAndMergeFrom(const MessageLite& other) override {
193     MergeFromInternal(*::google::protobuf::internal::DownCast<const Derived*>(&other));
194   }
195 
196   const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
197     while (!ctx->Done(&ptr)) {
198       uint32_t tag;
199       ptr = ReadTag(ptr, &tag);
200       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
201       if (tag == kKeyTag) {
202         set_has_key();
203         KeyMapEntryAccessorType* key = mutable_key();
204         ptr = KeyTypeHandler::Read(ptr, ctx, key);
205         if (!Derived::ValidateKey(key)) return nullptr;
206       } else if (tag == kValueTag) {
207         set_has_value();
208         ValueMapEntryAccessorType* value = mutable_value();
209         ptr = ValueTypeHandler::Read(ptr, ctx, value);
210         if (!Derived::ValidateValue(value)) return nullptr;
211       } else {
212         if (tag == 0 || WireFormatLite::GetTagWireType(tag) ==
213                             WireFormatLite::WIRETYPE_END_GROUP) {
214           ctx->SetLastTag(tag);
215           return ptr;
216         }
217         ptr = UnknownFieldParse(tag, static_cast<std::string*>(nullptr), ptr,
218                                 ctx);
219       }
220       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
221     }
222     return ptr;
223   }
224 
225   size_t ByteSizeLong() const override {
226     size_t size = 0;
227     size += kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key()));
228     size += kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value()));
229     return size;
230   }
231 
232   ::uint8_t* _InternalSerialize(
233       ::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override {
234     ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
235     return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
236   }
237 
238   // Don't override SerializeWithCachedSizesToArray.  Use MessageLite's.
239 
240   int GetCachedSize() const override {
241     int size = 0;
242     size += has_key() ? static_cast<int>(kTagSize) +
243                             KeyTypeHandler::GetCachedSize(key())
244                       : 0;
245     size += has_value() ? static_cast<int>(kTagSize) +
246                               ValueTypeHandler::GetCachedSize(value())
247                         : 0;
248     return size;
249   }
250 
251   bool IsInitialized() const override {
252     return ValueTypeHandler::IsInitialized(value_);
253   }
254 
255   Base* New(Arena* arena) const override {
256     Derived* entry = Arena::CreateMessage<Derived>(arena);
257     return entry;
258   }
259 
260  protected:
261   // We can't declare this function directly here as it would hide the other
262   // overload (const Message&).
263   void MergeFromInternal(const MapEntryImpl& from) {
264     if (from._has_bits_[0]) {
265       if (from.has_key()) {
266         KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
267         KeyTypeHandler::Merge(from.key(), &key_, Base::GetArenaForAllocation());
268         set_has_key();
269       }
270       if (from.has_value()) {
271         ValueTypeHandler::EnsureMutable(&value_, Base::GetArenaForAllocation());
272         ValueTypeHandler::Merge(from.value(), &value_,
273                                 Base::GetArenaForAllocation());
274         set_has_value();
275       }
276     }
277   }
278 
279  public:
280   void Clear() override {
281     KeyTypeHandler::Clear(&key_, Base::GetArenaForAllocation());
282     ValueTypeHandler::Clear(&value_, Base::GetArenaForAllocation());
283     clear_has_key();
284     clear_has_value();
285   }
286 
287   // Parsing using MergePartialFromCodedStream, above, is not as
288   // efficient as it could be.  This helper class provides a speedier way.
289   template <typename MapField, typename Map>
290   class Parser {
291    public:
292     explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
293     ~Parser() {
294       if (entry_ != nullptr && entry_->GetArenaForAllocation() == nullptr)
295         delete entry_;
296     }
297 
298     const char* _InternalParse(const char* ptr, ParseContext* ctx) {
299       if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kKeyTag)) {
300         ptr = KeyTypeHandler::Read(ptr + 1, ctx, &key_);
301         if (PROTOBUF_PREDICT_FALSE(!ptr || !Derived::ValidateKey(&key_))) {
302           return nullptr;
303         }
304         if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kValueTag)) {
305           typename Map::size_type map_size = map_->size();
306           value_ptr_ = &(*map_)[key_];
307           if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) {
308             using T =
309                 typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type;
310             ptr = ValueTypeHandler::Read(ptr + 1, ctx,
311                                          reinterpret_cast<T>(value_ptr_));
312             if (PROTOBUF_PREDICT_FALSE(!ptr ||
313                                        !Derived::ValidateValue(value_ptr_))) {
314               map_->erase(key_);  // Failure! Undo insertion.
315               return nullptr;
316             }
317             if (PROTOBUF_PREDICT_TRUE(ctx->Done(&ptr))) return ptr;
318             if (!ptr) return nullptr;
319             NewEntry();
320             ValueMover::Move(value_ptr_, entry_->mutable_value());
321             map_->erase(key_);
322             goto move_key;
323           }
324         } else {
325           if (!ptr) return nullptr;
326         }
327         NewEntry();
328       move_key:
329         KeyMover::Move(&key_, entry_->mutable_key());
330       } else {
331         if (!ptr) return nullptr;
332         NewEntry();
333       }
334       ptr = entry_->_InternalParse(ptr, ctx);
335       if (ptr) UseKeyAndValueFromEntry();
336       return ptr;
337     }
338 
339     template <typename UnknownType>
340     const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
341                                         bool (*is_valid)(int),
342                                         uint32_t field_num,
343                                         InternalMetadata* metadata) {
344       auto entry = NewEntry();
345       ptr = entry->_InternalParse(ptr, ctx);
346       if (!ptr) return nullptr;
347       if (is_valid(entry->value())) {
348         UseKeyAndValueFromEntry();
349       } else {
350         WriteLengthDelimited(field_num, entry->SerializeAsString(),
351                              metadata->mutable_unknown_fields<UnknownType>());
352       }
353       return ptr;
354     }
355 
356     MapEntryImpl* NewEntry() { return entry_ = mf_->NewEntry(); }
357 
358     const Key& key() const { return key_; }
359     const Value& value() const { return *value_ptr_; }
360 
361     const Key& entry_key() const { return entry_->key(); }
362     const Value& entry_value() const { return entry_->value(); }
363 
364    private:
365     void UseKeyAndValueFromEntry() {
366       // Update key_ in case we need it later (because key() is called).
367       // This is potentially inefficient, especially if the key is
368       // expensive to copy (e.g., a long string), but this is a cold
369       // path, so it's not a big deal.
370       key_ = entry_->key();
371       value_ptr_ = &(*map_)[key_];
372       ValueMover::Move(entry_->mutable_value(), value_ptr_);
373     }
374 
375     // After reading a key and value successfully, and inserting that data
376     // into map_, we are not at the end of the input.  This is unusual, but
377     // allowed by the spec.
378     bool ReadBeyondKeyValuePair(io::CodedInputStream* input) PROTOBUF_COLD {
379       NewEntry();
380       ValueMover::Move(value_ptr_, entry_->mutable_value());
381       map_->erase(key_);
382       KeyMover::Move(&key_, entry_->mutable_key());
383       const bool result = entry_->MergePartialFromCodedStream(input);
384       if (result) UseKeyAndValueFromEntry();
385       return result;
386     }
387 
388     typedef MoveHelper<KeyTypeHandler::kIsEnum, KeyTypeHandler::kIsMessage,
389                        KeyTypeHandler::kWireType ==
390                            WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
391                        Key>
392         KeyMover;
393     typedef MoveHelper<ValueTypeHandler::kIsEnum, ValueTypeHandler::kIsMessage,
394                        ValueTypeHandler::kWireType ==
395                            WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
396                        Value>
397         ValueMover;
398 
399     MapField* const mf_;
400     Map* const map_;
401     Key key_;
402     Value* value_ptr_;
403     MapEntryImpl* entry_ = nullptr;
404   };
405 
406  protected:
407   void set_has_key() { _has_bits_[0] |= 0x00000001u; }
408   bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
409   void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
410   void set_has_value() { _has_bits_[0] |= 0x00000002u; }
411   bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
412   void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
413 
414  public:
415   inline Arena* GetArena() const { return Base::GetArena(); }
416 
417  protected:  // Needed for constructing tables
418   KeyOnMemory key_;
419   ValueOnMemory value_;
420   uint32_t _has_bits_[1];
421 
422  private:
423   friend class ::PROTOBUF_NAMESPACE_ID::Arena;
424   typedef void InternalArenaConstructable_;
425   typedef void DestructorSkippable_;
426   template <typename C, typename K, typename V, WireFormatLite::FieldType,
427             WireFormatLite::FieldType>
428   friend class internal::MapEntry;
429   template <typename C, typename K, typename V, WireFormatLite::FieldType,
430             WireFormatLite::FieldType>
431   friend class internal::MapFieldLite;
432 
433   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl);
434 };
435 
436 template <typename T, typename Key, typename Value,
437           WireFormatLite::FieldType kKeyFieldType,
438           WireFormatLite::FieldType kValueFieldType>
439 class MapEntryLite : public MapEntryImpl<T, MessageLite, Key, Value,
440                                          kKeyFieldType, kValueFieldType> {
441  public:
442   typedef MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
443                        kValueFieldType>
444       SuperType;
445   constexpr MapEntryLite() {}
446   explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
447   ~MapEntryLite() override {
448     MessageLite::_internal_metadata_.template Delete<std::string>();
449   }
450   void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }
451 
452  private:
453   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
454 };
455 
456 // Helpers for deterministic serialization =============================
457 
458 // Iterator base for MapSorterFlat and MapSorterPtr.
459 template <typename storage_type>
460 struct MapSorterIt {
461   storage_type* ptr;
462   MapSorterIt(storage_type* ptr) : ptr(ptr) {}
463   bool operator==(const MapSorterIt& other) const { return ptr == other.ptr; }
464   bool operator!=(const MapSorterIt& other) const { return !(*this == other); }
465   MapSorterIt& operator++() { ++ptr; return *this; }
466   MapSorterIt operator++(int) { auto other = *this; ++ptr; return other; }
467   MapSorterIt operator+(int v) { return MapSorterIt{ptr + v}; }
468 };
469 
470 // MapSorterFlat stores keys inline with pointers to map entries, so that
471 // keys can be compared without indirection. This type is used for maps with
472 // keys that are not strings.
473 template <typename MapT>
474 class MapSorterFlat {
475  public:
476   using value_type = typename MapT::value_type;
477   using storage_type = std::pair<typename MapT::key_type, const value_type*>;
478 
479   // This const_iterator dereferenes to the map entry stored in the sorting
480   // array pairs. This is the same interface as the Map::const_iterator type,
481   // and allows generated code to use the same loop body with either form:
482   //   for (const auto& entry : map) { ... }
483   //   for (const auto& entry : MapSorterFlat(map)) { ... }
484   struct const_iterator : public MapSorterIt<storage_type> {
485     using pointer = const typename MapT::value_type*;
486     using reference = const typename MapT::value_type&;
487     using MapSorterIt<storage_type>::MapSorterIt;
488 
489     pointer operator->() const { return this->ptr->second; }
490     reference operator*() const { return *this->operator->(); }
491   };
492 
493   explicit MapSorterFlat(const MapT& m)
494       : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
495     if (!size_) return;
496     storage_type* it = &items_[0];
497     for (const auto& entry : m) {
498       *it++ = {entry.first, &entry};
499     }
500     std::sort(&items_[0], &items_[size_],
501               [](const storage_type& a, const storage_type& b) {
502                 return a.first < b.first;
503               });
504   }
505   size_t size() const { return size_; }
506   const_iterator begin() const { return {items_.get()}; }
507   const_iterator end() const { return {items_.get() + size_}; }
508 
509  private:
510   size_t size_;
511   std::unique_ptr<storage_type[]> items_;
512 };
513 
514 // MapSorterPtr stores and sorts pointers to map entries. This type is used for
515 // maps with keys that are strings.
516 template <typename MapT>
517 class MapSorterPtr {
518  public:
519   using value_type = typename MapT::value_type;
520   using storage_type = const typename MapT::value_type*;
521 
522   // This const_iterator dereferenes the map entry pointer stored in the sorting
523   // array. This is the same interface as the Map::const_iterator type, and
524   // allows generated code to use the same loop body with either form:
525   //   for (const auto& entry : map) { ... }
526   //   for (const auto& entry : MapSorterPtr(map)) { ... }
527   struct const_iterator : public MapSorterIt<storage_type> {
528     using pointer = const typename MapT::value_type*;
529     using reference = const typename MapT::value_type&;
530     using MapSorterIt<storage_type>::MapSorterIt;
531 
532     pointer operator->() const { return *this->ptr; }
533     reference operator*() const { return *this->operator->(); }
534   };
535 
536   explicit MapSorterPtr(const MapT& m)
537       : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
538     if (!size_) return;
539     storage_type* it = &items_[0];
540     for (const auto& entry : m) {
541       *it++ = &entry;
542     }
543     std::sort(&items_[0], &items_[size_],
544               [](const storage_type& a, const storage_type& b) {
545                 return a->first < b->first;
546               });
547   }
548   size_t size() const { return size_; }
549   const_iterator begin() const { return {items_.get()}; }
550   const_iterator end() const { return {items_.get() + size_}; }
551 
552  private:
553   size_t size_;
554   std::unique_ptr<storage_type[]> items_;
555 };
556 
557 }  // namespace internal
558 }  // namespace protobuf
559 }  // namespace google
560 
561 #include <google/protobuf/port_undef.inc>
562 
563 #endif  // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
564