-- c99f979ad34f155fbeeea69b88bdc7458d89a21c by Derek Mauro <dmauro@google.com>: Remove a floating point division by zero test. This isn't testing behavior related to the library, and MSVC warns about it in opt mode. PiperOrigin-RevId: 285220804 -- 68b015491f0dbf1ab547994673281abd1f34cd4b by Gennadiy Rozental <rogeeff@google.com>: This CL introduces following changes to the class FlagImpl: * We eliminate the CommandLineFlagLocks struct. Instead callback guard and callback function are combined into a single CallbackData struct, while primary data lock is stored separately. * CallbackData member of class FlagImpl is initially set to be nullptr and is only allocated and initialized when a flag's callback is being set. For most flags we do not pay for the extra space and extra absl::Mutex now. * Primary data guard is stored in data_guard_ data member. This is a properly aligned character buffer of necessary size. During initialization of the flag we construct absl::Mutex in this space using placement new call. * We now avoid extra value copy after successful attempt to parse value out of string. Instead we swap flag's current value with tentative value we just produced. PiperOrigin-RevId: 285132636 -- ed45d118fb818969eb13094cf7827c885dfc562c by Tom Manshreck <shreck@google.com>: Change null-term* (and nul-term*) to NUL-term* in comments PiperOrigin-RevId: 285036610 -- 729619017944db895ce8d6d29c1995aa2e5628a5 by Derek Mauro <dmauro@google.com>: Use the Posix implementation of thread identity on MinGW. Some versions of MinGW suffer from thread_local bugs. PiperOrigin-RevId: 285022920 -- 39a25493503c76885bc3254c28f66a251c5b5bb0 by Greg Falcon <gfalcon@google.com>: Implementation detail change. Add further ABSL_NAMESPACE_BEGIN and _END annotation macros to files in Abseil. PiperOrigin-RevId: 285012012 GitOrigin-RevId: c99f979ad34f155fbeeea69b88bdc7458d89a21c Change-Id: I4c85d3704e45d11a9ac50d562f39640a6adbedc1
		
			
				
	
	
		
			209 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
	
		
			6.8 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/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 {
 | |
| ABSL_NAMESPACE_BEGIN
 | |
| 
 | |
| 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:
 | |
| #ifdef 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) {
 | |
|     if (args.size() <= ABSL_ARRAYSIZE(few_args_)) {
 | |
|       for (size_t i = 0; i < args.size(); ++i) {
 | |
|         few_args_[i] = args[i];
 | |
|       }
 | |
|       args_ = absl::MakeSpan(few_args_, args.size());
 | |
|     } else {
 | |
|       many_args_.assign(args.begin(), args.end());
 | |
|       args_ = many_args_;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   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::Span<const FormatArgImpl> args_;
 | |
|   // if args_.size() is 4 or less:
 | |
|   FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0),
 | |
|                                 FormatArgImpl(0), FormatArgImpl(0)};
 | |
|   // if args_.size() is more than 4:
 | |
|   std::vector<FormatArgImpl> many_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);
 | |
| 
 | |
| std::string FormatPack(const UntypedFormatSpecImpl format,
 | |
|                        absl::Span<const FormatArgImpl> args);
 | |
| 
 | |
| 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
 | |
| ABSL_NAMESPACE_END
 | |
| }  // namespace absl
 | |
| 
 | |
| #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 |