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_METADATA_LITE_H__ 32 #define GOOGLE_PROTOBUF_METADATA_LITE_H__ 33 34 #include <string> 35 #include <google/protobuf/stubs/common.h> 36 #include <google/protobuf/arena.h> 37 #include <google/protobuf/generated_message_util.h> 38 #include <google/protobuf/message_lite.h> 39 #include <google/protobuf/port.h> 40 41 #include <google/protobuf/port_def.inc> 42 43 #ifdef SWIG 44 #error "You cannot SWIG proto headers" 45 #endif 46 47 namespace google { 48 namespace protobuf { 49 namespace internal { 50 51 // This is the representation for messages that support arena allocation. It 52 // uses a tagged pointer to either store the Arena pointer, if there are no 53 // unknown fields, or a pointer to a block of memory with both the Arena pointer 54 // and the UnknownFieldSet, if there are unknown fields. This optimization 55 // allows for "zero-overhead" storage of the Arena pointer, relative to the 56 // above baseline implementation. 57 // 58 // The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to 59 // indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container 60 // pointer. 61 template <class T, class Derived> 62 class InternalMetadataWithArenaBase { 63 public: InternalMetadataWithArenaBase()64 InternalMetadataWithArenaBase() : ptr_(NULL) {} InternalMetadataWithArenaBase(Arena * arena)65 explicit InternalMetadataWithArenaBase(Arena* arena) : ptr_(arena) {} 66 ~InternalMetadataWithArenaBase()67 ~InternalMetadataWithArenaBase() { 68 if (have_unknown_fields() && arena() == NULL) { 69 delete PtrValue<Container>(); 70 } 71 ptr_ = NULL; 72 } 73 unknown_fields()74 PROTOBUF_ALWAYS_INLINE const T& unknown_fields() const { 75 if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) { 76 return PtrValue<Container>()->unknown_fields; 77 } else { 78 return Derived::default_instance(); 79 } 80 } 81 mutable_unknown_fields()82 PROTOBUF_ALWAYS_INLINE T* mutable_unknown_fields() { 83 if (PROTOBUF_PREDICT_TRUE(have_unknown_fields())) { 84 return &PtrValue<Container>()->unknown_fields; 85 } else { 86 return mutable_unknown_fields_slow(); 87 } 88 } 89 arena()90 PROTOBUF_ALWAYS_INLINE Arena* arena() const { 91 if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) { 92 return PtrValue<Container>()->arena; 93 } else { 94 return PtrValue<Arena>(); 95 } 96 } 97 have_unknown_fields()98 PROTOBUF_ALWAYS_INLINE bool have_unknown_fields() const { 99 return PtrTag() == kTagContainer; 100 } 101 Swap(Derived * other)102 PROTOBUF_ALWAYS_INLINE void Swap(Derived* other) { 103 // Semantics here are that we swap only the unknown fields, not the arena 104 // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to 105 // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in 106 // different states (direct arena pointer vs. container with UFS) so we 107 // cannot simply swap ptr_ and then restore the arena pointers. We reuse 108 // UFS's swap implementation instead. 109 if (have_unknown_fields() || other->have_unknown_fields()) { 110 static_cast<Derived*>(this)->DoSwap(other->mutable_unknown_fields()); 111 } 112 } 113 MergeFrom(const Derived & other)114 PROTOBUF_ALWAYS_INLINE void MergeFrom(const Derived& other) { 115 if (other.have_unknown_fields()) { 116 static_cast<Derived*>(this)->DoMergeFrom(other.unknown_fields()); 117 } 118 } 119 Clear()120 PROTOBUF_ALWAYS_INLINE void Clear() { 121 if (have_unknown_fields()) { 122 static_cast<Derived*>(this)->DoClear(); 123 } 124 } 125 raw_arena_ptr()126 PROTOBUF_ALWAYS_INLINE void* raw_arena_ptr() const { return ptr_; } 127 128 private: 129 void* ptr_; 130 131 // Tagged pointer implementation. 132 enum { 133 // ptr_ is an Arena*. 134 kTagArena = 0, 135 // ptr_ is a Container*. 136 kTagContainer = 1, 137 }; 138 static const intptr_t kPtrTagMask = 1; 139 static const intptr_t kPtrValueMask = ~kPtrTagMask; 140 141 // Accessors for pointer tag and pointer value. PtrTag()142 PROTOBUF_ALWAYS_INLINE int PtrTag() const { 143 return reinterpret_cast<intptr_t>(ptr_) & kPtrTagMask; 144 } 145 146 template <typename U> PtrValue()147 U* PtrValue() const { 148 return reinterpret_cast<U*>(reinterpret_cast<intptr_t>(ptr_) & 149 kPtrValueMask); 150 } 151 152 // If ptr_'s tag is kTagContainer, it points to an instance of this struct. 153 struct Container { 154 T unknown_fields; 155 Arena* arena; 156 }; 157 mutable_unknown_fields_slow()158 PROTOBUF_NOINLINE T* mutable_unknown_fields_slow() { 159 Arena* my_arena = arena(); 160 Container* container = Arena::Create<Container>(my_arena); 161 // Two-step assignment works around a bug in clang's static analyzer: 162 // https://bugs.llvm.org/show_bug.cgi?id=34198. 163 ptr_ = container; 164 ptr_ = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(ptr_) | 165 kTagContainer); 166 container->arena = my_arena; 167 return &(container->unknown_fields); 168 } 169 }; 170 171 // We store unknown fields as a std::string right now, because there is 172 // currently no good interface for reading unknown fields into an ArenaString. 173 // We may want to revisit this to allow unknown fields to be parsed onto the 174 // Arena. 175 class InternalMetadataWithArenaLite 176 : public InternalMetadataWithArenaBase<std::string, 177 InternalMetadataWithArenaLite> { 178 public: InternalMetadataWithArenaLite()179 InternalMetadataWithArenaLite() {} 180 InternalMetadataWithArenaLite(Arena * arena)181 explicit InternalMetadataWithArenaLite(Arena* arena) 182 : InternalMetadataWithArenaBase<std::string, 183 InternalMetadataWithArenaLite>(arena) {} 184 DoSwap(std::string * other)185 void DoSwap(std::string* other) { mutable_unknown_fields()->swap(*other); } 186 DoMergeFrom(const std::string & other)187 void DoMergeFrom(const std::string& other) { 188 mutable_unknown_fields()->append(other); 189 } 190 DoClear()191 void DoClear() { mutable_unknown_fields()->clear(); } 192 default_instance()193 static const std::string& default_instance() { 194 // Can't use GetEmptyStringAlreadyInited() here because empty string 195 // may not have been initalized yet. This happens when protocol compiler 196 // statically determines the user can't access defaults and omits init code 197 // from proto constructors. However unknown fields are always part of a 198 // proto so it needs to be lazily initailzed. See b/112613846. 199 return GetEmptyString(); 200 } 201 }; 202 203 // This helper RAII class is needed to efficiently parse unknown fields. We 204 // should only call mutable_unknown_fields if there are actual unknown fields. 205 // The obvious thing to just use a stack string and swap it at the end of 206 // the parse won't work, because the destructor of StringOutputStream needs to 207 // be called before we can modify the string (it check-fails). Using 208 // LiteUnknownFieldSetter setter(&_internal_metadata_); 209 // StringOutputStream stream(setter.buffer()); 210 // guarantees that the string is only swapped after stream is destroyed. 211 class PROTOBUF_EXPORT LiteUnknownFieldSetter { 212 public: LiteUnknownFieldSetter(InternalMetadataWithArenaLite * metadata)213 explicit LiteUnknownFieldSetter(InternalMetadataWithArenaLite* metadata) 214 : metadata_(metadata) { 215 if (metadata->have_unknown_fields()) { 216 buffer_.swap(*metadata->mutable_unknown_fields()); 217 } 218 } ~LiteUnknownFieldSetter()219 ~LiteUnknownFieldSetter() { 220 if (!buffer_.empty()) metadata_->mutable_unknown_fields()->swap(buffer_); 221 } buffer()222 std::string* buffer() { return &buffer_; } 223 224 private: 225 InternalMetadataWithArenaLite* metadata_; 226 std::string buffer_; 227 }; 228 229 } // namespace internal 230 } // namespace protobuf 231 } // namespace google 232 233 #include <google/protobuf/port_undef.inc> 234 235 #endif // GOOGLE_PROTOBUF_METADATA_LITE_H__ 236