• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #ifndef GOOGLE_PROTOBUF_METADATA_LITE_H__
9 #define GOOGLE_PROTOBUF_METADATA_LITE_H__
10 
11 #include <string>
12 
13 #include "google/protobuf/arena.h"
14 #include "google/protobuf/port.h"
15 
16 // Must be included last.
17 #include "google/protobuf/port_def.inc"
18 
19 #ifdef SWIG
20 #error "You cannot SWIG proto headers"
21 #endif
22 
23 namespace google {
24 namespace protobuf {
25 
26 class UnknownFieldSet;
27 
28 namespace internal {
29 
30 // This is the representation for messages that support arena allocation. It
31 // uses a tagged pointer to either store the owning Arena pointer, if there are
32 // no unknown fields, or a pointer to a block of memory with both the owning
33 // Arena pointer and the UnknownFieldSet, if there are unknown fields. Besides,
34 // it also uses the tag to distinguish whether the owning Arena pointer is also
35 // used by sub-structure allocation. This optimization allows for
36 // "zero-overhead" storage of the Arena pointer, relative to the above baseline
37 // implementation.
38 //
39 // The tagged pointer uses the least two significant bits to disambiguate cases.
40 // It uses bit 0 == 0 to indicate an arena pointer and bit 0 == 1 to indicate a
41 // UFS+Arena-container pointer. Besides it uses bit 1 == 0 to indicate arena
42 // allocation and bit 1 == 1 to indicate heap allocation.
43 class PROTOBUF_EXPORT InternalMetadata {
44  public:
InternalMetadata()45   constexpr InternalMetadata() : ptr_(0) {}
InternalMetadata(Arena * arena)46   explicit InternalMetadata(Arena* arena) {
47     ptr_ = reinterpret_cast<intptr_t>(arena);
48   }
49 
50   // Delete will delete the unknown fields only if they weren't allocated on an
51   // arena.  Then it updates the flags so that if you call
52   // have_unknown_fields(), it will return false.
53   //
54   // It is designed to be used as part of a Message class's destructor call, so
55   // that when control eventually gets to ~InternalMetadata(), we don't need to
56   // check for have_unknown_fields() again.
57   template <typename T>
Delete()58   void Delete() {
59     // Note that Delete<> should be called not more than once.
60     if (have_unknown_fields()) {
61       DeleteOutOfLineHelper<T>();
62     }
63   }
64 
arena()65   PROTOBUF_NDEBUG_INLINE Arena* arena() const {
66     if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
67       return PtrValue<ContainerBase>()->arena;
68     } else {
69       return PtrValue<Arena>();
70     }
71   }
72 
have_unknown_fields()73   PROTOBUF_NDEBUG_INLINE bool have_unknown_fields() const {
74     return HasUnknownFieldsTag();
75   }
76 
raw_arena_ptr()77   PROTOBUF_NDEBUG_INLINE void* raw_arena_ptr() const {
78     return reinterpret_cast<void*>(ptr_);
79   }
80 
81   template <typename T>
unknown_fields(const T & (* default_instance)())82   PROTOBUF_NDEBUG_INLINE const T& unknown_fields(
83       const T& (*default_instance)()) const {
84     if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
85       return PtrValue<Container<T>>()->unknown_fields;
86     } else {
87       return default_instance();
88     }
89   }
90 
91   template <typename T>
mutable_unknown_fields()92   PROTOBUF_NDEBUG_INLINE T* mutable_unknown_fields() {
93     if (PROTOBUF_PREDICT_TRUE(have_unknown_fields())) {
94       return &PtrValue<Container<T>>()->unknown_fields;
95     } else {
96       return mutable_unknown_fields_slow<T>();
97     }
98   }
99 
100   template <typename T>
Swap(InternalMetadata * other)101   PROTOBUF_NDEBUG_INLINE void Swap(InternalMetadata* other) {
102     // Semantics here are that we swap only the unknown fields, not the arena
103     // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
104     // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
105     // different states (direct arena pointer vs. container with UFS) so we
106     // cannot simply swap ptr_ and then restore the arena pointers. We reuse
107     // UFS's swap implementation instead.
108     if (have_unknown_fields() || other->have_unknown_fields()) {
109       DoSwap<T>(other->mutable_unknown_fields<T>());
110     }
111   }
112 
InternalSwap(InternalMetadata * PROTOBUF_RESTRICT other)113   PROTOBUF_NDEBUG_INLINE void InternalSwap(
114       InternalMetadata* PROTOBUF_RESTRICT other) {
115     std::swap(ptr_, other->ptr_);
116   }
117 
118   template <typename T>
MergeFrom(const InternalMetadata & other)119   PROTOBUF_NDEBUG_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_NDEBUG_INLINE void Clear() {
127     if (have_unknown_fields()) {
128       DoClear<T>();
129     }
130   }
131 
132  private:
133   intptr_t ptr_;
134 
135   // Tagged pointer implementation.
136   static constexpr intptr_t kUnknownFieldsTagMask = 1;
137   static constexpr intptr_t kPtrTagMask = kUnknownFieldsTagMask;
138   static constexpr intptr_t kPtrValueMask = ~kPtrTagMask;
139 
140   // Accessors for pointer tag and pointer value.
HasUnknownFieldsTag()141   PROTOBUF_ALWAYS_INLINE bool HasUnknownFieldsTag() const {
142     return ptr_ & kUnknownFieldsTagMask;
143   }
144 
145   template <typename U>
PtrValue()146   U* PtrValue() const {
147     return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
148   }
149 
150   // If ptr_'s tag is kTagContainer, it points to an instance of this struct.
151   struct ContainerBase {
152     Arena* arena;
153   };
154 
155   template <typename T>
156   struct Container : public ContainerBase {
157     T unknown_fields;
158   };
159 
160   template <typename T>
DeleteOutOfLineHelper()161   PROTOBUF_NOINLINE void DeleteOutOfLineHelper() {
162     delete PtrValue<Container<T>>();
163     // TODO:  This store is load-bearing.  Since we are destructing
164     // the message at this point, see if we can eliminate it.
165     ptr_ = 0;
166   }
167 
168   template <typename T>
mutable_unknown_fields_slow()169   PROTOBUF_NOINLINE T* mutable_unknown_fields_slow() {
170     Arena* my_arena = arena();
171     Container<T>* container = Arena::Create<Container<T>>(my_arena);
172     // Two-step assignment works around a bug in clang's static analyzer:
173     // https://bugs.llvm.org/show_bug.cgi?id=34198.
174     ptr_ = reinterpret_cast<intptr_t>(container);
175     ptr_ |= kUnknownFieldsTagMask;
176     container->arena = my_arena;
177     return &(container->unknown_fields);
178   }
179 
180   // Templated functions.
181 
182   template <typename T>
DoClear()183   PROTOBUF_NOINLINE void DoClear() {
184     mutable_unknown_fields<T>()->Clear();
185   }
186 
187   template <typename T>
DoMergeFrom(const T & other)188   PROTOBUF_NOINLINE void DoMergeFrom(const T& other) {
189     mutable_unknown_fields<T>()->MergeFrom(other);
190   }
191 
192   template <typename T>
DoSwap(T * other)193   PROTOBUF_NOINLINE void DoSwap(T* other) {
194     mutable_unknown_fields<T>()->Swap(other);
195   }
196 
197   // Private helper with debug checks for ~InternalMetadata()
198   void CheckedDestruct();
199 };
200 
201 // String Template specializations.
202 
203 template <>
204 PROTOBUF_EXPORT void InternalMetadata::DoClear<std::string>();
205 template <>
206 PROTOBUF_EXPORT void InternalMetadata::DoMergeFrom<std::string>(
207     const std::string& other);
208 template <>
209 PROTOBUF_EXPORT void InternalMetadata::DoSwap<std::string>(std::string* other);
210 
211 // Instantiated once in message.cc (where the definition of UnknownFieldSet is
212 // known) to prevent much duplication across translation units of a large build.
213 extern template PROTOBUF_EXPORT void
214 InternalMetadata::DoClear<UnknownFieldSet>();
215 extern template PROTOBUF_EXPORT void
216 InternalMetadata::DoMergeFrom<UnknownFieldSet>(const UnknownFieldSet& other);
217 extern template PROTOBUF_EXPORT void
218 InternalMetadata::DoSwap<UnknownFieldSet>(UnknownFieldSet* other);
219 extern template PROTOBUF_EXPORT void
220 InternalMetadata::DeleteOutOfLineHelper<UnknownFieldSet>();
221 extern template PROTOBUF_EXPORT UnknownFieldSet*
222 InternalMetadata::mutable_unknown_fields_slow<UnknownFieldSet>();
223 
224 // This helper RAII class is needed to efficiently parse unknown fields. We
225 // should only call mutable_unknown_fields if there are actual unknown fields.
226 // The obvious thing to just use a stack string and swap it at the end of
227 // the parse won't work, because the destructor of StringOutputStream needs to
228 // be called before we can modify the string (it check-fails). Using
229 // LiteUnknownFieldSetter setter(&_internal_metadata_);
230 // StringOutputStream stream(setter.buffer());
231 // guarantees that the string is only swapped after stream is destroyed.
232 class PROTOBUF_EXPORT LiteUnknownFieldSetter {
233  public:
LiteUnknownFieldSetter(InternalMetadata * metadata)234   explicit LiteUnknownFieldSetter(InternalMetadata* metadata)
235       : metadata_(metadata) {
236     if (metadata->have_unknown_fields()) {
237       buffer_.swap(*metadata->mutable_unknown_fields<std::string>());
238     }
239   }
~LiteUnknownFieldSetter()240   ~LiteUnknownFieldSetter() {
241     if (!buffer_.empty())
242       metadata_->mutable_unknown_fields<std::string>()->swap(buffer_);
243   }
buffer()244   std::string* buffer() { return &buffer_; }
245 
246  private:
247   InternalMetadata* metadata_;
248   std::string buffer_;
249 };
250 
251 }  // namespace internal
252 }  // namespace protobuf
253 }  // namespace google
254 
255 #include "google/protobuf/port_undef.inc"
256 
257 #endif  // GOOGLE_PROTOBUF_METADATA_LITE_H__
258