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