| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 | 
							- // Copyright 2020 The Abseil Authors.
 
- //
 
- // Licensed under the Apache License, Version 2.0 (the "License");
 
- // you may not use this file except in compliance with the License.
 
- // You may obtain a copy of the License at
 
- //
 
- //      https://www.apache.org/licenses/LICENSE-2.0
 
- //
 
- // Unless required by applicable law or agreed to in writing, software
 
- // distributed under the License is distributed on an "AS IS" BASIS,
 
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
- // See the License for the specific language governing permissions and
 
- // limitations under the License.
 
- #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 
- #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 
- #include <string.h>
 
- #include <wchar.h>
 
- #include <cstdio>
 
- #include <iomanip>
 
- #include <limits>
 
- #include <memory>
 
- #include <sstream>
 
- #include <string>
 
- #include <type_traits>
 
- #include "absl/base/port.h"
 
- #include "absl/meta/type_traits.h"
 
- #include "absl/numeric/int128.h"
 
- #include "absl/strings/internal/str_format/extension.h"
 
- #include "absl/strings/string_view.h"
 
- namespace absl {
 
- ABSL_NAMESPACE_BEGIN
 
- class Cord;
 
- class FormatCountCapture;
 
- class FormatSink;
 
- template <absl::FormatConversionCharSet C>
 
- struct FormatConvertResult;
 
- class FormatConversionSpec;
 
- namespace str_format_internal {
 
- template <typename T, typename = void>
 
- struct HasUserDefinedConvert : std::false_type {};
 
- template <typename T>
 
- struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
 
-                                     std::declval<const T&>(),
 
-                                     std::declval<const FormatConversionSpec&>(),
 
-                                     std::declval<FormatSink*>()))>>
 
-     : std::true_type {};
 
- void AbslFormatConvert();  // Stops the lexical name lookup
 
- template <typename T>
 
- auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
 
-                        FormatSinkImpl* sink)
 
-     -> decltype(AbslFormatConvert(v,
 
-                                   std::declval<const FormatConversionSpec&>(),
 
-                                   std::declval<FormatSink*>())) {
 
-   using FormatConversionSpecT =
 
-       absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
 
-   using FormatSinkT =
 
-       absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
 
-   auto fcs = conv.Wrap<FormatConversionSpecT>();
 
-   auto fs = sink->Wrap<FormatSinkT>();
 
-   return AbslFormatConvert(v, fcs, &fs);
 
- }
 
- template <typename T>
 
- class StreamedWrapper;
 
- // If 'v' can be converted (in the printf sense) according to 'conv',
 
- // then convert it, appending to `sink` and return `true`.
 
- // Otherwise fail and return `false`.
 
- // AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
 
- // as an extension mechanism. These FormatConvertImpl functions are the default
 
- // implementations.
 
- // The ADL search is augmented via the 'Sink*' parameter, which also
 
- // serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
 
- // functions in the namespaces associated with 'v'.
 
- // Raw pointers.
 
- struct VoidPtr {
 
-   VoidPtr() = default;
 
-   template <typename T,
 
-             decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0>
 
-   VoidPtr(T* ptr)  // NOLINT
 
-       : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
 
-   uintptr_t value;
 
- };
 
- template <FormatConversionCharSet C>
 
- struct ArgConvertResult {
 
-   bool value;
 
- };
 
- template <FormatConversionCharSet C>
 
- constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
 
-   return C;
 
- }
 
- template <FormatConversionCharSet C>
 
- constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
 
-   return C;
 
- }
 
- using StringConvertResult =
 
-     ArgConvertResult<FormatConversionCharSetInternal::s>;
 
- ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
 
-     VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
 
- // Strings.
 
- StringConvertResult FormatConvertImpl(const std::string& v,
 
-                                       FormatConversionSpecImpl conv,
 
-                                       FormatSinkImpl* sink);
 
- StringConvertResult FormatConvertImpl(string_view v,
 
-                                       FormatConversionSpecImpl conv,
 
-                                       FormatSinkImpl* sink);
 
