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 ConversionSpec { 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, typename...> 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 <typename... 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 std::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 std::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<ArgumentToConv<Args>()...>(s), 109 "bad format trap"))) 110 : Base(s) {} 111 FormatSpecTemplate(string_view s)112 FormatSpecTemplate(string_view s) // NOLINT 113 __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s), 114 "bad format trap"))) 115 : Base(s) {} 116 117 #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 118 119 FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT 120 FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT 121 122 #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 123 124 template <Conv... C, typename = typename std::enable_if< 125 AllOf(sizeof...(C) == sizeof...(Args), 126 Contains(ArgumentToConv<Args>(), 127 C)...)>::type> FormatSpecTemplate(const ExtendedParsedFormat<C...> & pc)128 FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT 129 : Base(&pc) {} 130 }; 131 132 template <typename... Args> 133 struct FormatSpecDeductionBarrier { 134 using type = FormatSpecTemplate<Args...>; 135 }; 136 137 class Streamable { 138 public: Streamable(const UntypedFormatSpecImpl & format,absl::Span<const FormatArgImpl> args)139 Streamable(const UntypedFormatSpecImpl& format, 140 absl::Span<const FormatArgImpl> args) 141 : format_(format) { 142 if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { 143 for (size_t i = 0; i < args.size(); ++i) { 144 few_args_[i] = args[i]; 145 } 146 args_ = absl::MakeSpan(few_args_, args.size()); 147 } else { 148 many_args_.assign(args.begin(), args.end()); 149 args_ = many_args_; 150 } 151 } 152 153 std::ostream& Print(std::ostream& os) const; 154 155 friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { 156 return l.Print(os); 157 } 158 159 private: 160 const UntypedFormatSpecImpl& format_; 161 absl::Span<const FormatArgImpl> args_; 162 // if args_.size() is 4 or less: 163 FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0), 164 FormatArgImpl(0), FormatArgImpl(0)}; 165 // if args_.size() is more than 4: 166 std::vector<FormatArgImpl> many_args_; 167 }; 168 169 // for testing 170 std::string Summarize(UntypedFormatSpecImpl format, 171 absl::Span<const FormatArgImpl> args); 172 bool BindWithPack(const UnboundConversion* props, 173 absl::Span<const FormatArgImpl> pack, BoundConversion* bound); 174 175 bool FormatUntyped(FormatRawSinkImpl raw_sink, 176 UntypedFormatSpecImpl format, 177 absl::Span<const FormatArgImpl> args); 178 179 std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, 180 absl::Span<const FormatArgImpl> args); 181 182 std::string FormatPack(const UntypedFormatSpecImpl format, 183 absl::Span<const FormatArgImpl> args); 184 185 int FprintF(std::FILE* output, UntypedFormatSpecImpl format, 186 absl::Span<const FormatArgImpl> args); 187 int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, 188 absl::Span<const FormatArgImpl> args); 189 190 // Returned by Streamed(v). Converts via '%s' to the std::string created 191 // by std::ostream << v. 192 template <typename T> 193 class StreamedWrapper { 194 public: StreamedWrapper(const T & v)195 explicit StreamedWrapper(const T& v) : v_(v) { } 196 197 private: 198 template <typename S> 199 friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v, 200 ConversionSpec conv, 201 FormatSinkImpl* out); 202 const T& v_; 203 }; 204 205 } // namespace str_format_internal 206 ABSL_NAMESPACE_END 207 } // namespace absl 208 209 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 210