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