- ArgConvertResult<FormatConversionCharSetUnion(
 
-     FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
 
- FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
 
-                   FormatSinkImpl* sink);
 
- template <class AbslCord, typename std::enable_if<std::is_same<
 
-                               AbslCord, absl::Cord>::value>::type* = nullptr>
 
- StringConvertResult FormatConvertImpl(const AbslCord& value,
 
-                                       FormatConversionSpecImpl conv,
 
-                                       FormatSinkImpl* sink) {
 
-   bool is_left = conv.has_left_flag();
 
-   size_t space_remaining = 0;
 
-   int width = conv.width();
 
-   if (width >= 0) space_remaining = width;
 
-   size_t to_write = value.size();
 
-   int precision = conv.precision();
 
-   if (precision >= 0)
 
-     to_write = (std::min)(to_write, static_cast<size_t>(precision));
 
-   space_remaining = Excess(to_write, space_remaining);
 
-   if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
 
-   for (string_view piece : value.Chunks()) {
 
-     if (piece.size() > to_write) {
 
-       piece.remove_suffix(piece.size() - to_write);
 
-       to_write = 0;
 
-     } else {
 
-       to_write -= piece.size();
 
-     }
 
-     sink->Append(piece);
 
-     if (to_write == 0) {
 
-       break;
 
-     }
 
-   }
 
-   if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
 
-   return {true};
 
- }
 
- using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
 
-     FormatConversionCharSetInternal::c,
 
-     FormatConversionCharSetInternal::kNumeric,
 
-     FormatConversionCharSetInternal::kStar)>;
 
- using FloatingConvertResult =
 
-     ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
 
- // Floats.
 
- FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- FloatingConvertResult FormatConvertImpl(long double v,
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- // Chars.
 
- IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(signed char v,
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(unsigned char v,
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- // Ints.
 
- IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(unsigned v,
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- IntegralConvertResult FormatConvertImpl(uint128 v,
 
-                                         FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink);
 
- template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
 
- IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
 
-                                         FormatSinkImpl* sink) {
 
-   return FormatConvertImpl(static_cast<int>(v), conv, sink);
 
- }
 
- // We provide this function to help the checker, but it is never defined.
 
- // FormatArgImpl will use the underlying Convert functions instead.
 
- template <typename T>
 
- typename std::enable_if<std::is_enum<T>::value &&
 
-                             !HasUserDefinedConvert<T>::value,
 
-                         IntegralConvertResult>::type
 
- FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
 
- template <typename T>
 
- StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
 
-                                       FormatConversionSpecImpl conv,
 
-                                       FormatSinkImpl* out) {
 
-   std::ostringstream oss;
 
-   oss << v.v_;
 
-   if (!oss) return {false};
 
-   return str_format_internal::FormatConvertImpl(oss.str(), conv, out);
 
- }
 
- // Use templates and dependent types to delay evaluation of the function
 
- // until after FormatCountCapture is fully defined.
 
- struct FormatCountCaptureHelper {
 
-   template <class T = int>
 
-   static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
 
-       const FormatCountCapture& v, FormatConversionSpecImpl conv,
 
-       FormatSinkImpl* sink) {
 
-     const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
 
-     if (conv.conversion_char() !=
 
-         str_format_internal::FormatConversionCharInternal::n) {
 
-       return {false};
 
-     }
 
-     *v2.p_ = static_cast<int>(sink->size());
 
-     return {true};
 
-   }
 
- };
 
- template <class T = int>
 
- ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
 
-     const FormatCountCapture& v, FormatConversionSpecImpl conv,
 
-     FormatSinkImpl* sink) {
 
-   return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
 
- }
 
- // Helper friend struct to hide implementation details from the public API of
 
- // FormatArgImpl.
 
