Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-13 08:23:32

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_MICRO_STRING_H__
0009 #define GOOGLE_PROTOBUF_MICRO_STRING_H__
0010 
0011 #include <cstddef>
0012 #include <cstdint>
0013 
0014 #include "absl/base/config.h"
0015 #include "absl/log/absl_check.h"
0016 #include "absl/strings/string_view.h"
0017 #include "google/protobuf/arena.h"
0018 
0019 // must be last:
0020 #include "google/protobuf/port_def.inc"
0021 
0022 namespace google {
0023 namespace protobuf {
0024 namespace internal {
0025 
0026 struct MicroStringTestPeer;
0027 
0028 // The MicroString class holds a `char` buffer.
0029 // The basic usage provides `Set` and `Get` functions that deal with
0030 // `absl::string_view`.
0031 // It has several layers of optimizations for different sized payloads, as well
0032 // as some features for unowned payloads.
0033 //
0034 // It can be in one of several representations, each with their own properties:
0035 //  - Inline: When enabled, Inline instances store the bytes inlined in the
0036 //            class. They require no memory allocation.
0037 //            This representation holds the size in the first (lsb) byte (left
0038 //            shifted to allow for tags) and the rest of the bytes are the data.
0039 //            The inline buffer can span beyond the `MicroString` class (see
0040 //            `MicroStringExtra` below). To support this most operations take
0041 //            the `inline_capacity` dynamically so that `MicroStringExtra` and
0042 //            the runtime can pass the real buffer size.
0043 //  - MicroRep: Cheapest out of line representation. It is two `uint8_t` for
0044 //              capacity and size, then the char buffer.
0045 //  - LargeRep: The following representations use LargeRep as the header,
0046 //              differentiating themselves via the `capacity` field.
0047 //    * kOwned: A `char` array follows the base. Similar to MicroRep, but with
0048 //              2^32 byte limit, instead of 2^8.
0049 //    * kAlias: The base points into an aliased unowned buffer. The base itself
0050 //              is owned. Used for `SetAlias`.
0051 //              Copying the MicroString will make its own copy of the data, as
0052 //              alias lifetime is not guaranteed beyond the original message.
0053 //    * kUnowned: Similar to kAlias, but the base is also unowned. Both the base
0054 //                and the payload are guaranteed immutable and immortal. Used
0055 //                for global strings, like non-empty default values.
0056 //                Requires no memory allocation. Copying the MicroString will
0057 //                maintain the unowned status and require no memory allocation.
0058 //    * kString: The object holds a StringRep. The base points into the
0059 //               `std::string` instance. Used for `SetString` to allow taking
0060 //               ownership of `std::string` payloads.
0061 //               Copying the MicroString will not maintain the kString state, as
0062 //               it is unnecessary. The copy will use normal reps.
0063 //
0064 //
0065 // All the functions that write to the inline space take the inline capacity as
0066 // a parameter. This allows the subclass to extend the capacity while the base
0067 // class handles the logic. It also allows external callers, like reflection, to
0068 // pass the dynamically known capacity.
0069 class PROTOBUF_EXPORT MicroString {
0070   struct LargeRep {
0071     char* payload;
0072     uint32_t size;
0073     // One of LargeRepKind, or the capacity for the owned buffer.
0074     uint32_t capacity;
0075 
0076     absl::string_view view() const { return {payload, size}; }
0077     char* owned_head() {
0078       ABSL_DCHECK_GE(capacity, kOwned);
0079       return reinterpret_cast<char*>(this + 1);
0080     }
0081 
0082     void SetExternalBuffer(absl::string_view buffer) {
0083       payload = const_cast<char*>(buffer.data());
0084       size = buffer.size();
0085     }
0086 
0087     void SetInitialSize(size_t size) {
0088       PoisonMemoryRegion(owned_head() + size, capacity - size);
0089       this->size = size;
0090     }
0091 
0092     void Unpoison() { UnpoisonMemoryRegion(owned_head(), capacity); }
0093 
0094     void ChangeSize(size_t new_size) {
0095       PoisonMemoryRegion(owned_head() + new_size, capacity - new_size);
0096       UnpoisonMemoryRegion(owned_head(), new_size);
0097       size = new_size;
0098     }
0099   };
0100 
0101   struct MicroRep {
0102     uint8_t size;
0103     uint8_t capacity;
0104 
0105     char* data() { return reinterpret_cast<char*>(this + 1); }
0106     const char* data() const { return reinterpret_cast<const char*>(this + 1); }
0107     absl::string_view view() const { return {data(), size}; }
0108 
0109     void SetInitialSize(uint8_t size) {
0110       PoisonMemoryRegion(data() + size, capacity - size);
0111       this->size = size;
0112     }
0113 
0114     void Unpoison() { UnpoisonMemoryRegion(data(), capacity); }
0115 
0116     void ChangeSize(uint8_t new_size) {
0117       PoisonMemoryRegion(data() + new_size, capacity - new_size);
0118       UnpoisonMemoryRegion(data(), new_size);
0119       size = new_size;
0120     }
0121   };
0122 
0123  public:
0124   // We don't allow extra capacity in big-endian because it is harder to manage
0125   // the pointer to the MicroString "base".
0126   static constexpr bool kAllowExtraCapacity = IsLittleEndian();
0127   static constexpr size_t kInlineCapacity = sizeof(uintptr_t) - 1;
0128   static constexpr size_t kMaxMicroRepCapacity = 256 - sizeof(MicroRep);
0129 
0130   // Empty string.
0131   constexpr MicroString() : rep_() {}
0132 
0133   explicit MicroString(Arena*) : MicroString() {}
0134 
0135   MicroString(Arena* arena, const MicroString& other)
0136       : MicroString(FromOtherTag{}, other, arena) {}
0137 
0138   // Trivial destructor.
0139   // The payload must be destroyed via `Destroy()` when not in an arena. If
0140   // using arenas, no destruction is necessary and calls to `Destroy()` are
0141   // invalid.
0142   ~MicroString() = default;
0143 
0144   union UnownedPayload {
0145     LargeRep payload;
0146     // We use a union to be able to get an unaligned pointer for the
0147     // payload in the constexpr constructor. `for_tag + kIsLargeRepTag` is
0148     // equivalent to `reinterpret_cast<uintptr_t>(&payload) | kIsLargeRepTag`
0149     // but works during constant evaluation.
0150     char for_tag[1];
0151 
0152     // To match the LazyString API.
0153     auto get() const { return payload.view(); }
0154   };
0155   constexpr MicroString(const UnownedPayload& unowned_input)  // NOLINT
0156       : rep_(const_cast<char*>(unowned_input.for_tag + kIsLargeRepTag)) {}
0157 
0158   // Like the constructor above, but for DynamicMessage where we don't have a
0159   // generated UnownedPayload to pass.
0160   // The instance created has to be destroyed with
0161   // `DestroyDefaultValuePrototype`.
0162   static MicroString MakeDefaultValuePrototype(absl::string_view default_value);
0163   void DestroyDefaultValuePrototype();
0164 
0165   // Resets value to the default constructor state.
0166   // Disregards initial value of rep_ (so this is the *ONLY* safe method to call
0167   // after construction or when reinitializing after becoming the active field
0168   // in a oneof union).
0169   void InitDefault() { rep_ = nullptr; }
0170 
0171   // Destroys the payload.
0172   // REQUIRES: no arenas. Trying to destroy a string constructed with arenas is
0173   // invalid and there is no checking for it.
0174   void Destroy() {
0175     if (!is_inline()) DestroySlow();
0176   }
0177 
0178   // Resets the object to the empty string.
0179   // Does not necessarily release any memory.
0180   void Clear() {
0181     if (is_inline()) {
0182       set_inline_size(0);
0183       return;
0184     }
0185     ClearSlow();
0186   }
0187 
0188   // Sets the payload to `other`. Copy behavior depends on the kind of payload.
0189   void Set(const MicroString& other, Arena* arena) {
0190     SetFromOtherImpl(*this, other, arena);
0191   }
0192 
0193   void Set(const MicroString& other, Arena* arena, size_t inline_capacity) {
0194     // Unowned property gets propagated, even if we have a rep already.
0195     if (other.is_large_rep() && other.large_rep_kind() == kUnowned) {
0196       if (arena == nullptr) Destroy();
0197       rep_ = other.rep_;
0198       return;
0199     }
0200     Set(other.Get(), arena, inline_capacity);
0201   }
0202 
0203   // Sets the payload to `data`. Always copies the data.
0204   void Set(absl::string_view data, Arena* arena) {
0205     SetMaybeConstant(*this, data, arena);
0206   }
0207   void Set(absl::string_view data, Arena* arena, size_t inline_capacity) {
0208     SetImpl(data, arena, inline_capacity);
0209   }
0210 
0211   // Extra overloads to allow for other implicit conversions.
0212   // Eg types that convert to `std::string` (like
0213   // `std::reference_wrapper<std::string>`).
0214   template <typename... Args>
0215   void Set(const std::string& data, Args... args) {
0216     Set(absl::string_view(data), args...);
0217   }
0218   template <typename... Args>
0219   void Set(std::string&& data, Args... args) {
0220     SetString(std::move(data), args...);
0221   }
0222   template <typename... Args>
0223   void Set(const char* data, Args... args) {
0224     Set(absl::string_view(data), args...);
0225   }
0226 
0227   // Sets the payload to `data`. Might copy the data or alias the input buffer.
0228   void SetAlias(absl::string_view data, Arena* arena,
0229                 size_t inline_capacity = kInlineCapacity);
0230 
0231   // Set the payload to `unowned`. Will not allocate memory, but might free
0232   // memory if already set.
0233   void SetUnowned(const UnownedPayload& unowned_input, Arena* arena);
0234 
0235   // To match the API of ArenaStringPtr.
0236   // It resets the value to the passed default, trying to keep preexisting
0237   // buffer if we are on an arena. This reduces arena bloat when reusing a
0238   // message.
0239   void ClearToDefault(const UnownedPayload& unowned_input, Arena* arena);
0240 
0241   // Like above, but takes a prototype `MicroString` that has the unowned rep.
0242   // Used for reflection that does not have access to the `UnownedPayload`.
0243   void ClearToDefault(const MicroString& other, Arena* arena);
0244 
0245   // Set the string, but the input comes in individual chunks.
0246   // This function is designed to be called from the parser.
0247   // `size` is the expected total size of the string. It is ok to append fewer
0248   // bytes than `size`, but never more. The final size of the string will be
0249   // whatever was appended to it.
0250   // `size` is used as a hint to reserve space, but the implementation might
0251   // decide not to do so for very large values and just grow on append.
0252   //
0253   // The `setter` callback is passed an `append` callback that it can use to
0254   // append the chunks one by one.
0255   // Eg
0256   //
0257   // str.SetInChunks(10, arena, [](auto append) {
0258   //   append("12345");
0259   //   append("67890");
0260   // });
0261   //
0262   // The callback approach reduces the dispatch overhead to be done only once
0263   // instead of on each append call.
0264   template <typename F>
0265   void SetInChunks(size_t size, Arena* arena, F setter,
0266                    size_t inline_capacity = kInlineCapacity);
0267 
0268   // The capacity for write access of this string.
0269   // It can be 0 if the payload is not writable. For example, aliased buffers.
0270   size_t Capacity() const;
0271 
0272   size_t SpaceUsedExcludingSelfLong() const;
0273 
0274   absl::string_view Get() const {
0275     if (is_micro_rep()) {
0276       return micro_rep()->view();
0277     } else if (is_inline()) {
0278       return inline_view();
0279     } else {
0280       return large_rep()->view();
0281     }
0282   }
0283 
0284   // To be used by constexpr constructors of fields with non-empty default
0285   // values. It will alias `data` so it must be an immutable input, like a
0286   // literal string.
0287   static constexpr UnownedPayload MakeUnownedPayload(absl::string_view data) {
0288     return UnownedPayload{LargeRep{const_cast<char*>(data.data()),
0289                                    static_cast<uint32_t>(data.size()),
0290                                    kUnowned}};
0291   }
0292 
0293   void InternalSwap(MicroString* other,
0294                     size_t inline_capacity = kInlineCapacity) {
0295     std::swap_ranges(reinterpret_cast<char*>(this),
0296                      reinterpret_cast<char*>(this) + inline_capacity + 1,
0297                      reinterpret_cast<char*>(other));
0298   }
0299 
0300  protected:
0301   friend MicroStringTestPeer;
0302 
0303   struct StringRep : LargeRep {
0304     std::string str;
0305     void ResetBase() { SetExternalBuffer(str); }
0306   };
0307 
0308   static_assert(alignof(void*) >= 4, "We need two tag bits from pointers.");
0309   static constexpr uintptr_t kIsLargeRepTag = 0x1;
0310   static_assert(sizeof(UnownedPayload::for_tag) == kIsLargeRepTag,
0311                 "See comment in for_tag declaration above.");
0312 
0313   static constexpr uintptr_t kIsMicroRepTag = 0x2;
0314   static constexpr int kTagShift = 2;
0315   static constexpr size_t kMaxInlineCapacity = 255 >> kTagShift;
0316 
0317   static_assert((kIsLargeRepTag & kIsMicroRepTag) == 0,
0318                 "The tags are exclusive.");
0319 
0320   enum LargeRepKind {
0321     // The buffer is unowned, but the large_rep payload is owned.
0322     kAlias,
0323     // The whole payload is unowned.
0324     kUnowned,
0325     // The payload is a StringRep payload.
0326     kString,
0327     // An owned LargeRep+chars payload.
0328     // kOwned must be the last one for large_rep_kind() to work.
0329     kOwned
0330   };
0331   LargeRepKind large_rep_kind() const {
0332     ABSL_DCHECK(is_large_rep());
0333     size_t cap = large_rep()->capacity;
0334     return cap >= kOwned ? kOwned : static_cast<LargeRepKind>(cap);
0335   }
0336 
0337   // Micro-optimization: by using kIsMicroRepTag as 2, the MicroRep `rep_`
0338   // pointer (with the tag) is already pointing into the data buffer.
0339   static_assert(sizeof(MicroRep) == kIsMicroRepTag);
0340   MicroRep* micro_rep() const {
0341     ABSL_DCHECK(is_micro_rep());
0342     // NOTE: We use `-` instead of `&` so that the arithmetic gets folded into
0343     // offsets after the cast.
0344     // ie `micro_rep()->data()` cancel each other out.
0345     return reinterpret_cast<MicroRep*>(reinterpret_cast<uintptr_t>(rep_) -
0346                                        kIsMicroRepTag);
0347   }
0348   static size_t MicroRepSize(size_t capacity) {
0349     return sizeof(MicroRep) + capacity;
0350   }
0351   static size_t OwnedRepSize(size_t capacity) {
0352     return sizeof(LargeRep) + capacity;
0353   }
0354 
0355   LargeRep* large_rep() const {
0356     ABSL_DCHECK(is_large_rep());
0357     // NOTE: We use `-` instead of `&` so that the arithmetic gets folded into
0358     // offsets after the cast.
0359     return reinterpret_cast<LargeRep*>(reinterpret_cast<uintptr_t>(rep_) -
0360                                        kIsLargeRepTag);
0361   }
0362   StringRep* string_rep() const {
0363     ABSL_DCHECK_EQ(+kString, +large_rep_kind());
0364     return static_cast<StringRep*>(large_rep());
0365   }
0366 
0367   bool is_micro_rep() const {
0368     return (reinterpret_cast<uintptr_t>(rep_) & kIsMicroRepTag) ==
0369            kIsMicroRepTag;
0370   }
0371   bool is_large_rep() const {
0372     return (reinterpret_cast<uintptr_t>(rep_) & kIsLargeRepTag) ==
0373            kIsLargeRepTag;
0374   }
0375   bool is_inline() const { return !is_micro_rep() && !is_large_rep(); }
0376   size_t inline_size() const {
0377     ABSL_DCHECK(is_inline());
0378     return static_cast<uint8_t>(reinterpret_cast<uintptr_t>(rep_)) >> kTagShift;
0379   }
0380   void set_inline_size(size_t size) {
0381     size <<= kTagShift;
0382     PROTOBUF_ASSUME(size <= 0xFF);
0383     // Only overwrite the size byte to avoid clobbering the char bytes in case
0384     // of aliasing.
0385     rep_ = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(rep_) & ~0xFF) |
0386                                    size);
0387     ABSL_DCHECK(is_inline());
0388   }
0389   char* inline_head() {
0390     ABSL_DCHECK(is_inline());
0391 
0392     // In little-endian the layout is
0393     //    [ size ] [ chars... ]
0394     // while in big endian it is
0395     //    [ chars... ] [ size ]
0396     return IsLittleEndian() ? reinterpret_cast<char*>(&rep_) + 1
0397                             : reinterpret_cast<char*>(&rep_);
0398   }
0399   const char* inline_head() const {
0400     return const_cast<MicroString*>(this)->inline_head();
0401   }
0402   absl::string_view inline_view() const {
0403     return {inline_head(), inline_size()};
0404   }
0405 
0406   // These are templates so that they can implement the logic for the derived
0407   // types too. We need the full type to do the assignment properly.
0408   struct FromOtherTag {};
0409   template <typename Self>
0410   MicroString(FromOtherTag, const Self& other, Arena* arena) {
0411     if (other.is_inline()) {
0412       static_cast<Self&>(*this) = other;
0413       return;
0414     }
0415     // Init as empty and run the slow path.
0416     InitDefault();
0417     SetFromOtherSlow(other, arena, Self::kInlineCapacity);
0418   }
0419 
0420   template <typename Self>
0421   static void SetFromOtherImpl(Self& self, const Self& other, Arena* arena) {
0422     // If inline, just memcpy directly.
0423     // Use bitwise and because we don't want short circuiting. It adds extra
0424     // branches. Cast to `int` to silence -Wbitwise-instead-of-logical.
0425     if (static_cast<int>(self.is_inline()) &
0426         static_cast<int>(other.is_inline())) {
0427       self = other;
0428       return;
0429     }
0430     self.SetFromOtherSlow(other, arena, Self::kInlineCapacity);
0431   }
0432 
0433   // Sets the payload to `str`. Might copy the data or take ownership of `str`.
0434   void SetString(std::string&& data, Arena* arena,
0435                  size_t inline_capacity = kInlineCapacity);
0436 
0437   void SetFromOtherSlow(const MicroString& other, Arena* arena,
0438                         size_t inline_capacity);
0439 
0440   void ClearSlow();
0441 
0442   template <typename Self>
0443   static void SetMaybeConstant(Self& self, absl::string_view data,
0444                                Arena* arena) {
0445     const size_t size = data.size();
0446     if (PROTOBUF_BUILTIN_CONSTANT_P(size <= Self::kInlineCapacity) &&
0447         size <= Self::kInlineCapacity && self.is_inline()) {
0448       // Using a separate local variable allows the optimizer to merge the
0449       // writes better. We do a single write to memory on the assingment below.
0450       Self tmp;
0451       tmp.set_inline_size(size);
0452       if (size != 0) {
0453         memcpy(tmp.inline_head(), data.data(), data.size());
0454       }
0455       self = tmp;
0456       return;
0457     }
0458     self.SetImpl(data, arena, Self::kInlineCapacity);
0459   }
0460   void SetImpl(absl::string_view data, Arena* arena, size_t inline_capacity);
0461 
0462   void DestroySlow();
0463 
0464   // Allocate the corresponding rep, and sets its size and capacity.
0465   // The actual capacity might be larger than the requested one.
0466   // The data bytes are uninitialized.
0467   // rep_ is updated to point to the new rep without any cleanup of the old
0468   // value.
0469   MicroRep* AllocateMicroRep(size_t size, Arena* arena);
0470   LargeRep* AllocateOwnedRep(size_t size, Arena* arena);
0471   StringRep* AllocateStringRep(Arena* arena);
0472 
0473   void* rep_;
0474 };
0475 
0476 template <typename F>
0477 void MicroString::SetInChunks(size_t size, Arena* arena, F setter,
0478                               size_t inline_capacity) {
0479   const auto invoke_setter = [&](char* p) {
0480     char* start = p;
0481     setter([&](absl::string_view chunk) {
0482       ABSL_DCHECK_LE(p - start + chunk.size(), size);
0483       memcpy(p, chunk.data(), chunk.size());
0484       p += chunk.size();
0485     });
0486     return p - start;
0487   };
0488 
0489   const auto do_inline = [&] {
0490     ABSL_DCHECK_LE(size, inline_capacity);
0491     set_inline_size(invoke_setter(inline_head()));
0492   };
0493 
0494   const auto do_micro = [&](MicroRep* r) {
0495     ABSL_DCHECK_LE(size, r->capacity);
0496     r->Unpoison();
0497     r->ChangeSize(invoke_setter(r->data()));
0498   };
0499 
0500   const auto do_owned = [&](LargeRep* r) {
0501     ABSL_DCHECK_LE(size, r->capacity);
0502     r->Unpoison();
0503     r->ChangeSize(invoke_setter(r->owned_head()));
0504   };
0505 
0506   const auto do_string = [&](StringRep* r) {
0507     r->str.clear();
0508     setter([&](absl::string_view chunk) {
0509       r->str.append(chunk.data(), chunk.size());
0510     });
0511     r->ResetBase();
0512   };
0513 
0514   if (is_inline()) {
0515     if (size <= inline_capacity) {
0516       return do_inline();
0517     }
0518   } else if (is_micro_rep()) {
0519     if (auto* r = micro_rep(); size <= r->capacity) {
0520       return do_micro(r);
0521     }
0522   } else if (is_large_rep()) {
0523     switch (large_rep_kind()) {
0524       case kOwned:
0525         if (auto* r = large_rep(); size <= r->capacity) {
0526           return do_owned(r);
0527         }
0528         break;
0529       case kString:
0530         return do_string(string_rep());
0531       case kAlias:
0532       case kUnowned:
0533         break;
0534     }
0535   }
0536 
0537   // Copied from ParseContext as an acceptable size that we can preallocate
0538   // without verifying.
0539   static constexpr size_t kSafeStringSize = 50000000;
0540 
0541   // We didn't have space for it, so allocate the space and dispatch.
0542   if (arena == nullptr) Destroy();
0543 
0544   if (size <= inline_capacity) {
0545     set_inline_size(0);
0546     do_inline();
0547   } else if (size <= kMaxMicroRepCapacity) {
0548     do_micro(AllocateMicroRep(size, arena));
0549   } else if (size <= kSafeStringSize) {
0550     do_owned(AllocateOwnedRep(size, arena));
0551   } else {
0552     // Fallback to using std::string and normal growth instead of reserving.
0553     do_string(AllocateStringRep(arena));
0554   }
0555 }
0556 
0557 // MicroStringExtra lays out the memory as:
0558 //
0559 //   [ MicroString ] [ extra char buffer ]
0560 //
0561 // which in little endian ends up as
0562 //
0563 //   [ char size/tag ] [ MicroStrings's inline space ] [ extra char buffer ]
0564 //
0565 // so from the inline_head() position we can access all the normal and extra
0566 // buffer bytes.
0567 //
0568 // This does not work on bigendian so we disable Extra for now there.
0569 template <size_t RequestedSpace>
0570 class MicroStringExtraImpl : private MicroString {
0571   static constexpr size_t RoundUp(size_t n) {
0572     return (n + (alignof(MicroString) - 1)) & ~(alignof(MicroString) - 1);
0573   }
0574 
0575  public:
0576   // Round up to avoid padding
0577   static constexpr size_t kInlineCapacity =
0578       RoundUp(RequestedSpace + /* inline_size */ 1) - /* inline_size */ 1;
0579 
0580   static_assert(kInlineCapacity < MicroString::kMaxInlineCapacity,
0581                 "Must fit with the tags.");
0582 
0583   constexpr MicroStringExtraImpl() {
0584     // Some compilers don't like to assert kAllowExtraCapacity directly, so make
0585     // the expression dependent.
0586     static_assert(static_cast<int>(RequestedSpace != 0) &
0587                   static_cast<int>(MicroString::kAllowExtraCapacity));
0588   }
0589   MicroStringExtraImpl(Arena* arena, const MicroStringExtraImpl& other)
0590       : MicroString(FromOtherTag{}, other, arena) {}
0591 
0592   using MicroString::Get;
0593   // Redefine the setters, passing the extended inline capacity.
0594   void Set(const MicroStringExtraImpl& other, Arena* arena) {
0595     SetFromOtherImpl(*this, other, arena);
0596   }
0597   void Set(absl::string_view data, Arena* arena) {
0598     SetMaybeConstant(*this, data, arena);
0599   }
0600   void Set(const std::string& data, Arena* arena) {
0601     Set(absl::string_view(data), arena);
0602   }
0603   void Set(const char* data, Arena* arena) {
0604     Set(absl::string_view(data), arena);
0605   }
0606   void Set(std::string&& str, Arena* arena) {
0607     MicroString::SetString(std::move(str), arena, kInlineCapacity);
0608   }
0609 
0610   void SetAlias(absl::string_view data, Arena* arena) {
0611     MicroString::SetAlias(data, arena, kInlineCapacity);
0612   }
0613 
0614   using MicroString::Destroy;
0615 
0616   size_t Capacity() const {
0617     return is_inline() ? kInlineCapacity : MicroString::Capacity();
0618   }
0619 
0620   void InternalSwap(MicroStringExtraImpl* other) {
0621     MicroString::InternalSwap(other, kInlineCapacity);
0622   }
0623 
0624   using MicroString::SpaceUsedExcludingSelfLong;
0625 
0626  private:
0627   friend MicroString;
0628 
0629   char extra_buffer_[kInlineCapacity - MicroString::kInlineCapacity];
0630 };
0631 
0632 // MicroStringExtra allows the user to specify the inline space.
0633 // This will be used in conjunction with profiles that determine expected string
0634 // sizes.
0635 //
0636 // MicroStringExtra<N> will contain at least `N` bytes of inline space, assuming
0637 // inline strings are enabled in this platform.
0638 // If inline strings are not enabled in this platform, then the argument is
0639 // ignored and no inline space is provided.
0640 // It could be rouneded up to prevent padding.
0641 template <size_t InlineCapacity>
0642 using MicroStringExtra =
0643     std::conditional_t<(!MicroString::kAllowExtraCapacity ||
0644                         InlineCapacity <= MicroString::kInlineCapacity),
0645                        MicroString, MicroStringExtraImpl<InlineCapacity>>;
0646 
0647 }  // namespace internal
0648 }  // namespace protobuf
0649 }  // namespace google
0650 
0651 #include "google/protobuf/port_undef.inc"
0652 
0653 #endif  // GOOGLE_PROTOBUF_MICRO_STRING_H__