xref: /aosp_15_r20/external/webrtc/third_party/abseil-cpp/absl/strings/substitute.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 //
2 // Copyright 2017 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 // -----------------------------------------------------------------------------
17 // File: substitute.h
18 // -----------------------------------------------------------------------------
19 //
20 // This package contains functions for efficiently performing string
21 // substitutions using a format string with positional notation:
22 // `Substitute()` and `SubstituteAndAppend()`.
23 //
24 // Unlike printf-style format specifiers, `Substitute()` functions do not need
25 // to specify the type of the substitution arguments. Supported arguments
26 // following the format string, such as strings, string_views, ints,
27 // floats, and bools, are automatically converted to strings during the
28 // substitution process. (See below for a full list of supported types.)
29 //
30 // `Substitute()` does not allow you to specify *how* to format a value, beyond
31 // the default conversion to string. For example, you cannot format an integer
32 // in hex.
33 //
34 // The format string uses positional identifiers indicated by a dollar sign ($)
35 // and single digit positional ids to indicate which substitution arguments to
36 // use at that location within the format string.
37 //
38 // A '$$' sequence in the format string causes a literal '$' character to be
39 // output.
40 //
41 // Example 1:
42 //   std::string s = Substitute("$1 purchased $0 $2 for $$10. Thanks $1!",
43 //                              5, "Bob", "Apples");
44 //   EXPECT_EQ("Bob purchased 5 Apples for $10. Thanks Bob!", s);
45 //
46 // Example 2:
47 //   std::string s = "Hi. ";
48 //   SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
49 //   EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s);
50 //
51 // Supported types:
52 //   * absl::string_view, std::string, const char* (null is equivalent to "")
53 //   * int32_t, int64_t, uint32_t, uint64_t
54 //   * float, double
55 //   * bool (Printed as "true" or "false")
56 //   * pointer types other than char* (Printed as "0x<lower case hex string>",
57 //     except that null is printed as "NULL")
58 //   * user-defined types via the `AbslStringify()` customization point. See the
59 //     documentation for `absl::StrCat` for an explanation on how to use this.
60 //
61 // If an invalid format string is provided, Substitute returns an empty string
62 // and SubstituteAndAppend does not change the provided output string.
63 // A format string is invalid if it:
64 //   * ends in an unescaped $ character,
65 //     e.g. "Hello $", or
66 //   * calls for a position argument which is not provided,
67 //     e.g. Substitute("Hello $2", "world"), or
68 //   * specifies a non-digit, non-$ character after an unescaped $ character,
69 //     e.g. "Hello $f".
70 // In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program.
71 
72 #ifndef ABSL_STRINGS_SUBSTITUTE_H_
73 #define ABSL_STRINGS_SUBSTITUTE_H_
74 
75 #include <cstring>
76 #include <string>
77 #include <type_traits>
78 #include <vector>
79 
80 #include "absl/base/macros.h"
81 #include "absl/base/port.h"
82 #include "absl/strings/ascii.h"
83 #include "absl/strings/escaping.h"
84 #include "absl/strings/internal/stringify_sink.h"
85 #include "absl/strings/numbers.h"
86 #include "absl/strings/str_cat.h"
87 #include "absl/strings/str_split.h"
88 #include "absl/strings/string_view.h"
89 #include "absl/strings/strip.h"
90 
91 namespace absl {
92 ABSL_NAMESPACE_BEGIN
93 namespace substitute_internal {
94 
95 // Arg
96 //
97 // This class provides an argument type for `absl::Substitute()` and
98 // `absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various
99 // types to a string. (`Arg` is very similar to the `AlphaNum` class in
100 // `StrCat()`.)
101 //
102 // This class has implicit constructors.
103 class Arg {
104  public:
105   // Overloads for string-y things
106   //
107   // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
Arg(const char * value)108   Arg(const char* value)  // NOLINT(google-explicit-constructor)
109       : piece_(absl::NullSafeStringView(value)) {}
110   template <typename Allocator>
Arg(const std::basic_string<char,std::char_traits<char>,Allocator> & value)111   Arg(  // NOLINT
112       const std::basic_string<char, std::char_traits<char>, Allocator>&
113           value) noexcept
114       : piece_(value) {}
Arg(absl::string_view value)115   Arg(absl::string_view value)  // NOLINT(google-explicit-constructor)
116       : piece_(value) {}
117 
118   // Overloads for primitives
119   //
120   // No overloads are available for signed and unsigned char because if people
121   // are explicitly declaring their chars as signed or unsigned then they are
122   // probably using them as 8-bit integers and would probably prefer an integer
123   // representation. However, we can't really know, so we make the caller decide
124   // what to do.
Arg(char value)125   Arg(char value)  // NOLINT(google-explicit-constructor)
126       : piece_(scratch_, 1) {
127     scratch_[0] = value;
128   }
Arg(short value)129   Arg(short value)  // NOLINT(*)
130       : piece_(scratch_,
131                static_cast<size_t>(
132                    numbers_internal::FastIntToBuffer(value, scratch_) -
133                    scratch_)) {}
Arg(unsigned short value)134   Arg(unsigned short value)  // NOLINT(*)
135       : piece_(scratch_,
136                static_cast<size_t>(
137                    numbers_internal::FastIntToBuffer(value, scratch_) -
138                    scratch_)) {}
Arg(int value)139   Arg(int value)  // NOLINT(google-explicit-constructor)
140       : piece_(scratch_,
141                static_cast<size_t>(
142                    numbers_internal::FastIntToBuffer(value, scratch_) -
143                    scratch_)) {}
Arg(unsigned int value)144   Arg(unsigned int value)  // NOLINT(google-explicit-constructor)
145       : piece_(scratch_,
146                static_cast<size_t>(
147                    numbers_internal::FastIntToBuffer(value, scratch_) -
148                    scratch_)) {}
Arg(long value)149   Arg(long value)  // NOLINT(*)
150       : piece_(scratch_,
151                static_cast<size_t>(
152                    numbers_internal::FastIntToBuffer(value, scratch_) -
153                    scratch_)) {}
Arg(unsigned long value)154   Arg(unsigned long value)  // NOLINT(*)
155       : piece_(scratch_,
156                static_cast<size_t>(
157                    numbers_internal::FastIntToBuffer(value, scratch_) -
158                    scratch_)) {}
Arg(long long value)159   Arg(long long value)  // NOLINT(*)
160       : piece_(scratch_,
161                static_cast<size_t>(
162                    numbers_internal::FastIntToBuffer(value, scratch_) -
163                    scratch_)) {}
Arg(unsigned long long value)164   Arg(unsigned long long value)  // NOLINT(*)
165       : piece_(scratch_,
166                static_cast<size_t>(
167                    numbers_internal::FastIntToBuffer(value, scratch_) -
168                    scratch_)) {}
Arg(float value)169   Arg(float value)  // NOLINT(google-explicit-constructor)
170       : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
171   }
Arg(double value)172   Arg(double value)  // NOLINT(google-explicit-constructor)
173       : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
174   }
Arg(bool value)175   Arg(bool value)  // NOLINT(google-explicit-constructor)
176       : piece_(value ? "true" : "false") {}
177 
178   template <typename T, typename = typename std::enable_if<
179                             strings_internal::HasAbslStringify<T>::value>::type>
180   Arg(  // NOLINT(google-explicit-constructor)
181       const T& v, strings_internal::StringifySink&& sink = {})
piece_(strings_internal::ExtractStringification (sink,v))182       : piece_(strings_internal::ExtractStringification(sink, v)) {}
183 
184   Arg(Hex hex);  // NOLINT(google-explicit-constructor)
185   Arg(Dec dec);  // NOLINT(google-explicit-constructor)
186 
187   // vector<bool>::reference and const_reference require special help to convert
188   // to `Arg` because it requires two user defined conversions.
189   template <typename T,
190             absl::enable_if_t<
191                 std::is_class<T>::value &&
192                 (std::is_same<T, std::vector<bool>::reference>::value ||
193                  std::is_same<T, std::vector<bool>::const_reference>::value)>* =
194                 nullptr>
Arg(T value)195   Arg(T value)  // NOLINT(google-explicit-constructor)
196       : Arg(static_cast<bool>(value)) {}
197 
198   // `void*` values, with the exception of `char*`, are printed as
199   // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
200   Arg(const void* value);  // NOLINT(google-explicit-constructor)
201 
202   // Normal enums are already handled by the integer formatters.
203   // This overload matches only scoped enums.
204   template <typename T,
205             typename = typename std::enable_if<
206                 std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
Arg(T value)207   Arg(T value)  // NOLINT(google-explicit-constructor)
208       : Arg(static_cast<typename std::underlying_type<T>::type>(value)) {}
209 
210   Arg(const Arg&) = delete;
211   Arg& operator=(const Arg&) = delete;
212 
piece()213   absl::string_view piece() const { return piece_; }
214 
215  private:
216   absl::string_view piece_;
217   char scratch_[numbers_internal::kFastToBufferSize];
218 };
219 
220 // Internal helper function. Don't call this from outside this implementation.
221 // This interface may change without notice.
222 void SubstituteAndAppendArray(std::string* output, absl::string_view format,
223                               const absl::string_view* args_array,
224                               size_t num_args);
225 
226 #if defined(ABSL_BAD_CALL_IF)
CalculateOneBit(const char * format)227 constexpr int CalculateOneBit(const char* format) {
228   // Returns:
229   // * 2^N for '$N' when N is in [0-9]
230   // * 0 for correct '$' escaping: '$$'.
231   // * -1 otherwise.
232   return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1)
233                                           : (1 << (*format - '0'));
234 }
235 
SkipNumber(const char * format)236 constexpr const char* SkipNumber(const char* format) {
237   return !*format ? format : (format + 1);
238 }
239 
PlaceholderBitmask(const char * format)240 constexpr int PlaceholderBitmask(const char* format) {
241   return !*format
242              ? 0
243              : *format != '$' ? PlaceholderBitmask(format + 1)
244                               : (CalculateOneBit(format + 1) |
245                                  PlaceholderBitmask(SkipNumber(format + 1)));
246 }
247 #endif  // ABSL_BAD_CALL_IF
248 
249 }  // namespace substitute_internal
250 
251 //
252 // PUBLIC API
253 //
254 
255 // SubstituteAndAppend()
256 //
257 // Substitutes variables into a given format string and appends to a given
258 // output string. See file comments above for usage.
259 //
260 // The declarations of `SubstituteAndAppend()` below consist of overloads
261 // for passing 0 to 10 arguments, respectively.
262 //
263 // NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic
264 // templates to allow a variable number of arguments.
265 //
266 // Example:
267 //  template <typename... Args>
268 //  void VarMsg(std::string* boilerplate, absl::string_view format,
269 //      const Args&... args) {
270 //    absl::SubstituteAndAppend(boilerplate, format, args...);
271 //  }
272 //
SubstituteAndAppend(std::string * output,absl::string_view format)273 inline void SubstituteAndAppend(std::string* output, absl::string_view format) {
274   substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
275 }
276 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0)277 inline void SubstituteAndAppend(std::string* output, absl::string_view format,
278                                 const substitute_internal::Arg& a0) {
279   const absl::string_view args[] = {a0.piece()};
280   substitute_internal::SubstituteAndAppendArray(output, format, args,
281                                                 ABSL_ARRAYSIZE(args));
282 }
283 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1)284 inline void SubstituteAndAppend(std::string* output, absl::string_view format,
285                                 const substitute_internal::Arg& a0,
286                                 const substitute_internal::Arg& a1) {
287   const absl::string_view args[] = {a0.piece(), a1.piece()};
288   substitute_internal::SubstituteAndAppendArray(output, format, args,
289                                                 ABSL_ARRAYSIZE(args));
290 }
291 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2)292 inline void SubstituteAndAppend(std::string* output, absl::string_view format,
293                                 const substitute_internal::Arg& a0,
294                                 const substitute_internal::Arg& a1,
295                                 const substitute_internal::Arg& a2) {
296   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()};
297   substitute_internal::SubstituteAndAppendArray(output, format, args,
298                                                 ABSL_ARRAYSIZE(args));
299 }
300 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3)301 inline void SubstituteAndAppend(std::string* output, absl::string_view format,
302                                 const substitute_internal::Arg& a0,
303                                 const substitute_internal::Arg& a1,
304                                 const substitute_internal::Arg& a2,
305                                 const substitute_internal::Arg& a3) {
306   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
307                                     a3.piece()};
308   substitute_internal::SubstituteAndAppendArray(output, format, args,
309                                                 ABSL_ARRAYSIZE(args));
310 }
311 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4)312 inline void SubstituteAndAppend(std::string* output, absl::string_view format,
313                                 const substitute_internal::Arg& a0,
314                                 const substitute_internal::Arg& a1,
315                                 const substitute_internal::Arg& a2,
316                                 const substitute_internal::Arg& a3,
317                                 const substitute_internal::Arg& a4) {
318   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
319                                     a3.piece(), a4.piece()};
320   substitute_internal::SubstituteAndAppendArray(output, format, args,
321                                                 ABSL_ARRAYSIZE(args));
322 }
323 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5)324 inline void SubstituteAndAppend(std::string* output, absl::string_view format,
325                                 const substitute_internal::Arg& a0,
326                                 const substitute_internal::Arg& a1,
327                                 const substitute_internal::Arg& a2,
328                                 const substitute_internal::Arg& a3,
329                                 const substitute_internal::Arg& a4,
330                                 const substitute_internal::Arg& a5) {
331   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
332                                     a3.piece(), a4.piece(), a5.piece()};
333   substitute_internal::SubstituteAndAppendArray(output, format, args,
334                                                 ABSL_ARRAYSIZE(args));
335 }
336 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6)337 inline void SubstituteAndAppend(std::string* output, absl::string_view format,
338                                 const substitute_internal::Arg& a0,
339                                 const substitute_internal::Arg& a1,
340                                 const substitute_internal::Arg& a2,
341                                 const substitute_internal::Arg& a3,
342                                 const substitute_internal::Arg& a4,
343                                 const substitute_internal::Arg& a5,
344                                 const substitute_internal::Arg& a6) {
345   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
346                                     a3.piece(), a4.piece(), a5.piece(),
347                                     a6.piece()};
348   substitute_internal::SubstituteAndAppendArray(output, format, args,
349                                                 ABSL_ARRAYSIZE(args));
350 }
351 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6,const substitute_internal::Arg & a7)352 inline void SubstituteAndAppend(
353     std::string* output, absl::string_view format,
354     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
355     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
356     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
357     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) {
358   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
359                                     a3.piece(), a4.piece(), a5.piece(),
360                                     a6.piece(), a7.piece()};
361   substitute_internal::SubstituteAndAppendArray(output, format, args,
362                                                 ABSL_ARRAYSIZE(args));
363 }
364 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6,const substitute_internal::Arg & a7,const substitute_internal::Arg & a8)365 inline void SubstituteAndAppend(
366     std::string* output, absl::string_view format,
367     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
368     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
369     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
370     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
371     const substitute_internal::Arg& a8) {
372   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
373                                     a3.piece(), a4.piece(), a5.piece(),
374                                     a6.piece(), a7.piece(), a8.piece()};
375   substitute_internal::SubstituteAndAppendArray(output, format, args,
376                                                 ABSL_ARRAYSIZE(args));
377 }
378 
SubstituteAndAppend(std::string * output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6,const substitute_internal::Arg & a7,const substitute_internal::Arg & a8,const substitute_internal::Arg & a9)379 inline void SubstituteAndAppend(
380     std::string* output, absl::string_view format,
381     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
382     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
383     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
384     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
385     const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) {
386   const absl::string_view args[] = {
387       a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(),
388       a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()};
389   substitute_internal::SubstituteAndAppendArray(output, format, args,
390                                                 ABSL_ARRAYSIZE(args));
391 }
392 
393 #if defined(ABSL_BAD_CALL_IF)
394 // This body of functions catches cases where the number of placeholders
395 // doesn't match the number of data arguments.
396 void SubstituteAndAppend(std::string* output, const char* format)
397     ABSL_BAD_CALL_IF(
398         substitute_internal::PlaceholderBitmask(format) != 0,
399         "There were no substitution arguments "
400         "but this format string either has a $[0-9] in it or contains "
401         "an unescaped $ character (use $$ instead)");
402 
403 void SubstituteAndAppend(std::string* output, const char* format,
404                          const substitute_internal::Arg& a0)
405     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
406                      "There was 1 substitution argument given, but "
407                      "this format string is missing its $0, contains "
408                      "one of $1-$9, or contains an unescaped $ character (use "
409                      "$$ instead)");
410 
411 void SubstituteAndAppend(std::string* output, const char* format,
412                          const substitute_internal::Arg& a0,
413                          const substitute_internal::Arg& a1)
414     ABSL_BAD_CALL_IF(
415         substitute_internal::PlaceholderBitmask(format) != 3,
416         "There were 2 substitution arguments given, but this format string is "
417         "missing its $0/$1, contains one of $2-$9, or contains an "
418         "unescaped $ character (use $$ instead)");
419 
420 void SubstituteAndAppend(std::string* output, const char* format,
421                          const substitute_internal::Arg& a0,
422                          const substitute_internal::Arg& a1,
423                          const substitute_internal::Arg& a2)
424     ABSL_BAD_CALL_IF(
425         substitute_internal::PlaceholderBitmask(format) != 7,
426         "There were 3 substitution arguments given, but "
427         "this format string is missing its $0/$1/$2, contains one of "
428         "$3-$9, or contains an unescaped $ character (use $$ instead)");
429 
430 void SubstituteAndAppend(std::string* output, const char* format,
431                          const substitute_internal::Arg& a0,
432                          const substitute_internal::Arg& a1,
433                          const substitute_internal::Arg& a2,
434                          const substitute_internal::Arg& a3)
435     ABSL_BAD_CALL_IF(
436         substitute_internal::PlaceholderBitmask(format) != 15,
437         "There were 4 substitution arguments given, but "
438         "this format string is missing its $0-$3, contains one of "
439         "$4-$9, or contains an unescaped $ character (use $$ instead)");
440 
441 void SubstituteAndAppend(std::string* output, const char* format,
442                          const substitute_internal::Arg& a0,
443                          const substitute_internal::Arg& a1,
444                          const substitute_internal::Arg& a2,
445                          const substitute_internal::Arg& a3,
446                          const substitute_internal::Arg& a4)
447     ABSL_BAD_CALL_IF(
448         substitute_internal::PlaceholderBitmask(format) != 31,
449         "There were 5 substitution arguments given, but "
450         "this format string is missing its $0-$4, contains one of "
451         "$5-$9, or contains an unescaped $ character (use $$ instead)");
452 
453 void SubstituteAndAppend(std::string* output, const char* format,
454                          const substitute_internal::Arg& a0,
455                          const substitute_internal::Arg& a1,
456                          const substitute_internal::Arg& a2,
457                          const substitute_internal::Arg& a3,
458                          const substitute_internal::Arg& a4,
459                          const substitute_internal::Arg& a5)
460     ABSL_BAD_CALL_IF(
461         substitute_internal::PlaceholderBitmask(format) != 63,
462         "There were 6 substitution arguments given, but "
463         "this format string is missing its $0-$5, contains one of "
464         "$6-$9, or contains an unescaped $ character (use $$ instead)");
465 
466 void SubstituteAndAppend(
467     std::string* output, const char* format, const substitute_internal::Arg& a0,
468     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
469     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
470     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
471     ABSL_BAD_CALL_IF(
472         substitute_internal::PlaceholderBitmask(format) != 127,
473         "There were 7 substitution arguments given, but "
474         "this format string is missing its $0-$6, contains one of "
475         "$7-$9, or contains an unescaped $ character (use $$ instead)");
476 
477 void SubstituteAndAppend(
478     std::string* output, const char* format, const substitute_internal::Arg& a0,
479     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
480     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
481     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
482     const substitute_internal::Arg& a7)
483     ABSL_BAD_CALL_IF(
484         substitute_internal::PlaceholderBitmask(format) != 255,
485         "There were 8 substitution arguments given, but "
486         "this format string is missing its $0-$7, contains one of "
487         "$8-$9, or contains an unescaped $ character (use $$ instead)");
488 
489 void SubstituteAndAppend(
490     std::string* output, const char* format, const substitute_internal::Arg& a0,
491     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
492     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
493     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
494     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
495     ABSL_BAD_CALL_IF(
496         substitute_internal::PlaceholderBitmask(format) != 511,
497         "There were 9 substitution arguments given, but "
498         "this format string is missing its $0-$8, contains a $9, or "
499         "contains an unescaped $ character (use $$ instead)");
500 
501 void SubstituteAndAppend(
502     std::string* output, const char* format, const substitute_internal::Arg& a0,
503     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
504     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
505     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
506     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
507     const substitute_internal::Arg& a9)
508     ABSL_BAD_CALL_IF(
509         substitute_internal::PlaceholderBitmask(format) != 1023,
510         "There were 10 substitution arguments given, but this "
511         "format string either doesn't contain all of $0 through $9 or "
512         "contains an unescaped $ character (use $$ instead)");
513 #endif  // ABSL_BAD_CALL_IF
514 
515 // Substitute()
516 //
517 // Substitutes variables into a given format string. See file comments above
518 // for usage.
519 //
520 // The declarations of `Substitute()` below consist of overloads for passing 0
521 // to 10 arguments, respectively.
522 //
523 // NOTE: A zero-argument `Substitute()` may be used within variadic templates to
524 // allow a variable number of arguments.
525 //
526 // Example:
527 //  template <typename... Args>
528 //  void VarMsg(absl::string_view format, const Args&... args) {
529 //    std::string s = absl::Substitute(format, args...);
530 
Substitute(absl::string_view format)531 ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
532   std::string result;
533   SubstituteAndAppend(&result, format);
534   return result;
535 }
536 
Substitute(absl::string_view format,const substitute_internal::Arg & a0)537 ABSL_MUST_USE_RESULT inline std::string Substitute(
538     absl::string_view format, const substitute_internal::Arg& a0) {
539   std::string result;
540   SubstituteAndAppend(&result, format, a0);
541   return result;
542 }
543 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1)544 ABSL_MUST_USE_RESULT inline std::string Substitute(
545     absl::string_view format, const substitute_internal::Arg& a0,
546     const substitute_internal::Arg& a1) {
547   std::string result;
548   SubstituteAndAppend(&result, format, a0, a1);
549   return result;
550 }
551 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2)552 ABSL_MUST_USE_RESULT inline std::string Substitute(
553     absl::string_view format, const substitute_internal::Arg& a0,
554     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) {
555   std::string result;
556   SubstituteAndAppend(&result, format, a0, a1, a2);
557   return result;
558 }
559 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3)560 ABSL_MUST_USE_RESULT inline std::string Substitute(
561     absl::string_view format, const substitute_internal::Arg& a0,
562     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
563     const substitute_internal::Arg& a3) {
564   std::string result;
565   SubstituteAndAppend(&result, format, a0, a1, a2, a3);
566   return result;
567 }
568 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4)569 ABSL_MUST_USE_RESULT inline std::string Substitute(
570     absl::string_view format, const substitute_internal::Arg& a0,
571     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
572     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
573   std::string result;
574   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4);
575   return result;
576 }
577 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5)578 ABSL_MUST_USE_RESULT inline std::string Substitute(
579     absl::string_view format, const substitute_internal::Arg& a0,
580     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
581     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
582     const substitute_internal::Arg& a5) {
583   std::string result;
584   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5);
585   return result;
586 }
587 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6)588 ABSL_MUST_USE_RESULT inline std::string Substitute(
589     absl::string_view format, const substitute_internal::Arg& a0,
590     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
591     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
592     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) {
593   std::string result;
594   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6);
595   return result;
596 }
597 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6,const substitute_internal::Arg & a7)598 ABSL_MUST_USE_RESULT inline std::string Substitute(
599     absl::string_view format, const substitute_internal::Arg& a0,
600     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
601     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
602     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
603     const substitute_internal::Arg& a7) {
604   std::string result;
605   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7);
606   return result;
607 }
608 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6,const substitute_internal::Arg & a7,const substitute_internal::Arg & a8)609 ABSL_MUST_USE_RESULT inline std::string Substitute(
610     absl::string_view format, const substitute_internal::Arg& a0,
611     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
612     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
613     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
614     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) {
615   std::string result;
616   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8);
617   return result;
618 }
619 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2,const substitute_internal::Arg & a3,const substitute_internal::Arg & a4,const substitute_internal::Arg & a5,const substitute_internal::Arg & a6,const substitute_internal::Arg & a7,const substitute_internal::Arg & a8,const substitute_internal::Arg & a9)620 ABSL_MUST_USE_RESULT inline std::string Substitute(
621     absl::string_view format, const substitute_internal::Arg& a0,
622     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
623     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
624     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
625     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
626     const substitute_internal::Arg& a9) {
627   std::string result;
628   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
629   return result;
630 }
631 
632 #if defined(ABSL_BAD_CALL_IF)
633 // This body of functions catches cases where the number of placeholders
634 // doesn't match the number of data arguments.
635 std::string Substitute(const char* format)
636     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
637                      "There were no substitution arguments "
638                      "but this format string either has a $[0-9] in it or "
639                      "contains an unescaped $ character (use $$ instead)");
640 
641 std::string Substitute(const char* format, const substitute_internal::Arg& a0)
642     ABSL_BAD_CALL_IF(
643         substitute_internal::PlaceholderBitmask(format) != 1,
644         "There was 1 substitution argument given, but "
645         "this format string is missing its $0, contains one of $1-$9, "
646         "or contains an unescaped $ character (use $$ instead)");
647 
648 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
649                        const substitute_internal::Arg& a1)
650     ABSL_BAD_CALL_IF(
651         substitute_internal::PlaceholderBitmask(format) != 3,
652         "There were 2 substitution arguments given, but "
653         "this format string is missing its $0/$1, contains one of "
654         "$2-$9, or contains an unescaped $ character (use $$ instead)");
655 
656 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
657                        const substitute_internal::Arg& a1,
658                        const substitute_internal::Arg& a2)
659     ABSL_BAD_CALL_IF(
660         substitute_internal::PlaceholderBitmask(format) != 7,
661         "There were 3 substitution arguments given, but "
662         "this format string is missing its $0/$1/$2, contains one of "
663         "$3-$9, or contains an unescaped $ character (use $$ instead)");
664 
665 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
666                        const substitute_internal::Arg& a1,
667                        const substitute_internal::Arg& a2,
668                        const substitute_internal::Arg& a3)
669     ABSL_BAD_CALL_IF(
670         substitute_internal::PlaceholderBitmask(format) != 15,
671         "There were 4 substitution arguments given, but "
672         "this format string is missing its $0-$3, contains one of "
673         "$4-$9, or contains an unescaped $ character (use $$ instead)");
674 
675 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
676                        const substitute_internal::Arg& a1,
677                        const substitute_internal::Arg& a2,
678                        const substitute_internal::Arg& a3,
679                        const substitute_internal::Arg& a4)
680     ABSL_BAD_CALL_IF(
681         substitute_internal::PlaceholderBitmask(format) != 31,
682         "There were 5 substitution arguments given, but "
683         "this format string is missing its $0-$4, contains one of "
684         "$5-$9, or contains an unescaped $ character (use $$ instead)");
685 
686 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
687                        const substitute_internal::Arg& a1,
688                        const substitute_internal::Arg& a2,
689                        const substitute_internal::Arg& a3,
690                        const substitute_internal::Arg& a4,
691                        const substitute_internal::Arg& a5)
692     ABSL_BAD_CALL_IF(
693         substitute_internal::PlaceholderBitmask(format) != 63,
694         "There were 6 substitution arguments given, but "
695         "this format string is missing its $0-$5, contains one of "
696         "$6-$9, or contains an unescaped $ character (use $$ instead)");
697 
698 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
699                        const substitute_internal::Arg& a1,
700                        const substitute_internal::Arg& a2,
701                        const substitute_internal::Arg& a3,
702                        const substitute_internal::Arg& a4,
703                        const substitute_internal::Arg& a5,
704                        const substitute_internal::Arg& a6)
705     ABSL_BAD_CALL_IF(
706         substitute_internal::PlaceholderBitmask(format) != 127,
707         "There were 7 substitution arguments given, but "
708         "this format string is missing its $0-$6, contains one of "
709         "$7-$9, or contains an unescaped $ character (use $$ instead)");
710 
711 std::string Substitute(const char* format, const substitute_internal::Arg& a0,
712                        const substitute_internal::Arg& a1,
713                        const substitute_internal::Arg& a2,
714                        const substitute_internal::Arg& a3,
715                        const substitute_internal::Arg& a4,
716                        const substitute_internal::Arg& a5,
717                        const substitute_internal::Arg& a6,
718                        const substitute_internal::Arg& a7)
719     ABSL_BAD_CALL_IF(
720         substitute_internal::PlaceholderBitmask(format) != 255,
721         "There were 8 substitution arguments given, but "
722         "this format string is missing its $0-$7, contains one of "
723         "$8-$9, or contains an unescaped $ character (use $$ instead)");
724 
725 std::string Substitute(
726     const char* format, const substitute_internal::Arg& a0,
727     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
728     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
729     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
730     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
731     ABSL_BAD_CALL_IF(
732         substitute_internal::PlaceholderBitmask(format) != 511,
733         "There were 9 substitution arguments given, but "
734         "this format string is missing its $0-$8, contains a $9, or "
735         "contains an unescaped $ character (use $$ instead)");
736 
737 std::string Substitute(
738     const char* format, const substitute_internal::Arg& a0,
739     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
740     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
741     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
742     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
743     const substitute_internal::Arg& a9)
744     ABSL_BAD_CALL_IF(
745         substitute_internal::PlaceholderBitmask(format) != 1023,
746         "There were 10 substitution arguments given, but this "
747         "format string either doesn't contain all of $0 through $9 or "
748         "contains an unescaped $ character (use $$ instead)");
749 #endif  // ABSL_BAD_CALL_IF
750 
751 ABSL_NAMESPACE_END
752 }  // namespace absl
753 
754 #endif  // ABSL_STRINGS_SUBSTITUTE_H_
755