1 // Copyright 2020 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 16 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 17 18 #include <array> 19 #include <cstdio> 20 #include <sstream> 21 #include <string> 22 23 #include "absl/base/port.h" 24 #include "absl/strings/internal/str_format/arg.h" 25 #include "absl/strings/internal/str_format/checker.h" 26 #include "absl/strings/internal/str_format/parser.h" 27 #include "absl/types/span.h" 28 #include "absl/utility/utility.h" 29 30 namespace absl { 31 ABSL_NAMESPACE_BEGIN 32 33 class UntypedFormatSpec; 34 35 namespace str_format_internal { 36 37 class BoundConversion : public FormatConversionSpecImpl { 38 public: arg()39 const FormatArgImpl* arg() const { return arg_; } set_arg(const FormatArgImpl * a)40 void set_arg(const FormatArgImpl* a) { arg_ = a; } 41 42 private: 43 const FormatArgImpl* arg_; 44 }; 45 46 // This is the type-erased class that the implementation uses. 47 class UntypedFormatSpecImpl { 48 public: 49 UntypedFormatSpecImpl() = delete; 50 UntypedFormatSpecImpl(string_view s)51 explicit UntypedFormatSpecImpl(string_view s) 52 : data_(s.data()), size_(s.size()) {} UntypedFormatSpecImpl(const str_format_internal::ParsedFormatBase * pc)53 explicit UntypedFormatSpecImpl( 54 const str_format_internal::ParsedFormatBase* pc) 55 : data_(pc), size_(~size_t{}) {} 56 has_parsed_conversion()57 bool has_parsed_conversion() const { return size_ == ~size_t{}; } 58 str()59 string_view str() const { 60 assert(!has_parsed_conversion()); 61 return string_view(static_cast<const char*>(data_), size_); 62 } parsed_conversion()63 const str_format_internal::ParsedFormatBase* parsed_conversion() const { 64 assert(has_parsed_conversion()); 65 return static_cast<const str_format_internal::ParsedFormatBase*>(data_); 66 } 67 68 template <typename T> Extract(const T & s)69 static const UntypedFormatSpecImpl& Extract(const T& s) { 70 return s.spec_; 71 } 72 73 private: 74 const void* data_; 75 size_t size_; 76 }; 77 78 template <typename T, FormatConversionCharSet...> 79 struct MakeDependent { 80 using type = T; 81 }; 82 83 // Implicitly convertible from `const char*`, `string_view`, and the 84 // `ExtendedParsedFormat` type. This abstraction allows all format functions to 85 // operate on any without providing too many overloads. 86 template <FormatConversionCharSet... Args> 87 class FormatSpecTemplate 88 : public MakeDependent<UntypedFormatSpec, Args...>::type { 89 using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; 90 91 template <bool res> 92 struct ErrorMaker { operatorErrorMaker93 constexpr bool operator()(int) const { return res; } 94 }; 95 96 template <int i, int j> 97 static constexpr bool CheckArity(ErrorMaker<true> SpecifierCount = {}, 98 ErrorMaker<i == j> ParametersPassed = {}) { 99 static_assert(SpecifierCount(i) == ParametersPassed(j), 100 "Number of arguments passed must match the number of " 101 "conversion specifiers."); 102 return true; 103 } 104 105 template <FormatConversionCharSet specified, FormatConversionCharSet passed, 106 int arg> 107 static constexpr bool CheckMatch( 108 ErrorMaker<Contains(specified, passed)> MismatchedArgumentNumber = {}) { 109 static_assert(MismatchedArgumentNumber(arg), 110 "Passed argument must match specified format."); 111 return true; 112 } 113 114 template <FormatConversionCharSet... C, size_t... I> CheckMatches(absl::index_sequence<I...>)115 static bool CheckMatches(absl::index_sequence<I...>) { 116 bool res[] = {true, CheckMatch<Args, C, I + 1>()...}; 117 (void)res; 118 return true; 119 } 120 121 public: 122 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 123 124 // Honeypot overload for when the string is not constexpr. 125 // We use the 'unavailable' attribute to give a better compiler error than 126 // just 'method is deleted'. 127 FormatSpecTemplate(...) // NOLINT 128 __attribute__((unavailable("Format string is not constexpr."))); 129 130 // Honeypot overload for when the format is constexpr and invalid. 131 // We use the 'unavailable' attribute to give a better compiler error than 132 // just 'method is deleted'. 133 // To avoid checking the format twice, we just check that the format is 134 // constexpr. If it is valid, then the overload below will kick in. 135 // We add the template here to make this overload have lower priority. 136 template <typename = void> 137 FormatSpecTemplate(const char* s) // NOLINT 138 __attribute__(( 139 enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), 140 unavailable( 141 "Format specified does not match the arguments passed."))); 142 143 template <typename T = void> FormatSpecTemplate(string_view s)144 FormatSpecTemplate(string_view s) // NOLINT 145 __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), 146 "constexpr trap"))) 147 : Base("to avoid noise in the compiler error") { 148 static_assert(sizeof(T*) == 0, 149 "Format specified does not match the arguments passed."); 150 } 151 152 // Good format overload. FormatSpecTemplate(const char * s)153 FormatSpecTemplate(const char* s) // NOLINT 154 __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) 155 : Base(s) {} 156 FormatSpecTemplate(string_view s)157 FormatSpecTemplate(string_view s) // NOLINT 158 __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) 159 : Base(s) {} 160 161 #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 162 163 FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT 164 FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT 165 166 #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 167 168 template <FormatConversionCharSet... C> FormatSpecTemplate(const ExtendedParsedFormat<C...> & pc)169 FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT 170 : Base(&pc) { 171 CheckArity<sizeof...(C), sizeof...(Args)>(); 172 CheckMatches<C...>(absl::make_index_sequence<sizeof...(C)>{}); 173 } 174 }; 175 176 class Streamable { 177 public: Streamable(const UntypedFormatSpecImpl & format,absl::Span<const FormatArgImpl> args)178 Streamable(const UntypedFormatSpecImpl& format, 179 absl::Span<const FormatArgImpl> args) 180 : format_(format) { 181 if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { 182 for (size_t i = 0; i < args.size(); ++i) { 183 few_args_[i] = args[i]; 184 } 185 args_ = absl::MakeSpan(few_args_, args.size()); 186 } else { 187 many_args_.assign(args.begin(), args.end()); 188 args_ = many_args_; 189 } 190 } 191 192 std::ostream& Print(std::ostream& os) const; 193 194 friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { 195 return l.Print(os); 196 } 197 198 private: 199 const UntypedFormatSpecImpl& format_; 200 absl::Span<const FormatArgImpl> args_; 201 // if args_.size() is 4 or less: 202 FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0), 203 FormatArgImpl(0), FormatArgImpl(0)}; 204 // if args_.size() is more than 4: 205 std::vector<FormatArgImpl> many_args_; 206 }; 207 208 // for testing 209 std::string Summarize(UntypedFormatSpecImpl format, 210 absl::Span<const FormatArgImpl> args); 211 bool BindWithPack(const UnboundConversion* props, 212 absl::Span<const FormatArgImpl> pack, BoundConversion* bound); 213 214 bool FormatUntyped(FormatRawSinkImpl raw_sink, 215 UntypedFormatSpecImpl format, 216 absl::Span<const FormatArgImpl> args); 217 218 std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, 219 absl::Span<const FormatArgImpl> args); 220 221 std::string FormatPack(const UntypedFormatSpecImpl format, 222 absl::Span<const FormatArgImpl> args); 223 224 int FprintF(std::FILE* output, UntypedFormatSpecImpl format, 225 absl::Span<const FormatArgImpl> args); 226 int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, 227 absl::Span<const FormatArgImpl> args); 228 229 // Returned by Streamed(v). Converts via '%s' to the std::string created 230 // by std::ostream << v. 231 template <typename T> 232 class StreamedWrapper { 233 public: StreamedWrapper(const T & v)234 explicit StreamedWrapper(const T& v) : v_(v) { } 235 236 private: 237 template <typename S> 238 friend ArgConvertResult<FormatConversionCharSetUnion( 239 FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::v)> 240 FormatConvertImpl(const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, 241 FormatSinkImpl* out); 242 const T& v_; 243 }; 244 245 } // namespace str_format_internal 246 ABSL_NAMESPACE_END 247 } // namespace absl 248 249 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 250