Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-12 09:13:10

0001 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2008 Google Inc.  All rights reserved.
0003 //
0004 // Use of this source code is governed by a BSD-style
0005 // license that can be found in the LICENSE file or at
0006 // https://developers.google.com/open-source/licenses/bsd
0007 
0008 #ifndef GOOGLE_PROTOBUF_METADATA_LITE_H__
0009 #define GOOGLE_PROTOBUF_METADATA_LITE_H__
0010 
0011 #include <string>
0012 
0013 #include "absl/base/optimization.h"
0014 #include "google/protobuf/arena.h"
0015 #include "google/protobuf/port.h"
0016 
0017 // Must be included last.
0018 #include "google/protobuf/port_def.inc"
0019 
0020 #ifdef SWIG
0021 #error "You cannot SWIG proto headers"
0022 #endif
0023 
0024 namespace google {
0025 namespace protobuf {
0026 
0027 class UnknownFieldSet;
0028 
0029 namespace internal {
0030 
0031 // This is the representation for messages that support arena allocation. It
0032 // uses a tagged pointer to either store the owning Arena pointer, if there are
0033 // no unknown fields, or a pointer to a block of memory with both the owning
0034 // Arena pointer and the UnknownFieldSet, if there are unknown fields. Besides,
0035 // it also uses the tag to distinguish whether the owning Arena pointer is also
0036 // used by sub-structure allocation. This optimization allows for
0037 // "zero-overhead" storage of the Arena pointer, relative to the above baseline
0038 // implementation.
0039 //
0040 // The tagged pointer uses the least two significant bits to disambiguate cases.
0041 // It uses bit 0 == 0 to indicate an arena pointer and bit 0 == 1 to indicate a
0042 // UFS+Arena-container pointer. Besides it uses bit 1 == 0 to indicate arena
0043 // allocation and bit 1 == 1 to indicate heap allocation.
0044 class PROTOBUF_EXPORT InternalMetadata {
0045  public:
0046   constexpr InternalMetadata() : ptr_(0) {}
0047   explicit InternalMetadata(Arena* arena) {
0048     ptr_ = reinterpret_cast<intptr_t>(arena);
0049   }
0050 
0051   // Delete will delete the unknown fields only if they weren't allocated on an
0052   // arena.  Then it updates the flags so that if you call
0053   // have_unknown_fields(), it will return false.
0054   //
0055   // It is designed to be used as part of a Message class's destructor call, so
0056   // that when control eventually gets to ~InternalMetadata(), we don't need to
0057   // check for have_unknown_fields() again.
0058   template <typename T>
0059   void Delete() {
0060     // Note that Delete<> should be called not more than once.
0061     if (have_unknown_fields()) {
0062       DeleteOutOfLineHelper<T>();
0063     }
0064   }
0065 
0066   PROTOBUF_NDEBUG_INLINE Arena* arena() const {
0067     if (ABSL_PREDICT_FALSE(have_unknown_fields())) {
0068       return PtrValue<ContainerBase>()->arena;
0069     } else {
0070       return PtrValue<Arena>();
0071     }
0072   }
0073 
0074   PROTOBUF_NDEBUG_INLINE bool have_unknown_fields() const {
0075     return HasUnknownFieldsTag();
0076   }
0077 
0078   PROTOBUF_NDEBUG_INLINE void* raw_arena_ptr() const {
0079     return reinterpret_cast<void*>(ptr_);
0080   }
0081 
0082   template <typename T>
0083   PROTOBUF_NDEBUG_INLINE const T& unknown_fields(
0084       const T& (*default_instance)()) const {
0085     if (ABSL_PREDICT_FALSE(have_unknown_fields())) {
0086       return PtrValue<Container<T>>()->unknown_fields;
0087     } else {
0088       return default_instance();
0089     }
0090   }
0091 
0092   template <typename T>
0093   PROTOBUF_NDEBUG_INLINE T* mutable_unknown_fields() {
0094     if (ABSL_PREDICT_TRUE(have_unknown_fields())) {
0095       return &PtrValue<Container<T>>()->unknown_fields;
0096     } else {
0097       return mutable_unknown_fields_slow<T>();
0098     }
0099   }
0100 
0101   template <typename T>
0102   PROTOBUF_NDEBUG_INLINE void Swap(InternalMetadata* other) {
0103     // Semantics here are that we swap only the unknown fields, not the arena
0104     // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
0105     // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
0106     // different states (direct arena pointer vs. container with UFS) so we
0107     // cannot simply swap ptr_ and then restore the arena pointers. We reuse
0108     // UFS's swap implementation instead.
0109     if (have_unknown_fields() || other->have_unknown_fields()) {
0110       DoSwap<T>(other->mutable_unknown_fields<T>());
0111     }
0112   }
0113 
0114   PROTOBUF_NDEBUG_INLINE void InternalSwap(
0115       InternalMetadata* PROTOBUF_RESTRICT other) {
0116     std::swap(ptr_, other->ptr_);
0117   }
0118 
0119   template <typename T>
0120   PROTOBUF_NDEBUG_INLINE void MergeFrom(const InternalMetadata& other) {
0121     if (other.have_unknown_fields()) {
0122       DoMergeFrom<T>(other.unknown_fields<T>(nullptr));
0123     }
0124   }
0125 
0126   template <typename T>
0127   PROTOBUF_NDEBUG_INLINE void Clear() {
0128     if (have_unknown_fields()) {
0129       DoClear<T>();
0130     }
0131   }
0132 
0133  private:
0134   intptr_t ptr_;
0135 
0136   // Tagged pointer implementation.
0137   static constexpr intptr_t kUnknownFieldsTagMask = 1;
0138   static constexpr intptr_t kPtrTagMask = kUnknownFieldsTagMask;
0139   static constexpr intptr_t kPtrValueMask = ~kPtrTagMask;
0140 
0141   // Accessors for pointer tag and pointer value.
0142   PROTOBUF_ALWAYS_INLINE bool HasUnknownFieldsTag() const {
0143     return ptr_ & kUnknownFieldsTagMask;
0144   }
0145 
0146   template <typename U>
0147   U* PtrValue() const {
0148     return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
0149   }
0150 
0151   // If ptr_'s tag is kTagContainer, it points to an instance of this struct.
0152   struct ContainerBase {
0153     Arena* arena;
0154   };
0155 
0156   template <typename T>
0157   struct Container : public ContainerBase {
0158     T unknown_fields;
0159   };
0160 
0161   template <typename T>
0162   PROTOBUF_NOINLINE void DeleteOutOfLineHelper() {
0163     delete PtrValue<Container<T>>();
0164     // TODO:  This store is load-bearing.  Since we are destructing
0165     // the message at this point, see if we can eliminate it.
0166     ptr_ = 0;
0167   }
0168 
0169   template <typename T>
0170   PROTOBUF_NOINLINE T* mutable_unknown_fields_slow() {
0171     Arena* my_arena = arena();
0172     Container<T>* container = Arena::Create<Container<T>>(my_arena);
0173     // Two-step assignment works around a bug in clang's static analyzer:
0174     // https://bugs.llvm.org/show_bug.cgi?id=34198.
0175     ptr_ = reinterpret_cast<intptr_t>(container);
0176     ptr_ |= kUnknownFieldsTagMask;
0177     container->arena = my_arena;
0178     return &(container->unknown_fields);
0179   }
0180 
0181   // Templated functions.
0182 
0183   template <typename T>
0184   PROTOBUF_NOINLINE void DoClear() {
0185     mutable_unknown_fields<T>()->Clear();
0186   }
0187 
0188   template <typename T>
0189   PROTOBUF_NOINLINE void DoMergeFrom(const T& other) {
0190     mutable_unknown_fields<T>()->MergeFrom(other);
0191   }
0192 
0193   template <typename T>
0194   PROTOBUF_NOINLINE void DoSwap(T* other) {
0195     mutable_unknown_fields<T>()->Swap(other);
0196   }
0197 
0198   // Private helper with debug checks for ~InternalMetadata()
0199   void CheckedDestruct();
0200 };
0201 
0202 // String Template specializations.
0203 
0204 template <>
0205 PROTOBUF_EXPORT void InternalMetadata::DoClear<std::string>();
0206 template <>
0207 PROTOBUF_EXPORT void InternalMetadata::DoMergeFrom<std::string>(
0208     const std::string& other);
0209 template <>
0210 PROTOBUF_EXPORT void InternalMetadata::DoSwap<std::string>(std::string* other);
0211 
0212 // Instantiated once in message.cc (where the definition of UnknownFieldSet is
0213 // known) to prevent much duplication across translation units of a large build.
0214 extern template PROTOBUF_EXPORT void
0215 InternalMetadata::DoClear<UnknownFieldSet>();
0216 extern template PROTOBUF_EXPORT void
0217 InternalMetadata::DoMergeFrom<UnknownFieldSet>(const UnknownFieldSet& other);
0218 extern template PROTOBUF_EXPORT void
0219 InternalMetadata::DoSwap<UnknownFieldSet>(UnknownFieldSet* other);
0220 extern template PROTOBUF_EXPORT void
0221 InternalMetadata::DeleteOutOfLineHelper<UnknownFieldSet>();
0222 extern template PROTOBUF_EXPORT UnknownFieldSet*
0223 InternalMetadata::mutable_unknown_fields_slow<UnknownFieldSet>();
0224 
0225 // This helper RAII class is needed to efficiently parse unknown fields. We
0226 // should only call mutable_unknown_fields if there are actual unknown fields.
0227 // The obvious thing to just use a stack string and swap it at the end of
0228 // the parse won't work, because the destructor of StringOutputStream needs to
0229 // be called before we can modify the string (it check-fails). Using
0230 // LiteUnknownFieldSetter setter(&_internal_metadata_);
0231 // StringOutputStream stream(setter.buffer());
0232 // guarantees that the string is only swapped after stream is destroyed.
0233 class PROTOBUF_EXPORT LiteUnknownFieldSetter {
0234  public:
0235   explicit LiteUnknownFieldSetter(InternalMetadata* metadata)
0236       : metadata_(metadata) {
0237     if (metadata->have_unknown_fields()) {
0238       buffer_.swap(*metadata->mutable_unknown_fields<std::string>());
0239     }
0240   }
0241   ~LiteUnknownFieldSetter() {
0242     if (!buffer_.empty())
0243       metadata_->mutable_unknown_fields<std::string>()->swap(buffer_);
0244   }
0245   std::string* buffer() { return &buffer_; }
0246 
0247  private:
0248   InternalMetadata* metadata_;
0249   std::string buffer_;
0250 };
0251 
0252 }  // namespace internal
0253 }  // namespace protobuf
0254 }  // namespace google
0255 
0256 #include "google/protobuf/port_undef.inc"
0257 
0258 #endif  // GOOGLE_PROTOBUF_METADATA_LITE_H__