// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Must be included last. #include #ifdef SWIG #error "You cannot SWIG proto headers" #endif namespace google { namespace protobuf { namespace internal { template class MapEntry; template class MapFieldLite; } // namespace internal } // namespace protobuf } // namespace google namespace google { namespace protobuf { namespace internal { // MoveHelper::Move is used to set *dest. It copies *src, or moves it (in // the C++11 sense), or swaps it. *src is left in a sane state for // subsequent destruction, but shouldn't be used for anything. template struct MoveHelper { // primitives static void Move(T* src, T* dest) { *dest = *src; } }; template struct MoveHelper { // enums static void Move(T* src, T* dest) { *dest = *src; } // T is an enum here, so allow conversions to and from int. static void Move(T* src, int* dest) { *dest = static_cast(*src); } static void Move(int* src, T* dest) { *dest = static_cast(*src); } }; template struct MoveHelper { // messages static void Move(T* src, T* dest) { dest->Swap(src); } }; template struct MoveHelper { // strings and similar static void Move(T* src, T* dest) { *dest = std::move(*src); } }; // MapEntryImpl is used to implement parsing and serialization of map entries. // It uses Curious Recursive Template Pattern (CRTP) to provide the type of // the eventual code to the template code. template class MapEntryImpl : public Base { public: typedef MapEntryFuncs Funcs; protected: // Provide utilities to parse/serialize key/value. Provide utilities to // manipulate internal stored type. typedef MapTypeHandler KeyTypeHandler; typedef MapTypeHandler ValueTypeHandler; // Define internal memory layout. Strings and messages are stored as // pointers, while other types are stored as values. typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory; typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory; // Enum type cannot be used for MapTypeHandler::Read. Define a type // which will replace Enum with int. typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType; typedef typename ValueTypeHandler::MapEntryAccessorType ValueMapEntryAccessorType; // Constants for field number. static const int kKeyFieldNumber = 1; static const int kValueFieldNumber = 2; // Constants for field tag. static const uint8_t kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kKeyFieldNumber, KeyTypeHandler::kWireType); static const uint8_t kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( kValueFieldNumber, ValueTypeHandler::kWireType); static const size_t kTagSize = 1; public: // Work-around for a compiler bug (see repeated_field.h). typedef void MapEntryHasMergeTypeTrait; typedef Derived EntryType; typedef Key EntryKeyType; typedef Value EntryValueType; static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType; static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType; constexpr MapEntryImpl() : key_(KeyTypeHandler::Constinit()), value_(ValueTypeHandler::Constinit()), _has_bits_{} {} explicit MapEntryImpl(Arena* arena) : Base(arena), key_(KeyTypeHandler::Constinit()), value_(ValueTypeHandler::Constinit()), _has_bits_{} {} ~MapEntryImpl() override { if (Base::GetArenaForAllocation() != nullptr) return; KeyTypeHandler::DeleteNoArena(key_); ValueTypeHandler::DeleteNoArena(value_); } // accessors ====================================================== virtual inline const KeyMapEntryAccessorType& key() const { return KeyTypeHandler::GetExternalReference(key_); } virtual inline const ValueMapEntryAccessorType& value() const { return ValueTypeHandler::DefaultIfNotInitialized(value_); } inline KeyMapEntryAccessorType* mutable_key() { set_has_key(); return KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation()); } inline ValueMapEntryAccessorType* mutable_value() { set_has_value(); return ValueTypeHandler::EnsureMutable(&value_, Base::GetArenaForAllocation()); } // implements MessageLite ========================================= // MapEntryImpl is for implementation only and this function isn't called // anywhere. Just provide a fake implementation here for MessageLite. std::string GetTypeName() const override { return ""; } void CheckTypeAndMergeFrom(const MessageLite& other) override { MergeFromInternal(*::google::protobuf::internal::DownCast(&other)); } const char* _InternalParse(const char* ptr, ParseContext* ctx) final { while (!ctx->Done(&ptr)) { uint32_t tag; ptr = ReadTag(ptr, &tag); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); if (tag == kKeyTag) { set_has_key(); KeyMapEntryAccessorType* key = mutable_key(); ptr = KeyTypeHandler::Read(ptr, ctx, key); if (!Derived::ValidateKey(key)) return nullptr; } else if (tag == kValueTag) { set_has_value(); ValueMapEntryAccessorType* value = mutable_value(); ptr = ValueTypeHandler::Read(ptr, ctx, value); if (!Derived::ValidateValue(value)) return nullptr; } else { if (tag == 0 || WireFormatLite::GetTagWireType(tag) == WireFormatLite::WIRETYPE_END_GROUP) { ctx->SetLastTag(tag); return ptr; } ptr = UnknownFieldParse(tag, static_cast(nullptr), ptr, ctx); } GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); } return ptr; } size_t ByteSizeLong() const override { size_t size = 0; size += kTagSize + static_cast(KeyTypeHandler::ByteSize(key())); size += kTagSize + static_cast(ValueTypeHandler::ByteSize(value())); return size; } ::uint8_t* _InternalSerialize( ::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override { ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream); return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream); } // Don't override SerializeWithCachedSizesToArray. Use MessageLite's. int GetCachedSize() const override { int size = 0; size += has_key() ? static_cast(kTagSize) + KeyTypeHandler::GetCachedSize(key()) : 0; size += has_value() ? static_cast(kTagSize) + ValueTypeHandler::GetCachedSize(value()) : 0; return size; } bool IsInitialized() const override { return ValueTypeHandler::IsInitialized(value_); } Base* New(Arena* arena) const override { Derived* entry = Arena::CreateMessage(arena); return entry; } protected: // We can't declare this function directly here as it would hide the other // overload (const Message&). void MergeFromInternal(const MapEntryImpl& from) { if (from._has_bits_[0]) { if (from.has_key()) { KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation()); KeyTypeHandler::Merge(from.key(), &key_, Base::GetArenaForAllocation()); set_has_key(); } if (from.has_value()) { ValueTypeHandler::EnsureMutable(&value_, Base::GetArenaForAllocation()); ValueTypeHandler::Merge(from.value(), &value_, Base::GetArenaForAllocation()); set_has_value(); } } } public: void Clear() override { KeyTypeHandler::Clear(&key_, Base::GetArenaForAllocation()); ValueTypeHandler::Clear(&value_, Base::GetArenaForAllocation()); clear_has_key(); clear_has_value(); } // Parsing using MergePartialFromCodedStream, above, is not as // efficient as it could be. This helper class provides a speedier way. template class Parser { public: explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {} ~Parser() { if (entry_ != nullptr && entry_->GetArenaForAllocation() == nullptr) delete entry_; } const char* _InternalParse(const char* ptr, ParseContext* ctx) { if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kKeyTag)) { ptr = KeyTypeHandler::Read(ptr + 1, ctx, &key_); if (PROTOBUF_PREDICT_FALSE(!ptr || !Derived::ValidateKey(&key_))) { return nullptr; } if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kValueTag)) { typename Map::size_type map_size = map_->size(); value_ptr_ = &(*map_)[key_]; if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) { using T = typename MapIf::type; ptr = ValueTypeHandler::Read(ptr + 1, ctx, reinterpret_cast(value_ptr_)); if (PROTOBUF_PREDICT_FALSE(!ptr || !Derived::ValidateValue(value_ptr_))) { map_->erase(key_); // Failure! Undo insertion. return nullptr; } if (PROTOBUF_PREDICT_TRUE(ctx->Done(&ptr))) return ptr; if (!ptr) return nullptr; NewEntry(); ValueMover::Move(value_ptr_, entry_->mutable_value()); map_->erase(key_); goto move_key; } } else { if (!ptr) return nullptr; } NewEntry(); move_key: KeyMover::Move(&key_, entry_->mutable_key()); } else { if (!ptr) return nullptr; NewEntry(); } ptr = entry_->_InternalParse(ptr, ctx); if (ptr) UseKeyAndValueFromEntry(); return ptr; } template const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx, bool (*is_valid)(int), uint32_t field_num, InternalMetadata* metadata) { auto entry = NewEntry(); ptr = entry->_InternalParse(ptr, ctx); if (!ptr) return nullptr; if (is_valid(entry->value())) { UseKeyAndValueFromEntry(); } else { WriteLengthDelimited(field_num, entry->SerializeAsString(), metadata->mutable_unknown_fields()); } return ptr; } MapEntryImpl* NewEntry() { return entry_ = mf_->NewEntry(); } const Key& key() const { return key_; } const Value& value() const { return *value_ptr_; } const Key& entry_key() const { return entry_->key(); } const Value& entry_value() const { return entry_->value(); } private: void UseKeyAndValueFromEntry() { // Update key_ in case we need it later (because key() is called). // This is potentially inefficient, especially if the key is // expensive to copy (e.g., a long string), but this is a cold // path, so it's not a big deal. key_ = entry_->key(); value_ptr_ = &(*map_)[key_]; ValueMover::Move(entry_->mutable_value(), value_ptr_); } // After reading a key and value successfully, and inserting that data // into map_, we are not at the end of the input. This is unusual, but // allowed by the spec. bool ReadBeyondKeyValuePair(io::CodedInputStream* input) PROTOBUF_COLD { NewEntry(); ValueMover::Move(value_ptr_, entry_->mutable_value()); map_->erase(key_); KeyMover::Move(&key_, entry_->mutable_key()); const bool result = entry_->MergePartialFromCodedStream(input); if (result) UseKeyAndValueFromEntry(); return result; } typedef MoveHelper KeyMover; typedef MoveHelper ValueMover; MapField* const mf_; Map* const map_; Key key_; Value* value_ptr_; MapEntryImpl* entry_ = nullptr; }; protected: void set_has_key() { _has_bits_[0] |= 0x00000001u; } bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; } void clear_has_key() { _has_bits_[0] &= ~0x00000001u; } void set_has_value() { _has_bits_[0] |= 0x00000002u; } bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } void clear_has_value() { _has_bits_[0] &= ~0x00000002u; } public: inline Arena* GetArena() const { return Base::GetArena(); } protected: // Needed for constructing tables KeyOnMemory key_; ValueOnMemory value_; uint32_t _has_bits_[1]; private: friend class ::PROTOBUF_NAMESPACE_ID::Arena; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; template friend class internal::MapEntry; template friend class internal::MapFieldLite; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl); }; template class MapEntryLite : public MapEntryImpl { public: typedef MapEntryImpl SuperType; constexpr MapEntryLite() {} explicit MapEntryLite(Arena* arena) : SuperType(arena) {} ~MapEntryLite() override { MessageLite::_internal_metadata_.template Delete(); } void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); } private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite); }; // Helpers for deterministic serialization ============================= // Iterator base for MapSorterFlat and MapSorterPtr. template struct MapSorterIt { storage_type* ptr; MapSorterIt(storage_type* ptr) : ptr(ptr) {} bool operator==(const MapSorterIt& other) const { return ptr == other.ptr; } bool operator!=(const MapSorterIt& other) const { return !(*this == other); } MapSorterIt& operator++() { ++ptr; return *this; } MapSorterIt operator++(int) { auto other = *this; ++ptr; return other; } MapSorterIt operator+(int v) { return MapSorterIt{ptr + v}; } }; // MapSorterFlat stores keys inline with pointers to map entries, so that // keys can be compared without indirection. This type is used for maps with // keys that are not strings. template class MapSorterFlat { public: using value_type = typename MapT::value_type; using storage_type = std::pair; // This const_iterator dereferenes to the map entry stored in the sorting // array pairs. This is the same interface as the Map::const_iterator type, // and allows generated code to use the same loop body with either form: // for (const auto& entry : map) { ... } // for (const auto& entry : MapSorterFlat(map)) { ... } struct const_iterator : public MapSorterIt { using pointer = const typename MapT::value_type*; using reference = const typename MapT::value_type&; using MapSorterIt::MapSorterIt; pointer operator->() const { return this->ptr->second; } reference operator*() const { return *this->operator->(); } }; explicit MapSorterFlat(const MapT& m) : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) { if (!size_) return; storage_type* it = &items_[0]; for (const auto& entry : m) { *it++ = {entry.first, &entry}; } std::sort(&items_[0], &items_[size_], [](const storage_type& a, const storage_type& b) { return a.first < b.first; }); } size_t size() const { return size_; } const_iterator begin() const { return {items_.get()}; } const_iterator end() const { return {items_.get() + size_}; } private: size_t size_; std::unique_ptr items_; }; // MapSorterPtr stores and sorts pointers to map entries. This type is used for // maps with keys that are strings. template class MapSorterPtr { public: using value_type = typename MapT::value_type; using storage_type = const typename MapT::value_type*; // This const_iterator dereferenes the map entry pointer stored in the sorting // array. This is the same interface as the Map::const_iterator type, and // allows generated code to use the same loop body with either form: // for (const auto& entry : map) { ... } // for (const auto& entry : MapSorterPtr(map)) { ... } struct const_iterator : public MapSorterIt { using pointer = const typename MapT::value_type*; using reference = const typename MapT::value_type&; using MapSorterIt::MapSorterIt; pointer operator->() const { return *this->ptr; } reference operator*() const { return *this->operator->(); } }; explicit MapSorterPtr(const MapT& m) : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) { if (!size_) return; storage_type* it = &items_[0]; for (const auto& entry : m) { *it++ = &entry; } std::sort(&items_[0], &items_[size_], [](const storage_type& a, const storage_type& b) { return a->first < b->first; }); } size_t size() const { return size_; } const_iterator begin() const { return {items_.get()}; } const_iterator end() const { return {items_.get() + size_}; } private: size_t size_; std::unique_ptr items_; }; } // namespace internal } // namespace protobuf } // namespace google #include #endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__