1 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 2 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 3 4 #include <array> 5 #include <cstdio> 6 #include <sstream> 7 #include <string> 8 9 #include "absl/base/port.h" 10 #include "absl/strings/internal/str_format/arg.h" 11 #include "absl/strings/internal/str_format/checker.h" 12 #include "absl/strings/internal/str_format/parser.h" 13 #include "absl/types/span.h" 14 15 namespace absl { 16 ABSL_NAMESPACE_BEGIN 17 18 class UntypedFormatSpec; 19 20 namespace str_format_internal { 21 22 class BoundConversion : public FormatConversionSpecImpl { 23 public: arg()24 const FormatArgImpl* arg() const { return arg_; } set_arg(const FormatArgImpl * a)25 void set_arg(const FormatArgImpl* a) { arg_ = a; } 26 27 private: 28 const FormatArgImpl* arg_; 29 }; 30 31 // This is the type-erased class that the implementation uses. 32 class UntypedFormatSpecImpl { 33 public: 34 UntypedFormatSpecImpl() = delete; 35 UntypedFormatSpecImpl(string_view s)36 explicit UntypedFormatSpecImpl(string_view s) 37 : data_(s.data()), size_(s.size()) {} UntypedFormatSpecImpl(const str_format_internal::ParsedFormatBase * pc)38 explicit UntypedFormatSpecImpl( 39 const str_format_internal::ParsedFormatBase* pc) 40 : data_(pc), size_(~size_t{}) {} 41 has_parsed_conversion()42 bool has_parsed_conversion() const { return size_ == ~size_t{}; } 43 str()44 string_view str() const { 45 assert(!has_parsed_conversion()); 46 return string_view(static_cast<const char*>(data_), size_); 47 } parsed_conversion()48 const str_format_internal::ParsedFormatBase* parsed_conversion() const { 49 assert(has_parsed_conversion()); 50 return static_cast<const str_format_internal::ParsedFormatBase*>(data_); 51 } 52 53 template <typename T> Extract(const T & s)54 static const UntypedFormatSpecImpl& Extract(const T& s) { 55 return s.spec_; 56 } 57 58 private: 59 const void* data_; 60 size_t size_; 61 }; 62 63 template <typename T, FormatConversionCharSet...> 64 struct MakeDependent { 65 using type = T; 66 }; 67 68 // Implicitly convertible from `const char*`, `string_view`, and the 69 // `ExtendedParsedFormat` type. This abstraction allows all format functions to 70 // operate on any without providing too many overloads. 71 template <FormatConversionCharSet... Args> 72 class FormatSpecTemplate 73 : public MakeDependent<UntypedFormatSpec, Args...>::type { 74 using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; 75 76 public: 77 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 78 79 // Honeypot overload for when the string is not constexpr. 80 // We use the 'unavailable' attribute to give a better compiler error than 81 // just 'method is deleted'. 82 FormatSpecTemplate(...) // NOLINT 83 __attribute__((unavailable("Format string is not constexpr."))); 84 85 // Honeypot overload for when the format is constexpr and invalid. 86 // We use the 'unavailable' attribute to give a better compiler error than 87 // just 'method is deleted'. 88 // To avoid checking the format twice, we just check that the format is 89 // constexpr. If is it valid, then the overload below will kick in. 90 // We add the template here to make this overload have lower priority. 91 template <typename = void> 92 FormatSpecTemplate(const char* s) // NOLINT 93 __attribute__(( 94 enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), 95 unavailable( 96 "Format specified does not match the arguments passed."))); 97 98 template <typename T = void> FormatSpecTemplate(string_view s)99 FormatSpecTemplate(string_view s) // NOLINT 100 __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), 101 "constexpr trap"))) { 102 static_assert(sizeof(T*) == 0, 103 "Format specified does not match the arguments passed."); 104 } 105 106 // Good format overload. FormatSpecTemplate(const char * s)107 FormatSpecTemplate(const char* s) // NOLINT 108 __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) 109 : Base(s) {} 110 FormatSpecTemplate(string_view s)111 FormatSpecTemplate(string_view s) // NOLINT 112 __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) 113 : Base(s) {} 114 115 #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 116 117 FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT 118 FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT 119 120 #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 121 122 template <FormatConversionCharSet... C, 123 typename = typename std::enable_if< 124 AllOf(sizeof...(C) == sizeof...(Args), Contains(Args, 125 C)...)>::type> FormatSpecTemplate(const ExtendedParsedFormat<C...> & pc)126 FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT 127 : Base(&pc) {} 128 }; 129 130 class Streamable { 131 public: Streamable(const UntypedFormatSpecImpl & format,absl::Span<const FormatArgImpl> args)132 Streamable(const UntypedFormatSpecImpl& format, 133 absl::Span<const FormatArgImpl> args) 134 : format_(format) { 135 if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { 136 for (size_t i = 0; i < args.size(); ++i) { 137 few_args_[i] = args[i]; 138 } 139 args_ = absl::MakeSpan(few_args_, args.size()); 140 } else { 141 many_args_.assign(args.begin(), args.end()); 142 args_ = many_args_; 143 } 144 } 145 146 std::ostream& Print(std::ostream& os) const; 147 148 friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { 149 return l.Print(os); 150 } 151 152 private: 153 const UntypedFormatSpecImpl& format_; 154 absl::Span<const FormatArgImpl> args_; 155 // if args_.size() is 4 or less: 156 FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0), 157 FormatArgImpl(0), FormatArgImpl(0)}; 158 // if args_.size() is more than 4: 159 std::vector<FormatArgImpl> many_args_; 160 }; 161 162 // for testing 163 std::string Summarize(UntypedFormatSpecImpl format, 164 absl::Span<const FormatArgImpl> args); 165 bool BindWithPack(const UnboundConversion* props, 166 absl::Span<const FormatArgImpl> pack, BoundConversion* bound); 167 168 bool FormatUntyped(FormatRawSinkImpl raw_sink, 169 UntypedFormatSpecImpl format, 170 absl::Span<const FormatArgImpl> args); 171 172 std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, 173 absl::Span<const FormatArgImpl> args); 174 175 std::string FormatPack(const UntypedFormatSpecImpl format, 176 absl::Span<const FormatArgImpl> args); 177 178 int FprintF(std::FILE* output, UntypedFormatSpecImpl format, 179 absl::Span<const FormatArgImpl> args); 180 int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, 181 absl::Span<const FormatArgImpl> args); 182 183 // Returned by Streamed(v). Converts via '%s' to the std::string created 184 // by std::ostream << v. 185 template <typename T> 186 class StreamedWrapper { 187 public: StreamedWrapper(const T & v)188 explicit StreamedWrapper(const T& v) : v_(v) { } 189 190 private: 191 template <typename S> 192 friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl( 193 const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, 194 FormatSinkImpl* out); 195 const T& v_; 196 }; 197 198 } // namespace str_format_internal 199 ABSL_NAMESPACE_END 200 } // namespace absl 201 202 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 203