- struct FormatArgImplFriend {
 
-   template <typename Arg>
 
-   static bool ToInt(Arg arg, int* out) {
 
-     // A value initialized FormatConversionSpecImpl has a `none` conv, which
 
-     // tells the dispatcher to run the `int` conversion.
 
-     return arg.dispatcher_(arg.data_, {}, out);
 
-   }
 
-   template <typename Arg>
 
-   static bool Convert(Arg arg, FormatConversionSpecImpl conv,
 
-                       FormatSinkImpl* out) {
 
-     return arg.dispatcher_(arg.data_, conv, out);
 
-   }
 
-   template <typename Arg>
 
-   static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) {
 
-     return arg.dispatcher_;
 
-   }
 
- };
 
- template <typename Arg>
 
- constexpr FormatConversionCharSet ArgumentToConv() {
 
-   return absl::str_format_internal::ExtractCharSet(
 
-       decltype(str_format_internal::FormatConvertImpl(
 
-           std::declval<const Arg&>(),
 
-           std::declval<const FormatConversionSpecImpl&>(),
 
-           std::declval<FormatSinkImpl*>())){});
 
- }
 
- // A type-erased handle to a format argument.
 
- class FormatArgImpl {
 
-  private:
 
-   enum { kInlinedSpace = 8 };
 
-   using VoidPtr = str_format_internal::VoidPtr;
 
-   union Data {
 
-     const void* ptr;
 
-     const volatile void* volatile_ptr;
 
-     char buf[kInlinedSpace];
 
-   };
 
-   using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
 
-   template <typename T>
 
-   struct store_by_value
 
-       : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) &&
 
-                                          (std::is_integral<T>::value ||
 
-                                           std::is_floating_point<T>::value ||
 
-                                           std::is_pointer<T>::value ||
 
-                                           std::is_same<VoidPtr, T>::value)> {};
 
-   enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue };
 
-   template <typename T>
 
-   struct storage_policy
 
-       : std::integral_constant<StoragePolicy,
 
-                                (std::is_volatile<T>::value
 
-                                     ? ByVolatilePointer
 
-                                     : (store_by_value<T>::value ? ByValue
 
-                                                                 : ByPointer))> {
 
-   };
 
-   // To reduce the number of vtables we will decay values before hand.
 
-   // Anything with a user-defined Convert will get its own vtable.
 
-   // For everything else:
 
-   //   - Decay char* and char arrays into `const char*`
 
-   //   - Decay any other pointer to `const void*`
 
-   //   - Decay all enums to their underlying type.
 
-   //   - Decay function pointers to void*.
 
-   template <typename T, typename = void>
 
-   struct DecayType {
 
-     static constexpr bool kHasUserDefined =
 
-         str_format_internal::HasUserDefinedConvert<T>::value;
 
-     using type = typename std::conditional<
 
-         !kHasUserDefined && std::is_convertible<T, const char*>::value,
 
-         const char*,
 
-         typename std::conditional<!kHasUserDefined &&
 
-                                       std::is_convertible<T, VoidPtr>::value,
 
-                                   VoidPtr, const T&>::type>::type;
 
-   };
 
-   template <typename T>
 
-   struct DecayType<T,
 
-                    typename std::enable_if<
 
-                        !str_format_internal::HasUserDefinedConvert<T>::value &&
 
-                        std::is_enum<T>::value>::type> {
 
-     using type = typename std::underlying_type<T>::type;
 
-   };
 
-  public:
 
-   template <typename T>
 
-   explicit FormatArgImpl(const T& value) {
 
-     using D = typename DecayType<T>::type;
 
-     static_assert(
 
-         std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue,
 
-         "Decayed types must be stored by value");
 
-     Init(static_cast<D>(value));
 
-   }
 
-  private:
 
-   friend struct str_format_internal::FormatArgImplFriend;
 
-   template <typename T, StoragePolicy = storage_policy<T>::value>
 
-   struct Manager;
 
-   template <typename T>
 
-   struct Manager<T, ByPointer> {
 
-     static Data SetValue(const T& value) {
 
-       Data data;
 
-       data.ptr = std::addressof(value);
 
-       return data;
 
-     }
 
-     static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); }
 
