• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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