-- f9f068aa8a260dc576398e47b8e4540902e41358 by Derek Mauro <dmauro@google.com>: Fix test string with embedded NUL. Currently parses as octal. PiperOrigin-RevId: 237088193 -- d271ffdd3f450f817f6d30e98ff39d439aaf3a98 by Abseil Team <absl-team@google.com>: Make symbolizer examine any mapping with read+exec permission regardless of 'w' bit. PiperOrigin-RevId: 237056461 -- af315f8306d36a7367a452fd0b58cafdbf20719d by Abseil Team <absl-team@google.com>: Switch comments referencing base:: CondVar and Mutex to absl::. PiperOrigin-RevId: 236917884 -- c624d5d1c0bdb917bff5e651ba40599472f84e0e by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 236898300 -- 3cdc82429af964846d1152f49148abc61d196a4b by Samuel Benzaquen <sbenza@google.com>: Make the `long double` overload if AbslHashValue a template to avoid invalid conversions with implicit operators. This overload was never meant to capture anything other than `long double` and any current caller to it that wasn't a `long double` is potentially a bug. In particular, any type with an implicit `bool` conversion is calling this overload instead of trying to find a hash<> specialization, thus causing pretty bad hash behavior. PiperOrigin-RevId: 236877073 GitOrigin-RevId: f9f068aa8a260dc576398e47b8e4540902e41358 Change-Id: If9cc008dd814f0ca06ed881f612c06575f1f7137
		
			
				
	
	
		
			197 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 | |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 | |
| 
 | |
| #include <array>
 | |
| #include <cstdio>
 | |
| #include <sstream>
 | |
| #include <string>
 | |
| 
 | |
| #include "absl/base/port.h"
 | |
| #include "absl/container/inlined_vector.h"
 | |
| #include "absl/strings/internal/str_format/arg.h"
 | |
| #include "absl/strings/internal/str_format/checker.h"
 | |
| #include "absl/strings/internal/str_format/parser.h"
 | |
| #include "absl/types/span.h"
 | |
| 
 | |
| namespace absl {
 | |
| 
 | |
| class UntypedFormatSpec;
 | |
| 
 | |
| namespace str_format_internal {
 | |
| 
 | |
| class BoundConversion : public ConversionSpec {
 | |
|  public:
 | |
|   const FormatArgImpl* arg() const { return arg_; }
 | |
|   void set_arg(const FormatArgImpl* a) { arg_ = a; }
 | |
| 
 | |
|  private:
 | |
|   const FormatArgImpl* arg_;
 | |
| };
 | |
| 
 | |
| // This is the type-erased class that the implementation uses.
 | |
| class UntypedFormatSpecImpl {
 | |
|  public:
 | |
|   UntypedFormatSpecImpl() = delete;
 | |
| 
 | |
|   explicit UntypedFormatSpecImpl(string_view s)
 | |
|       : data_(s.data()), size_(s.size()) {}
 | |
|   explicit UntypedFormatSpecImpl(
 | |
|       const str_format_internal::ParsedFormatBase* pc)
 | |
|       : data_(pc), size_(~size_t{}) {}
 | |
| 
 | |
|   bool has_parsed_conversion() const { return size_ == ~size_t{}; }
 | |
| 
 | |
|   string_view str() const {
 | |
|     assert(!has_parsed_conversion());
 | |
|     return string_view(static_cast<const char*>(data_), size_);
 | |
|   }
 | |
|   const str_format_internal::ParsedFormatBase* parsed_conversion() const {
 | |
|     assert(has_parsed_conversion());
 | |
|     return static_cast<const str_format_internal::ParsedFormatBase*>(data_);
 | |
|   }
 | |
| 
 | |
|   template <typename T>
 | |
|   static const UntypedFormatSpecImpl& Extract(const T& s) {
 | |
|     return s.spec_;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   const void* data_;
 | |
|   size_t size_;
 | |
| };
 | |
| 
 | |
| template <typename T, typename...>
 | |
| struct MakeDependent {
 | |
|   using type = T;
 | |
| };
 | |
| 
 | |
| // Implicitly convertible from `const char*`, `string_view`, and the
 | |
| // `ExtendedParsedFormat` type. This abstraction allows all format functions to
 | |
| // operate on any without providing too many overloads.
 | |
| template <typename... Args>
 | |
| class FormatSpecTemplate
 | |
|     : public MakeDependent<UntypedFormatSpec, Args...>::type {
 | |
|   using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
 | |
| 
 | |
|  public:
 | |
| #if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 | |
| 
 | |
|   // Honeypot overload for when the std::string is not constexpr.
 | |
|   // We use the 'unavailable' attribute to give a better compiler error than
 | |
|   // just 'method is deleted'.
 | |
|   FormatSpecTemplate(...)  // NOLINT
 | |
|       __attribute__((unavailable("Format std::string is not constexpr.")));
 | |
| 
 | |
|   // Honeypot overload for when the format is constexpr and invalid.
 | |
|   // We use the 'unavailable' attribute to give a better compiler error than
 | |
|   // just 'method is deleted'.
 | |
|   // To avoid checking the format twice, we just check that the format is
 | |
|   // constexpr. If is it valid, then the overload below will kick in.
 | |
|   // We add the template here to make this overload have lower priority.
 | |
|   template <typename = void>
 | |
|   FormatSpecTemplate(const char* s)  // NOLINT
 | |
|       __attribute__((
 | |
|           enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"),
 | |
|           unavailable(
 | |
|               "Format specified does not match the arguments passed.")));
 | |
| 
 | |
|   template <typename T = void>
 | |
|   FormatSpecTemplate(string_view s)  // NOLINT
 | |
|       __attribute__((enable_if(str_format_internal::EnsureConstexpr(s),
 | |
|                                "constexpr trap"))) {
 | |
|     static_assert(sizeof(T*) == 0,
 | |
|                   "Format specified does not match the arguments passed.");
 | |
|   }
 | |
| 
 | |
|   // Good format overload.
 | |
|   FormatSpecTemplate(const char* s)  // NOLINT
 | |
|       __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
 | |
|                                "bad format trap")))
 | |
|       : Base(s) {}
 | |
| 
 | |
|   FormatSpecTemplate(string_view s)  // NOLINT
 | |
|       __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
 | |
|                                "bad format trap")))
 | |
