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