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