|       : Base(s) {}
 | |
| 
 | |
| #else  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 | |
| 
 | |
|   FormatSpecTemplate(const char* s) : Base(s) {}  // NOLINT
 | |
|   FormatSpecTemplate(string_view s) : Base(s) {}  // NOLINT
 | |
| 
 | |
| #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 | |
| 
 | |
|   template <Conv... C, typename = typename std::enable_if<
 | |
|                            sizeof...(C) == sizeof...(Args) &&
 | |
|                            AllOf(Contains(ArgumentToConv<Args>(),
 | |
|                                           C)...)>::type>
 | |
|   FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
 | |
|       : Base(&pc) {}
 | |
| };
 | |
| 
 | |
| template <typename... Args>
 | |
| struct FormatSpecDeductionBarrier {
 | |
|   using type = FormatSpecTemplate<Args...>;
 | |
| };
 | |
| 
 | |
| class Streamable {
 | |
|  public:
 | |
|   Streamable(const UntypedFormatSpecImpl& format,
 | |
|              absl::Span<const FormatArgImpl> args)
 | |
|       : format_(format), args_(args.begin(), args.end()) {}
 | |
| 
 | |
|   std::ostream& Print(std::ostream& os) const;
 | |
| 
 | |
|   friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
 | |
|     return l.Print(os);
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   const UntypedFormatSpecImpl& format_;
 | |
|   absl::InlinedVector<FormatArgImpl, 4> args_;
 | |
| };
 | |
| 
 | |
| // for testing
 | |
| std::string Summarize(UntypedFormatSpecImpl format,
 | |
|                       absl::Span<const FormatArgImpl> args);
 | |
| bool BindWithPack(const UnboundConversion* props,
 | |
|                   absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
 | |
| 
 | |
| bool FormatUntyped(FormatRawSinkImpl raw_sink,
 | |
|                    UntypedFormatSpecImpl format,
 | |
|                    absl::Span<const FormatArgImpl> args);
 | |
| 
 | |
| std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
 | |
|                         absl::Span<const FormatArgImpl> args);
 | |
| 
 | |
| inline std::string FormatPack(const UntypedFormatSpecImpl format,
 | |
|                               absl::Span<const FormatArgImpl> args) {
 | |
|   std::string out;
 | |
|   AppendPack(&out, format, args);
 | |
|   return out;
 | |
| }
 | |
| 
 | |
| int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
 | |
|             absl::Span<const FormatArgImpl> args);
 | |
| int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
 | |
|              absl::Span<const FormatArgImpl> args);
 | |
| 
 | |
| // Returned by Streamed(v). Converts via '%s' to the std::string created
 | |
| // by std::ostream << v.
 | |
| template <typename T>
 | |
| class StreamedWrapper {
 | |
|  public:
 | |
|   explicit StreamedWrapper(const T& v) : v_(v) { }
 | |
| 
 | |
|  private:
 | |
|   template <typename S>
 | |
|   friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v,
 | |
|                                                   ConversionSpec conv,
 | |
|                                                   FormatSinkImpl* out);
 | |
|   const T& v_;
 | |
| };
 | |
| 
 | |
| }  // namespace str_format_internal
 | |
| }  // namespace absl
 | |
| 
 | |
| #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 |