-   };
 
-   template <typename T>
 
-   struct Manager<T, ByVolatilePointer> {
 
-     static Data SetValue(const T& value) {
 
-       Data data;
 
-       data.volatile_ptr = &value;
 
-       return data;
 
-     }
 
-     static const T& Value(Data arg) {
 
-       return *static_cast<const T*>(arg.volatile_ptr);
 
-     }
 
-   };
 
-   template <typename T>
 
-   struct Manager<T, ByValue> {
 
-     static Data SetValue(const T& value) {
 
-       Data data;
 
-       memcpy(data.buf, &value, sizeof(value));
 
-       return data;
 
-     }
 
-     static T Value(Data arg) {
 
-       T value;
 
-       memcpy(&value, arg.buf, sizeof(T));
 
-       return value;
 
-     }
 
-   };
 
-   template <typename T>
 
-   void Init(const T& value) {
 
-     data_ = Manager<T>::SetValue(value);
 
-     dispatcher_ = &Dispatch<T>;
 
-   }
 
-   template <typename T>
 
-   static int ToIntVal(const T& val) {
 
-     using CommonType = typename std::conditional<std::is_signed<T>::value,
 
-                                                  int64_t, uint64_t>::type;
 
-     if (static_cast<CommonType>(val) >
 
-         static_cast<CommonType>((std::numeric_limits<int>::max)())) {
 
-       return (std::numeric_limits<int>::max)();
 
-     } else if (std::is_signed<T>::value &&
 
-                static_cast<CommonType>(val) <
 
-                    static_cast<CommonType>((std::numeric_limits<int>::min)())) {
 
-       return (std::numeric_limits<int>::min)();
 
-     }
 
-     return static_cast<int>(val);
 
-   }
 
-   template <typename T>
 
-   static bool ToInt(Data arg, int* out, std::true_type /* is_integral */,
 
-                     std::false_type) {
 
-     *out = ToIntVal(Manager<T>::Value(arg));
 
-     return true;
 
-   }
 
-   template <typename T>
 
-   static bool ToInt(Data arg, int* out, std::false_type,
 
-                     std::true_type /* is_enum */) {
 
-     *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>(
 
-         Manager<T>::Value(arg)));
 
-     return true;
 
-   }
 
-   template <typename T>
 
-   static bool ToInt(Data, int*, std::false_type, std::false_type) {
 
-     return false;
 
-   }
 
-   template <typename T>
 
-   static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
 
-     // A `none` conv indicates that we want the `int` conversion.
 
-     if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
 
-                            FormatConversionCharInternal::kNone)) {
 
-       return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
 
-                       std::is_enum<T>());
 
-     }
 
-     if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
 
-                                      spec.conversion_char()))) {
 
-       return false;
 
-     }
 
-     return str_format_internal::FormatConvertImpl(
 
-                Manager<T>::Value(arg), spec,
 
-                static_cast<FormatSinkImpl*>(out))
 
-         .value;
 
-   }
 
-   Data data_;
 
-   Dispatcher dispatcher_;
 
- };
 
- #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E)                     \
 
-   E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
 
-                                              void*)
 
- #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...)                   \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr,     \
 
-                                              __VA_ARGS__);                     \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__);               \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__);               \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__);        \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__);      \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short,      /* NOLINT */ \
 
-                                              __VA_ARGS__);                     \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__);                \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__);       \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */  \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long,      /* NOLINT */  \
 
-                                              __VA_ARGS__);                     \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */           \
 
-                                              __VA_ARGS__);                     \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */  \
 
-                                              __VA_ARGS__);                     \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__);             \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__);            \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__);              \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__);             \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__);        \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__);        \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__);        \
 
-   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__)
 
- ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
 
- }  // namespace str_format_internal
 
- ABSL_NAMESPACE_END
 
- }  // namespace absl
 
- #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 
 
  |