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