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/container/inlined_vector.h" 25 #include "absl/strings/internal/str_format/arg.h" 26 #include "absl/strings/internal/str_format/checker.h" 27 #include "absl/strings/internal/str_format/parser.h" 28 #include "absl/types/span.h" 29 #include "absl/utility/utility.h" 30 31 namespace absl { 32 ABSL_NAMESPACE_BEGIN 33 34 class UntypedFormatSpec; 35 36 namespace str_format_internal { 37 38 class BoundConversion : public FormatConversionSpecImpl { 39 public: arg()40 const FormatArgImpl* arg() const { return arg_; } set_arg(const FormatArgImpl * a)41 void set_arg(const FormatArgImpl* a) { arg_ = a; } 42 43 private: 44 const FormatArgImpl* arg_; 45 }; 46 47 // This is the type-erased class that the implementation uses. 48 class UntypedFormatSpecImpl { 49 public: 50 UntypedFormatSpecImpl() = delete; 51 UntypedFormatSpecImpl(string_view s)52 explicit UntypedFormatSpecImpl(string_view s) 53 : data_(s.data()), size_(s.size()) {} UntypedFormatSpecImpl(const str_format_internal::ParsedFormatBase * pc)54 explicit UntypedFormatSpecImpl( 55 const str_format_internal::ParsedFormatBase* pc) 56 : data_(pc), size_(~size_t{}) {} 57 has_parsed_conversion()58 bool has_parsed_conversion() const { return size_ == ~size_t{}; } 59 str()60 string_view str() const { 61 assert(!has_parsed_conversion()); 62 return string_view(static_cast<const char*>(data_), size_); 63 } parsed_conversion()64 const str_format_internal::ParsedFormatBase* parsed_conversion() const { 65 assert(has_parsed_conversion()); 66 return static_cast<const str_format_internal::ParsedFormatBase*>(data_); 67 } 68 69 template <typename T> Extract(const T & s)70 static const UntypedFormatSpecImpl& Extract(const T& s) { 71 return s.spec_; 72 } 73 74 private: 75 const void* data_; 76 size_t size_; 77 }; 78 79 template <typename T, FormatConversionCharSet...> 80 struct MakeDependent { 81 using type = T; 82 }; 83 84 // Implicitly convertible from `const char*`, `string_view`, and the 85 // `ExtendedParsedFormat` type. This abstraction allows all format functions to 86 // operate on any without providing too many overloads. 87 template <FormatConversionCharSet... Args> 88 class FormatSpecTemplate 89 : public MakeDependent<UntypedFormatSpec, Args...>::type { 90 using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; 91 92 template <bool res> 93 struct ErrorMaker { operatorErrorMaker94 constexpr bool operator()(int) const { return res; } 95 }; 96 97 template <int i, int j> 98 static constexpr bool CheckArity(ErrorMaker<true> SpecifierCount = {}, 99 ErrorMaker<i == j> ParametersPassed = {}) { 100 static_assert(SpecifierCount(i) == ParametersPassed(j), 101 "Number of arguments passed must match the number of " 102 "conversion specifiers."); 103 return true; 104 } 105 106 template <FormatConversionCharSet specified, FormatConversionCharSet passed, 107 int arg> 108 static constexpr bool CheckMatch( 109 ErrorMaker<Contains(specified, passed)> MismatchedArgumentNumber = {}) { 110 static_assert(MismatchedArgumentNumber(arg), 111 "Passed argument must match specified format."); 112 return true; 113 } 114 115 template <FormatConversionCharSet... C, size_t... I> CheckMatches(absl::index_sequence<I...>)116 static bool CheckMatches(absl::index_sequence<I...>) { 117 bool res[] = {true, CheckMatch<Args, C, I + 1>()...}; 118 (void)res; 119 return true; 120 } 121 122 public: 123 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 124 125 // Honeypot overload for when the string is not constexpr. 126 // We use the 'unavailable' attribute to give a better compiler error than 127 // just 'method is deleted'. 128 FormatSpecTemplate(...) // NOLINT 129 __attribute__((unavailable("Format string is not constexpr."))); 130 131 // Honeypot overload for when the format is constexpr and invalid. 132 // We use the 'unavailable' attribute to give a better compiler error than 133 // just 'method is deleted'. 134 // To avoid checking the format twice, we just check that the format is 135 // constexpr. If it is valid, then the overload below will kick in. 136 // We add the template here to make this overload have lower priority. 137 template <typename = void> 138 FormatSpecTemplate(const char* s) // NOLINT 139 __attribute__(( 140 enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), 141 unavailable( 142 "Format specified does not match the arguments passed."))); 143 144 template <typename T = void> FormatSpecTemplate(string_view s)145 FormatSpecTemplate(string_view s) // NOLINT 146 __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), 147 "constexpr trap"))) 148 : Base("to avoid noise in the compiler error") { 149 static_assert(sizeof(T*) == 0, 150 "Format specified does not match the arguments passed."); 151 } 152 153 // Good format overload. FormatSpecTemplate(const char * s)154 FormatSpecTemplate(const char* s) // NOLINT 155 __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) 156 : Base(s) {} 157 FormatSpecTemplate(string_view s)158 FormatSpecTemplate(string_view s) // NOLINT 159 __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) 160 : Base(s) {} 161 162 #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 163 164 FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT 165 FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT 166 167 #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 168 169 template <FormatConversionCharSet... C> FormatSpecTemplate(const ExtendedParsedFormat<C...> & pc)170 FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT 171 : Base(&pc) { 172 CheckArity<sizeof...(C), sizeof...(Args)>(); 173 CheckMatches<C...>(absl::make_index_sequence<sizeof...(C)>{}); 174 } 175 }; 176 177 class Streamable { 178 public: Streamable(const UntypedFormatSpecImpl & format,absl::Span<const FormatArgImpl> args)179 Streamable(const UntypedFormatSpecImpl& format, 180 absl::Span<const FormatArgImpl> args) 181 : format_(format), args_(args.begin(), args.end()) {} 182 183 std::ostream& Print(std::ostream& os) const; 184 185 friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { 186 return l.Print(os); 187 } 188 189 private: 190 const UntypedFormatSpecImpl& format_; 191 absl::InlinedVector<FormatArgImpl, 4> args_; 192 }; 193 194 // for testing 195 std::string Summarize(UntypedFormatSpecImpl format, 196 absl::Span<const FormatArgImpl> args); 197 bool BindWithPack(const UnboundConversion* props, 198 absl::Span<const FormatArgImpl> pack, BoundConversion* bound); 199 200 bool FormatUntyped(FormatRawSinkImpl raw_sink, UntypedFormatSpecImpl format, 201 absl::Span<const FormatArgImpl> args); 202 203 std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, 204 absl::Span<const FormatArgImpl> args); 205 206 std::string FormatPack(const UntypedFormatSpecImpl format, 207 absl::Span<const FormatArgImpl> args); 208 209 int FprintF(std::FILE* output, UntypedFormatSpecImpl format, 210 absl::Span<const FormatArgImpl> args); 211 int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, 212 absl::Span<const FormatArgImpl> args); 213 214 // Returned by Streamed(v). Converts via '%s' to the std::string created 215 // by std::ostream << v. 216 template <typename T> 217 class StreamedWrapper { 218 public: StreamedWrapper(const T & v)219 explicit StreamedWrapper(const T& v) : v_(v) {} 220 221 private: 222 template <typename S> 223 friend ArgConvertResult<FormatConversionCharSetUnion( 224 FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::v)> 225 FormatConvertImpl(const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, 226 FormatSinkImpl* out); 227 const T& v_; 228 }; 229 230 } // namespace str_format_internal 231 ABSL_NAMESPACE_END 232 } // namespace absl 233 234 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ 235