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