// 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. // Author: [email protected] (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // // DynamicMessage is implemented by constructing a data structure which // has roughly the same memory layout as a generated message would have. // Then, we use Reflection to implement our reflection interface. All // the other operations we need to implement (e.g. parsing, copying, // etc.) are already implemented in terms of Reflection, so the rest is // easy. // // The up side of this strategy is that it's very efficient. We don't // need to use hash_maps or generic representations of fields. The // down side is that this is a low-level memory management hack which // can be tricky to get right. // // As mentioned in the header, we only expose a DynamicMessageFactory // publicly, not the DynamicMessage class itself. This is because // GenericMessageReflection wants to have a pointer to a "default" // copy of the class, with all fields initialized to their default // values. We only want to construct one of these per message type, // so DynamicMessageFactory stores a cache of default messages for // each type it sees (each unique Descriptor pointer). The code // refers to the "default" copy of the class as the "prototype". // // Note on memory allocation: This module often calls "operator new()" // to allocate untyped memory, rather than calling something like // "new uint8_t[]". This is because "operator new()" means "Give me some // space which I can use as I please." while "new uint8_t[]" means "Give // me an array of 8-bit integers.". In practice, the later may return // a pointer that is not aligned correctly for general use. I believe // Item 8 of "More Effective C++" discusses this in more detail, though // I don't have the book on me right now so I'm not sure. #include <google/protobuf/dynamic_message.h> #include <algorithm> #include <cstddef> #include <memory> #include <new> #include <unordered_map> #include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/generated_message_reflection.h> #include <google/protobuf/generated_message_util.h> #include <google/protobuf/unknown_field_set.h> #include <google/protobuf/stubs/hash.h> #include <google/protobuf/arenastring.h> #include <google/protobuf/extension_set.h> #include <google/protobuf/map_field.h> #include <google/protobuf/map_field_inl.h> #include <google/protobuf/map_type_handler.h> #include <google/protobuf/reflection_ops.h> #include <google/protobuf/repeated_field.h> #include <google/protobuf/wire_format.h> // Must be included last. #include <google/protobuf/port_def.inc> namespace google { namespace protobuf { DynamicMapField; ExtensionSet; MapField; ArenaStringPtr; // =================================================================== // Some helper tables and functions... namespace { bool IsMapFieldInApi(const FieldDescriptor* field) { … } // Sync with helpers.h. inline bool HasHasbit(const FieldDescriptor* field) { … } inline bool InRealOneof(const FieldDescriptor* field) { … } // Compute the byte size of the in-memory representation of the field. int FieldSpaceUsed(const FieldDescriptor* field) { … } inline int DivideRoundingUp(int i, int j) { … } static const int kSafeAlignment = …; static const int kMaxOneofUnionSize = …; inline int AlignTo(int offset, int alignment) { … } // Rounds the given byte offset up to the next offset aligned such that any // type may be stored at it. inline int AlignOffset(int offset) { … } #define bitsizeof(T) … } // namespace // =================================================================== class DynamicMessage : public Message { … }; struct DynamicMessageFactory::TypeInfo { … }; DynamicMessage::DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info) : … { … } DynamicMessage::DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info, Arena* arena) : … { … } DynamicMessage::DynamicMessage(DynamicMessageFactory::TypeInfo* type_info, bool lock_factory) : … { … } inline void* DynamicMessage::MutableRaw(int i) { … } inline void* DynamicMessage::MutableExtensionsRaw() { … } inline void* DynamicMessage::MutableWeakFieldMapRaw() { … } inline void* DynamicMessage::MutableOneofCaseRaw(int i) { … } inline void* DynamicMessage::MutableOneofFieldRaw(const FieldDescriptor* f) { … } void DynamicMessage::SharedCtor(bool lock_factory) { … } bool DynamicMessage::is_prototype() const { … } #if defined(__cpp_lib_destroying_delete) && defined(__cpp_sized_deallocation) void DynamicMessage::operator delete(DynamicMessage* msg, std::destroying_delete_t) { const size_t size = msg->type_info_->size; msg->~DynamicMessage(); ::operator delete(msg, size); } #endif DynamicMessage::~DynamicMessage() { … } void DynamicMessage::CrossLinkPrototypes() { … } Message* DynamicMessage::New(Arena* arena) const { … } int DynamicMessage::GetCachedSize() const { … } void DynamicMessage::SetCachedSize(int size) const { … } Metadata DynamicMessage::GetMetadata() const { … } // =================================================================== DynamicMessageFactory::DynamicMessageFactory() : … { … } DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool) : … { … } DynamicMessageFactory::~DynamicMessageFactory() { … } const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) { … } const Message* DynamicMessageFactory::GetPrototypeNoLock( const Descriptor* type) { … } } // namespace protobuf } // namespace google #include <google/protobuf/port_undef.inc> // NOLINT