blob: c6da4dc6e72238c94713707fe82267fef4e245b9 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001//
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 "")
Austin Schuhb4691e92020-12-31 12:37:18 -080053// * int32_t, int64_t, uint32_t, uint64_t
Austin Schuh36244a12019-09-21 17:52:38 -070054// * 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
88namespace absl {
Austin Schuhb4691e92020-12-31 12:37:18 -080089ABSL_NAMESPACE_BEGIN
Austin Schuh36244a12019-09-21 17:52:38 -070090namespace 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.
100class Arg {
101 public:
Austin Schuhb4691e92020-12-31 12:37:18 -0800102 // Overloads for string-y things
Austin Schuh36244a12019-09-21 17:52:38 -0700103 //
104 // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
105 Arg(const char* value) // NOLINT(runtime/explicit)
106 : piece_(absl::NullSafeStringView(value)) {}
107 template <typename Allocator>
108 Arg( // NOLINT
109 const std::basic_string<char, std::char_traits<char>, Allocator>&
110 value) noexcept
111 : piece_(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.
122 Arg(char value) // NOLINT(runtime/explicit)
Austin Schuhb4691e92020-12-31 12:37:18 -0800123 : piece_(scratch_, 1) {
124 scratch_[0] = value;
125 }
Austin Schuh36244a12019-09-21 17:52:38 -0700126 Arg(short value) // NOLINT(*)
127 : piece_(scratch_,
128 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
129 Arg(unsigned short value) // NOLINT(*)
130 : piece_(scratch_,
131 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
132 Arg(int value) // NOLINT(runtime/explicit)
133 : piece_(scratch_,
134 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
135 Arg(unsigned int value) // NOLINT(runtime/explicit)
136 : piece_(scratch_,
137 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
138 Arg(long value) // NOLINT(*)
139 : piece_(scratch_,
140 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
141 Arg(unsigned long value) // NOLINT(*)
142 : piece_(scratch_,
143 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
144 Arg(long long value) // NOLINT(*)
145 : piece_(scratch_,
146 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
147 Arg(unsigned long long value) // NOLINT(*)
148 : piece_(scratch_,
149 numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
150 Arg(float value) // NOLINT(runtime/explicit)
151 : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
152 }
153 Arg(double value) // NOLINT(runtime/explicit)
154 : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
155 }
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>
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
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.
189void 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)
194constexpr int CalculateOneBit(const char* format) {
Austin Schuhb4691e92020-12-31 12:37:18 -0800195 // 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'));
Austin Schuh36244a12019-09-21 17:52:38 -0700201}
202
203constexpr const char* SkipNumber(const char* format) {
204 return !*format ? format : (format + 1);
205}
206
207constexpr int PlaceholderBitmask(const char* format) {
Austin Schuhb4691e92020-12-31 12:37:18 -0800208 return !*format
209 ? 0
210 : *format != '$' ? PlaceholderBitmask(format + 1)
211 : (CalculateOneBit(format + 1) |
212 PlaceholderBitmask(SkipNumber(format + 1)));
Austin Schuh36244a12019-09-21 17:52:38 -0700213}
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//
240inline void SubstituteAndAppend(std::string* output, absl::string_view format) {
241 substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
242}
243
244inline 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
251inline 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
259inline 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
268inline 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
279inline 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
291inline 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
304inline 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
319inline 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
332inline 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
346inline 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.
363void SubstituteAndAppend(std::string* output, const char* format)
364 ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
365 "There were no substitution arguments "
Austin Schuhb4691e92020-12-31 12:37:18 -0800366 "but this format string has a $[0-9] in it");
Austin Schuh36244a12019-09-21 17:52:38 -0700367
368void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800372 "this format string is either missing its $0, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700373 "contains one of $1-$9");
374
375void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800380 "this format string is either missing its $0/$1, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700381 "contains one of $2-$9");
382
383void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800389 "this format string is either missing its $0/$1/$2, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700390 "contains one of $3-$9");
391
392void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800399 "this format string is either missing its $0-$3, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700400 "contains one of $4-$9");
401
402void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800410 "this format string is either missing its $0-$4, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700411 "contains one of $5-$9");
412
413void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800422 "this format string is either missing its $0-$5, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700423 "contains one of $6-$9");
424
425void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800432 "this format string is either missing its $0-$6, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700433 "contains one of $7-$9");
434
435void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800443 "this format string is either missing its $0-$7, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700444 "contains one of $8-$9");
445
446void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800455 "this format string is either missing its $0-$8, or contains a $9");
Austin Schuh36244a12019-09-21 17:52:38 -0700456
457void 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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800466 "format string doesn't contain all of $0 through $9");
Austin Schuh36244a12019-09-21 17:52:38 -0700467#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
485ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
486 std::string result;
487 SubstituteAndAppend(&result, format);
488 return result;
489}
490
491ABSL_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
498ABSL_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
506ABSL_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
514ABSL_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
523ABSL_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
532ABSL_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
542ABSL_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
552ABSL_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
563ABSL_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
574ABSL_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.
589std::string Substitute(const char* format)
590 ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
591 "There were no substitution arguments "
Austin Schuhb4691e92020-12-31 12:37:18 -0800592 "but this format string has a $[0-9] in it");
Austin Schuh36244a12019-09-21 17:52:38 -0700593
594std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800597 "this format string is either missing its $0, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700598 "contains one of $1-$9");
599
600std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800604 "this format string is either missing its $0/$1, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700605 "contains one of $2-$9");
606
607std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800612 "this format string is either missing its $0/$1/$2, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700613 "contains one of $3-$9");
614
615std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800621 "this format string is either missing its $0-$3, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700622 "contains one of $4-$9");
623
624std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800631 "this format string is either missing its $0-$4, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700632 "contains one of $5-$9");
633
634std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800642 "this format string is either missing its $0-$5, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700643 "contains one of $6-$9");
644
645std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800654 "this format string is either missing its $0-$6, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700655 "contains one of $7-$9");
656
657std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800667 "this format string is either missing its $0-$7, or "
Austin Schuh36244a12019-09-21 17:52:38 -0700668 "contains one of $8-$9");
669
670std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800679 "this format string is either missing its $0-$8, or contains a $9");
Austin Schuh36244a12019-09-21 17:52:38 -0700680
681std::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 "
Austin Schuhb4691e92020-12-31 12:37:18 -0800690 "format string doesn't contain all of $0 through $9");
Austin Schuh36244a12019-09-21 17:52:38 -0700691#endif // ABSL_BAD_CALL_IF
692
Austin Schuhb4691e92020-12-31 12:37:18 -0800693ABSL_NAMESPACE_END
Austin Schuh36244a12019-09-21 17:52:38 -0700694} // namespace absl
695
696#endif // ABSL_STRINGS_SUBSTITUTE_H_