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