xref: /aosp_15_r20/external/cronet/third_party/abseil-cpp/absl/strings/substitute.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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/nullability.h"
82 #include "absl/base/port.h"
83 #include "absl/strings/ascii.h"
84 #include "absl/strings/escaping.h"
85 #include "absl/strings/internal/stringify_sink.h"
86 #include "absl/strings/numbers.h"
87 #include "absl/strings/str_cat.h"
88 #include "absl/strings/str_split.h"
89 #include "absl/strings/string_view.h"
90 #include "absl/strings/strip.h"
91 
92 namespace absl {
93 ABSL_NAMESPACE_BEGIN
94 namespace substitute_internal {
95 
96 // Arg
97 //
98 // This class provides an argument type for `absl::Substitute()` and
99 // `absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various
100 // types to a string. (`Arg` is very similar to the `AlphaNum` class in
101 // `StrCat()`.)
102 //
103 // This class has implicit constructors.
104 class Arg {
105  public:
106   // Overloads for string-y things
107   //
108   // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
Arg(absl::Nullable<const char * > value)109   Arg(absl::Nullable<const char*> value)  // NOLINT(google-explicit-constructor)
110       : piece_(absl::NullSafeStringView(value)) {}
111   template <typename Allocator>
Arg(const std::basic_string<char,std::char_traits<char>,Allocator> & value)112   Arg(  // NOLINT
113       const std::basic_string<char, std::char_traits<char>, Allocator>&
114           value) noexcept
115       : piece_(value) {}
Arg(absl::string_view value)116   Arg(absl::string_view value)  // NOLINT(google-explicit-constructor)
117       : piece_(value) {}
118 
119   // Overloads for primitives
120   //
121   // No overloads are available for signed and unsigned char because if people
122   // are explicitly declaring their chars as signed or unsigned then they are
123   // probably using them as 8-bit integers and would probably prefer an integer
124   // representation. However, we can't really know, so we make the caller decide
125   // what to do.
Arg(char value)126   Arg(char value)  // NOLINT(google-explicit-constructor)
127       : piece_(scratch_, 1) {
128     scratch_[0] = value;
129   }
Arg(short value)130   Arg(short value)  // NOLINT(*)
131       : piece_(scratch_,
132                static_cast<size_t>(
133                    numbers_internal::FastIntToBuffer(value, scratch_) -
134                    scratch_)) {}
Arg(unsigned short value)135   Arg(unsigned short value)  // NOLINT(*)
136       : piece_(scratch_,
137                static_cast<size_t>(
138                    numbers_internal::FastIntToBuffer(value, scratch_) -
139                    scratch_)) {}
Arg(int value)140   Arg(int value)  // NOLINT(google-explicit-constructor)
141       : piece_(scratch_,
142                static_cast<size_t>(
143                    numbers_internal::FastIntToBuffer(value, scratch_) -
144                    scratch_)) {}
Arg(unsigned int value)145   Arg(unsigned int value)  // NOLINT(google-explicit-constructor)
146       : piece_(scratch_,
147                static_cast<size_t>(
148                    numbers_internal::FastIntToBuffer(value, scratch_) -
149                    scratch_)) {}
Arg(long value)150   Arg(long value)  // NOLINT(*)
151       : piece_(scratch_,
152                static_cast<size_t>(
153                    numbers_internal::FastIntToBuffer(value, scratch_) -
154                    scratch_)) {}
Arg(unsigned long value)155   Arg(unsigned long value)  // NOLINT(*)
156       : piece_(scratch_,
157                static_cast<size_t>(
158                    numbers_internal::FastIntToBuffer(value, scratch_) -
159                    scratch_)) {}
Arg(long long value)160   Arg(long long value)  // NOLINT(*)
161       : piece_(scratch_,
162                static_cast<size_t>(
163                    numbers_internal::FastIntToBuffer(value, scratch_) -
164                    scratch_)) {}
Arg(unsigned long long value)165   Arg(unsigned long long value)  // NOLINT(*)
166       : piece_(scratch_,
167                static_cast<size_t>(
168                    numbers_internal::FastIntToBuffer(value, scratch_) -
169                    scratch_)) {}
Arg(float value)170   Arg(float value)  // NOLINT(google-explicit-constructor)
171       : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
172   }
Arg(double value)173   Arg(double value)  // NOLINT(google-explicit-constructor)
174       : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
175   }
Arg(bool value)176   Arg(bool value)  // NOLINT(google-explicit-constructor)
177       : piece_(value ? "true" : "false") {}
178 
179   template <typename T, typename = typename std::enable_if<
180                             HasAbslStringify<T>::value>::type>
181   Arg(  // NOLINT(google-explicit-constructor)
182       const T& v, strings_internal::StringifySink&& sink = {})
piece_(strings_internal::ExtractStringification (sink,v))183       : piece_(strings_internal::ExtractStringification(sink, v)) {}
184 
185   Arg(Hex hex);  // NOLINT(google-explicit-constructor)
186   Arg(Dec dec);  // NOLINT(google-explicit-constructor)
187 
188   // vector<bool>::reference and const_reference require special help to convert
189   // to `Arg` because it requires two user defined conversions.
190   template <typename T,
191             absl::enable_if_t<
192                 std::is_class<T>::value &&
193                 (std::is_same<T, std::vector<bool>::reference>::value ||
194                  std::is_same<T, std::vector<bool>::const_reference>::value)>* =
195                 nullptr>
Arg(T value)196   Arg(T value)  // NOLINT(google-explicit-constructor)
197       : Arg(static_cast<bool>(value)) {}
198 
199   // `void*` values, with the exception of `char*`, are printed as
200   // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
201   Arg(  // NOLINT(google-explicit-constructor)
202       absl::Nullable<const void*> value);
203 
204   // Normal enums are already handled by the integer formatters.
205   // This overload matches only scoped enums.
206   template <typename T,
207             typename = typename std::enable_if<
208                 std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
209                 !HasAbslStringify<T>::value>::type>
210   Arg(T value)  // NOLINT(google-explicit-constructor)
211       : Arg(static_cast<typename std::underlying_type<T>::type>(value)) {}
212 
213   Arg(const Arg&) = delete;
214   Arg& operator=(const Arg&) = delete;
215 
piece()216   absl::string_view piece() const { return piece_; }
217 
218  private:
219   absl::string_view piece_;
220   char scratch_[numbers_internal::kFastToBufferSize];
221 };
222 
223 // Internal helper function. Don't call this from outside this implementation.
224 // This interface may change without notice.
225 void SubstituteAndAppendArray(
226     absl::Nonnull<std::string*> output, absl::string_view format,
227     absl::Nullable<const absl::string_view*> args_array, size_t num_args);
228 
229 #if defined(ABSL_BAD_CALL_IF)
CalculateOneBit(absl::Nonnull<const char * > format)230 constexpr int CalculateOneBit(absl::Nonnull<const char*> format) {
231   // Returns:
232   // * 2^N for '$N' when N is in [0-9]
233   // * 0 for correct '$' escaping: '$$'.
234   // * -1 otherwise.
235   return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1)
236                                           : (1 << (*format - '0'));
237 }
238 
SkipNumber(absl::Nonnull<const char * > format)239 constexpr const char* SkipNumber(absl::Nonnull<const char*> format) {
240   return !*format ? format : (format + 1);
241 }
242 
PlaceholderBitmask(absl::Nonnull<const char * > format)243 constexpr int PlaceholderBitmask(absl::Nonnull<const char*> format) {
244   return !*format
245              ? 0
246              : *format != '$' ? PlaceholderBitmask(format + 1)
247                               : (CalculateOneBit(format + 1) |
248                                  PlaceholderBitmask(SkipNumber(format + 1)));
249 }
250 #endif  // ABSL_BAD_CALL_IF
251 
252 }  // namespace substitute_internal
253 
254 //
255 // PUBLIC API
256 //
257 
258 // SubstituteAndAppend()
259 //
260 // Substitutes variables into a given format string and appends to a given
261 // output string. See file comments above for usage.
262 //
263 // The declarations of `SubstituteAndAppend()` below consist of overloads
264 // for passing 0 to 10 arguments, respectively.
265 //
266 // NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic
267 // templates to allow a variable number of arguments.
268 //
269 // Example:
270 //  template <typename... Args>
271 //  void VarMsg(std::string* boilerplate, absl::string_view format,
272 //      const Args&... args) {
273 //    absl::SubstituteAndAppend(boilerplate, format, args...);
274 //  }
275 //
SubstituteAndAppend(absl::Nonnull<std::string * > output,absl::string_view format)276 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
277                                 absl::string_view format) {
278   substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
279 }
280 
SubstituteAndAppend(absl::Nonnull<std::string * > output,absl::string_view format,const substitute_internal::Arg & a0)281 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
282                                 absl::string_view format,
283                                 const substitute_internal::Arg& a0) {
284   const absl::string_view args[] = {a0.piece()};
285   substitute_internal::SubstituteAndAppendArray(output, format, args,
286                                                 ABSL_ARRAYSIZE(args));
287 }
288 
SubstituteAndAppend(absl::Nonnull<std::string * > output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1)289 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
290                                 absl::string_view format,
291                                 const substitute_internal::Arg& a0,
292                                 const substitute_internal::Arg& a1) {
293   const absl::string_view args[] = {a0.piece(), a1.piece()};
294   substitute_internal::SubstituteAndAppendArray(output, format, args,
295                                                 ABSL_ARRAYSIZE(args));
296 }
297 
SubstituteAndAppend(absl::Nonnull<std::string * > output,absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2)298 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
299                                 absl::string_view format,
300                                 const substitute_internal::Arg& a0,
301                                 const substitute_internal::Arg& a1,
302                                 const substitute_internal::Arg& a2) {
303   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()};
304   substitute_internal::SubstituteAndAppendArray(output, format, args,
305                                                 ABSL_ARRAYSIZE(args));
306 }
307 
SubstituteAndAppend(absl::Nonnull<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)308 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
309                                 absl::string_view format,
310                                 const substitute_internal::Arg& a0,
311                                 const substitute_internal::Arg& a1,
312                                 const substitute_internal::Arg& a2,
313                                 const substitute_internal::Arg& a3) {
314   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
315                                     a3.piece()};
316   substitute_internal::SubstituteAndAppendArray(output, format, args,
317                                                 ABSL_ARRAYSIZE(args));
318 }
319 
SubstituteAndAppend(absl::Nonnull<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)320 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
321                                 absl::string_view format,
322                                 const substitute_internal::Arg& a0,
323                                 const substitute_internal::Arg& a1,
324                                 const substitute_internal::Arg& a2,
325                                 const substitute_internal::Arg& a3,
326                                 const substitute_internal::Arg& a4) {
327   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
328                                     a3.piece(), a4.piece()};
329   substitute_internal::SubstituteAndAppendArray(output, format, args,
330                                                 ABSL_ARRAYSIZE(args));
331 }
332 
SubstituteAndAppend(absl::Nonnull<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)333 inline void SubstituteAndAppend(
334     absl::Nonnull<std::string*> output, absl::string_view format,
335     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
336     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
337     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5) {
338   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
339                                     a3.piece(), a4.piece(), a5.piece()};
340   substitute_internal::SubstituteAndAppendArray(output, format, args,
341                                                 ABSL_ARRAYSIZE(args));
342 }
343 
SubstituteAndAppend(absl::Nonnull<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)344 inline void SubstituteAndAppend(
345     absl::Nonnull<std::string*> output, absl::string_view format,
346     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
347     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
348     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
349     const substitute_internal::Arg& a6) {
350   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
351                                     a3.piece(), a4.piece(), a5.piece(),
352                                     a6.piece()};
353   substitute_internal::SubstituteAndAppendArray(output, format, args,
354                                                 ABSL_ARRAYSIZE(args));
355 }
356 
SubstituteAndAppend(absl::Nonnull<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)357 inline void SubstituteAndAppend(
358     absl::Nonnull<std::string*> output, absl::string_view format,
359     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
360     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
361     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
362     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) {
363   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
364                                     a3.piece(), a4.piece(), a5.piece(),
365                                     a6.piece(), a7.piece()};
366   substitute_internal::SubstituteAndAppendArray(output, format, args,
367                                                 ABSL_ARRAYSIZE(args));
368 }
369 
SubstituteAndAppend(absl::Nonnull<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)370 inline void SubstituteAndAppend(
371     absl::Nonnull<std::string*> output, absl::string_view format,
372     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
373     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
374     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
375     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
376     const substitute_internal::Arg& a8) {
377   const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
378                                     a3.piece(), a4.piece(), a5.piece(),
379                                     a6.piece(), a7.piece(), a8.piece()};
380   substitute_internal::SubstituteAndAppendArray(output, format, args,
381                                                 ABSL_ARRAYSIZE(args));
382 }
383 
SubstituteAndAppend(absl::Nonnull<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)384 inline void SubstituteAndAppend(
385     absl::Nonnull<std::string*> output, absl::string_view format,
386     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
387     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
388     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
389     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
390     const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) {
391   const absl::string_view args[] = {
392       a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(),
393       a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()};
394   substitute_internal::SubstituteAndAppendArray(output, format, args,
395                                                 ABSL_ARRAYSIZE(args));
396 }
397 
398 #if defined(ABSL_BAD_CALL_IF)
399 // This body of functions catches cases where the number of placeholders
400 // doesn't match the number of data arguments.
401 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
402                          absl::Nonnull<const char*> format)
403     ABSL_BAD_CALL_IF(
404         substitute_internal::PlaceholderBitmask(format) != 0,
405         "There were no substitution arguments "
406         "but this format string either has a $[0-9] in it or contains "
407         "an unescaped $ character (use $$ instead)");
408 
409 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
410                          absl::Nonnull<const char*> format,
411                          const substitute_internal::Arg& a0)
412     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
413                      "There was 1 substitution argument given, but "
414                      "this format string is missing its $0, contains "
415                      "one of $1-$9, or contains an unescaped $ character (use "
416                      "$$ instead)");
417 
418 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
419                          absl::Nonnull<const char*> format,
420                          const substitute_internal::Arg& a0,
421                          const substitute_internal::Arg& a1)
422     ABSL_BAD_CALL_IF(
423         substitute_internal::PlaceholderBitmask(format) != 3,
424         "There were 2 substitution arguments given, but this format string is "
425         "missing its $0/$1, contains one of $2-$9, or contains an "
426         "unescaped $ character (use $$ instead)");
427 
428 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
429                          absl::Nonnull<const char*> format,
430                          const substitute_internal::Arg& a0,
431                          const substitute_internal::Arg& a1,
432                          const substitute_internal::Arg& a2)
433     ABSL_BAD_CALL_IF(
434         substitute_internal::PlaceholderBitmask(format) != 7,
435         "There were 3 substitution arguments given, but "
436         "this format string is missing its $0/$1/$2, contains one of "
437         "$3-$9, or contains an unescaped $ character (use $$ instead)");
438 
439 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
440                          absl::Nonnull<const char*> format,
441                          const substitute_internal::Arg& a0,
442                          const substitute_internal::Arg& a1,
443                          const substitute_internal::Arg& a2,
444                          const substitute_internal::Arg& a3)
445     ABSL_BAD_CALL_IF(
446         substitute_internal::PlaceholderBitmask(format) != 15,
447         "There were 4 substitution arguments given, but "
448         "this format string is missing its $0-$3, contains one of "
449         "$4-$9, or contains an unescaped $ character (use $$ instead)");
450 
451 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
452                          absl::Nonnull<const char*> format,
453                          const substitute_internal::Arg& a0,
454                          const substitute_internal::Arg& a1,
455                          const substitute_internal::Arg& a2,
456                          const substitute_internal::Arg& a3,
457                          const substitute_internal::Arg& a4)
458     ABSL_BAD_CALL_IF(
459         substitute_internal::PlaceholderBitmask(format) != 31,
460         "There were 5 substitution arguments given, but "
461         "this format string is missing its $0-$4, contains one of "
462         "$5-$9, or contains an unescaped $ character (use $$ instead)");
463 
464 void SubstituteAndAppend(
465     absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
466     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
467     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
468     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5)
469     ABSL_BAD_CALL_IF(
470         substitute_internal::PlaceholderBitmask(format) != 63,
471         "There were 6 substitution arguments given, but "
472         "this format string is missing its $0-$5, contains one of "
473         "$6-$9, or contains an unescaped $ character (use $$ instead)");
474 
475 void SubstituteAndAppend(
476     absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
477     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
478     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
479     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
480     const substitute_internal::Arg& a6)
481     ABSL_BAD_CALL_IF(
482         substitute_internal::PlaceholderBitmask(format) != 127,
483         "There were 7 substitution arguments given, but "
484         "this format string is missing its $0-$6, contains one of "
485         "$7-$9, or contains an unescaped $ character (use $$ instead)");
486 
487 void SubstituteAndAppend(
488     absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
489     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
490     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
491     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
492     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7)
493     ABSL_BAD_CALL_IF(
494         substitute_internal::PlaceholderBitmask(format) != 255,
495         "There were 8 substitution arguments given, but "
496         "this format string is missing its $0-$7, contains one of "
497         "$8-$9, or contains an unescaped $ character (use $$ instead)");
498 
499 void SubstituteAndAppend(
500     absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
501     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
502     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
503     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
504     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
505     const substitute_internal::Arg& a8)
506     ABSL_BAD_CALL_IF(
507         substitute_internal::PlaceholderBitmask(format) != 511,
508         "There were 9 substitution arguments given, but "
509         "this format string is missing its $0-$8, contains a $9, or "
510         "contains an unescaped $ character (use $$ instead)");
511 
512 void SubstituteAndAppend(
513     absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
514     const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
515     const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
516     const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
517     const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
518     const substitute_internal::Arg& a8, const substitute_internal::Arg& a9)
519     ABSL_BAD_CALL_IF(
520         substitute_internal::PlaceholderBitmask(format) != 1023,
521         "There were 10 substitution arguments given, but this "
522         "format string either doesn't contain all of $0 through $9 or "
523         "contains an unescaped $ character (use $$ instead)");
524 #endif  // ABSL_BAD_CALL_IF
525 
526 // Substitute()
527 //
528 // Substitutes variables into a given format string. See file comments above
529 // for usage.
530 //
531 // The declarations of `Substitute()` below consist of overloads for passing 0
532 // to 10 arguments, respectively.
533 //
534 // NOTE: A zero-argument `Substitute()` may be used within variadic templates to
535 // allow a variable number of arguments.
536 //
537 // Example:
538 //  template <typename... Args>
539 //  void VarMsg(absl::string_view format, const Args&... args) {
540 //    std::string s = absl::Substitute(format, args...);
541 
Substitute(absl::string_view format)542 ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
543   std::string result;
544   SubstituteAndAppend(&result, format);
545   return result;
546 }
547 
Substitute(absl::string_view format,const substitute_internal::Arg & a0)548 ABSL_MUST_USE_RESULT inline std::string Substitute(
549     absl::string_view format, const substitute_internal::Arg& a0) {
550   std::string result;
551   SubstituteAndAppend(&result, format, a0);
552   return result;
553 }
554 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1)555 ABSL_MUST_USE_RESULT inline std::string Substitute(
556     absl::string_view format, const substitute_internal::Arg& a0,
557     const substitute_internal::Arg& a1) {
558   std::string result;
559   SubstituteAndAppend(&result, format, a0, a1);
560   return result;
561 }
562 
Substitute(absl::string_view format,const substitute_internal::Arg & a0,const substitute_internal::Arg & a1,const substitute_internal::Arg & a2)563 ABSL_MUST_USE_RESULT inline std::string Substitute(
564     absl::string_view format, const substitute_internal::Arg& a0,
565     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) {
566   std::string result;
567   SubstituteAndAppend(&result, format, a0, a1, a2);
568   return result;
569 }
570 
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)571 ABSL_MUST_USE_RESULT inline std::string Substitute(
572     absl::string_view format, const substitute_internal::Arg& a0,
573     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
574     const substitute_internal::Arg& a3) {
575   std::string result;
576   SubstituteAndAppend(&result, format, a0, a1, a2, a3);
577   return result;
578 }
579 
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)580 ABSL_MUST_USE_RESULT inline std::string Substitute(
581     absl::string_view format, const substitute_internal::Arg& a0,
582     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
583     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
584   std::string result;
585   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4);
586   return result;
587 }
588 
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)589 ABSL_MUST_USE_RESULT inline std::string Substitute(
590     absl::string_view format, const substitute_internal::Arg& a0,
591     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
592     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
593     const substitute_internal::Arg& a5) {
594   std::string result;
595   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5);
596   return result;
597 }
598 
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)599 ABSL_MUST_USE_RESULT inline std::string Substitute(
600     absl::string_view format, const substitute_internal::Arg& a0,
601     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
602     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
603     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) {
604   std::string result;
605   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6);
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)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) {
615   std::string result;
616   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7);
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)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   std::string result;
627   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8);
628   return result;
629 }
630 
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)631 ABSL_MUST_USE_RESULT inline std::string Substitute(
632     absl::string_view format, const substitute_internal::Arg& a0,
633     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
634     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
635     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
636     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
637     const substitute_internal::Arg& a9) {
638   std::string result;
639   SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
640   return result;
641 }
642 
643 #if defined(ABSL_BAD_CALL_IF)
644 // This body of functions catches cases where the number of placeholders
645 // doesn't match the number of data arguments.
646 std::string Substitute(absl::Nonnull<const char*> format)
647     ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
648                      "There were no substitution arguments "
649                      "but this format string either has a $[0-9] in it or "
650                      "contains an unescaped $ character (use $$ instead)");
651 
652 std::string Substitute(absl::Nonnull<const char*> format,
653                        const substitute_internal::Arg& a0)
654     ABSL_BAD_CALL_IF(
655         substitute_internal::PlaceholderBitmask(format) != 1,
656         "There was 1 substitution argument given, but "
657         "this format string is missing its $0, contains one of $1-$9, "
658         "or contains an unescaped $ character (use $$ instead)");
659 
660 std::string Substitute(absl::Nonnull<const char*> format,
661                        const substitute_internal::Arg& a0,
662                        const substitute_internal::Arg& a1)
663     ABSL_BAD_CALL_IF(
664         substitute_internal::PlaceholderBitmask(format) != 3,
665         "There were 2 substitution arguments given, but "
666         "this format string is missing its $0/$1, contains one of "
667         "$2-$9, or contains an unescaped $ character (use $$ instead)");
668 
669 std::string Substitute(absl::Nonnull<const char*> format,
670                        const substitute_internal::Arg& a0,
671                        const substitute_internal::Arg& a1,
672                        const substitute_internal::Arg& a2)
673     ABSL_BAD_CALL_IF(
674         substitute_internal::PlaceholderBitmask(format) != 7,
675         "There were 3 substitution arguments given, but "
676         "this format string is missing its $0/$1/$2, contains one of "
677         "$3-$9, or contains an unescaped $ character (use $$ instead)");
678 
679 std::string Substitute(absl::Nonnull<const char*> format,
680                        const substitute_internal::Arg& a0,
681                        const substitute_internal::Arg& a1,
682                        const substitute_internal::Arg& a2,
683                        const substitute_internal::Arg& a3)
684     ABSL_BAD_CALL_IF(
685         substitute_internal::PlaceholderBitmask(format) != 15,
686         "There were 4 substitution arguments given, but "
687         "this format string is missing its $0-$3, contains one of "
688         "$4-$9, or contains an unescaped $ character (use $$ instead)");
689 
690 std::string Substitute(absl::Nonnull<const char*> format,
691                        const substitute_internal::Arg& a0,
692                        const substitute_internal::Arg& a1,
693                        const substitute_internal::Arg& a2,
694                        const substitute_internal::Arg& a3,
695                        const substitute_internal::Arg& a4)
696     ABSL_BAD_CALL_IF(
697         substitute_internal::PlaceholderBitmask(format) != 31,
698         "There were 5 substitution arguments given, but "
699         "this format string is missing its $0-$4, contains one of "
700         "$5-$9, or contains an unescaped $ character (use $$ instead)");
701 
702 std::string Substitute(absl::Nonnull<const char*> format,
703                        const substitute_internal::Arg& a0,
704                        const substitute_internal::Arg& a1,
705                        const substitute_internal::Arg& a2,
706                        const substitute_internal::Arg& a3,
707                        const substitute_internal::Arg& a4,
708                        const substitute_internal::Arg& a5)
709     ABSL_BAD_CALL_IF(
710         substitute_internal::PlaceholderBitmask(format) != 63,
711         "There were 6 substitution arguments given, but "
712         "this format string is missing its $0-$5, contains one of "
713         "$6-$9, or contains an unescaped $ character (use $$ instead)");
714 
715 std::string Substitute(
716     absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
717     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
718     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
719     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
720     ABSL_BAD_CALL_IF(
721         substitute_internal::PlaceholderBitmask(format) != 127,
722         "There were 7 substitution arguments given, but "
723         "this format string is missing its $0-$6, contains one of "
724         "$7-$9, or contains an unescaped $ character (use $$ instead)");
725 
726 std::string Substitute(
727     absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
728     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
729     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
730     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
731     const substitute_internal::Arg& a7)
732     ABSL_BAD_CALL_IF(
733         substitute_internal::PlaceholderBitmask(format) != 255,
734         "There were 8 substitution arguments given, but "
735         "this format string is missing its $0-$7, contains one of "
736         "$8-$9, or contains an unescaped $ character (use $$ instead)");
737 
738 std::string Substitute(
739     absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
740     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
741     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
742     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
743     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
744     ABSL_BAD_CALL_IF(
745         substitute_internal::PlaceholderBitmask(format) != 511,
746         "There were 9 substitution arguments given, but "
747         "this format string is missing its $0-$8, contains a $9, or "
748         "contains an unescaped $ character (use $$ instead)");
749 
750 std::string Substitute(
751     absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
752     const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
753     const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
754     const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
755     const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
756     const substitute_internal::Arg& a9)
757     ABSL_BAD_CALL_IF(
758         substitute_internal::PlaceholderBitmask(format) != 1023,
759         "There were 10 substitution arguments given, but this "
760         "format string either doesn't contain all of $0 through $9 or "
761         "contains an unescaped $ character (use $$ instead)");
762 #endif  // ABSL_BAD_CALL_IF
763 
764 ABSL_NAMESPACE_END
765 }  // namespace absl
766 
767 #endif  // ABSL_STRINGS_SUBSTITUTE_H_
768