Coverage Report

Created: 2025-11-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/external/abseil-cpp~/absl/strings/substitute.h
Line
Count
Source
1
//
2
// Copyright 2017 The Abseil Authors.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
//      https://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
//
16
// -----------------------------------------------------------------------------
17
// File: substitute.h
18
// -----------------------------------------------------------------------------
19
//
20
// This package contains functions for efficiently performing string
21
// substitutions using a format string with positional notation:
22
// `Substitute()` and `SubstituteAndAppend()`.
23
//
24
// Unlike printf-style format specifiers, `Substitute()` functions do not need
25
// to specify the type of the substitution arguments. Supported arguments
26
// following the format string, such as strings, string_views, ints,
27
// floats, and bools, are automatically converted to strings during the
28
// substitution process. (See below for a full list of supported types.)
29
//
30
// `Substitute()` does not allow you to specify *how* to format a value, beyond
31
// the default conversion to string. For example, you cannot format an integer
32
// in hex.
33
//
34
// The format string uses positional identifiers indicated by a dollar sign ($)
35
// and single digit positional ids to indicate which substitution arguments to
36
// use at that location within the format string.
37
//
38
// A '$$' sequence in the format string causes a literal '$' character to be
39
// output.
40
//
41
// Example 1:
42
//   std::string s = Substitute("$1 purchased $0 $2 for $$10. Thanks $1!",
43
//                              5, "Bob", "Apples");
44
//   EXPECT_EQ("Bob purchased 5 Apples for $10. Thanks Bob!", s);
45
//
46
// Example 2:
47
//   std::string s = "Hi. ";
48
//   SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
49
//   EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s);
50
//
51
// Supported types:
52
//   * absl::string_view, std::string, const char* (null is equivalent to "")
53
//   * int32_t, int64_t, uint32_t, uint64_t
54
//   * float, double
55
//   * bool (Printed as "true" or "false")
56
//   * pointer types other than char* (Printed as "0x<lower case hex string>",
57
//     except that null is printed as "NULL")
58
//   * user-defined types via the `AbslStringify()` customization point. See the
59
//     documentation for `absl::StrCat` for an explanation on how to use this.
60
//
61
// If an invalid format string is provided, Substitute returns an empty string
62
// and SubstituteAndAppend does not change the provided output string.
63
// A format string is invalid if it:
64
//   * ends in an unescaped $ character,
65
//     e.g. "Hello $", or
66
//   * calls for a position argument which is not provided,
67
//     e.g. Substitute("Hello $2", "world"), or
68
//   * specifies a non-digit, non-$ character after an unescaped $ character,
69
//     e.g. "Hello $f".
70
// In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program.
71
72
#ifndef ABSL_STRINGS_SUBSTITUTE_H_
73
#define ABSL_STRINGS_SUBSTITUTE_H_
74
75
#include <cstring>
76
#include <string>
77
#include <type_traits>
78
#include <vector>
79
80
#include "absl/base/macros.h"
81
#include "absl/base/nullability.h"
82
#include "absl/base/port.h"
83
#include "absl/strings/ascii.h"
84
#include "absl/strings/escaping.h"
85
#include "absl/strings/internal/stringify_sink.h"
86
#include "absl/strings/numbers.h"
87
#include "absl/strings/str_cat.h"
88
#include "absl/strings/str_split.h"
89
#include "absl/strings/string_view.h"
90
#include "absl/strings/strip.h"
91
92
namespace absl {
93
ABSL_NAMESPACE_BEGIN
94
namespace substitute_internal {
95
96
// Arg
97
//
98
// This class provides an argument type for `absl::Substitute()` and
99
// `absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various
100
// types to a string. (`Arg` is very similar to the `AlphaNum` class in
101
// `StrCat()`.)
102
//
103
// This class has implicit constructors.
104
class Arg {
105
 public:
106
  // Overloads for string-y things
107
  //
108
  // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
109
  Arg(const char* absl_nullable value)  // NOLINT(google-explicit-constructor)
110
0
      : piece_(absl::NullSafeStringView(value)) {}
111
  template <typename Allocator>
112
  Arg(  // NOLINT
113
      const std::basic_string<char, std::char_traits<char>, Allocator>&
114
          value) noexcept
115
0
      : piece_(value) {}
116
  Arg(absl::string_view value)  // NOLINT(google-explicit-constructor)
117
0
      : piece_(value) {}
118
119
  // Overloads for primitives
120
  //
121
  // No overloads are available for signed and unsigned char because if people
122
  // are explicitly declaring their chars as signed or unsigned then they are
123
  // probably using them as 8-bit integers and would probably prefer an integer
124
  // representation. However, we can't really know, so we make the caller decide
125
  // what to do.
126
  Arg(char value)  // NOLINT(google-explicit-constructor)
127
0
      : piece_(scratch_, 1) {
128
0
    scratch_[0] = value;
129
0
  }
130
  Arg(short value)  // NOLINT(*)
131
      : piece_(scratch_,
132
               static_cast<size_t>(
133
                   numbers_internal::FastIntToBuffer(value, scratch_) -
134
0
                   scratch_)) {}
135
  Arg(unsigned short value)  // NOLINT(*)
136
      : piece_(scratch_,
137
               static_cast<size_t>(
138
                   numbers_internal::FastIntToBuffer(value, scratch_) -
139
0
                   scratch_)) {}
140
  Arg(int value)  // NOLINT(google-explicit-constructor)
141
0
      : piece_(scratch_,
142
0
               static_cast<size_t>(
143
0
                   numbers_internal::FastIntToBuffer(value, scratch_) -
144
0
                   scratch_)) {}
145
  Arg(unsigned int value)  // NOLINT(google-explicit-constructor)
146
      : piece_(scratch_,
147
               static_cast<size_t>(
148
                   numbers_internal::FastIntToBuffer(value, scratch_) -
149
0
                   scratch_)) {}
150
  Arg(long value)  // NOLINT(*)
151
0
      : piece_(scratch_,
152
0
               static_cast<size_t>(
153
0
                   numbers_internal::FastIntToBuffer(value, scratch_) -
154
0
                   scratch_)) {}
155
  Arg(unsigned long value)  // NOLINT(*)
156
      : piece_(scratch_,
157
               static_cast<size_t>(
158
                   numbers_internal::FastIntToBuffer(value, scratch_) -
159
0
                   scratch_)) {}
160
  Arg(long long value)  // NOLINT(*)
161
      : piece_(scratch_,
162
               static_cast<size_t>(
163
                   numbers_internal::FastIntToBuffer(value, scratch_) -
164
0
                   scratch_)) {}
165
  Arg(unsigned long long value)  // NOLINT(*)
166
      : piece_(scratch_,
167
               static_cast<size_t>(
168
                   numbers_internal::FastIntToBuffer(value, scratch_) -
169
0
                   scratch_)) {}
170
  Arg(float value)  // NOLINT(google-explicit-constructor)
171
0
      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
172
0
  }
173
  Arg(double value)  // NOLINT(google-explicit-constructor)
174
0
      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
175
0
  }
176
  Arg(bool value)  // NOLINT(google-explicit-constructor)
177
0
      : piece_(value ? "true" : "false") {}
178
179
  template <typename T, typename = typename std::enable_if<
180
                            HasAbslStringify<T>::value>::type>
181
  Arg(  // NOLINT(google-explicit-constructor)
182
      const T& v, strings_internal::StringifySink&& sink = {})
183
0
      : piece_(strings_internal::ExtractStringification(sink, v)) {}
184
185
  Arg(Hex hex);  // NOLINT(google-explicit-constructor)
186
  Arg(Dec dec);  // NOLINT(google-explicit-constructor)
187
188
  // vector<bool>::reference and const_reference require special help to convert
189
  // to `Arg` because it requires two user defined conversions.
190
  template <
191
      typename T,
192
      std::enable_if_t<
193
          std::is_class<T>::value &&
194
              (std::is_same<T, std::vector<bool>::reference>::value ||
195
               std::is_same<T, std::vector<bool>::const_reference>::value),
196
          bool> = true>
197
  Arg(T value)  // NOLINT(google-explicit-constructor)
198
      : Arg(static_cast<bool>(value)) {}
199
200
  // `void*` values, with the exception of `char*`, are printed as
201
  // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
202
  Arg(  // NOLINT(google-explicit-constructor)
203
      const void* absl_nullable value);
204
205
  // Normal enums are already handled by the integer formatters.
206
  // This overload matches only scoped enums.
207
  template <typename T,
208
            typename = typename std::enable_if<
209
                std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
210
                !HasAbslStringify<T>::value>::type>
211
  Arg(T value)  // NOLINT(google-explicit-constructor)
212
      : Arg(static_cast<typename std::underlying_type<T>::type>(value)) {}
213
214
  Arg(const Arg&) = delete;
215
  Arg& operator=(const Arg&) = delete;
216
217
0
  absl::string_view piece() const { return piece_; }
218
219
 private:
220
  absl::string_view piece_;
221
  char scratch_[numbers_internal::kFastToBufferSize];
222
};
223
224
// Internal helper function. Don't call this from outside this implementation.
225
// This interface may change without notice.
226
void SubstituteAndAppendArray(std::string* absl_nonnull output,
227
                              absl::string_view format,
228
                              const absl::string_view* absl_nullable args_array,
229
                              size_t num_args);
230
231
#if defined(ABSL_BAD_CALL_IF)
232
0
constexpr int CalculateOneBit(const char* absl_nonnull format) {
233
0
  // Returns:
234
0
  // * 2^N for '$N' when N is in [0-9]
235
0
  // * 0 for correct '$' escaping: '$$'.
236
0
  // * -1 otherwise.
237
0
  return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1)
238
0
                                          : (1 << (*format - '0'));
239
0
}
240
241
0
constexpr const char* absl_nonnull SkipNumber(const char* absl_nonnull format) {
242
0
  return !*format ? format : (format + 1);
243
0
}
244
245
0
constexpr int PlaceholderBitmask(const char* absl_nonnull format) {
246
0
  return !*format
247
0
             ? 0
248
0
             : *format != '$' ? PlaceholderBitmask(format + 1)
249
0
                              : (CalculateOneBit(format + 1) |
250
0
                                 PlaceholderBitmask(SkipNumber(format + 1)));
251
0
}
252
#endif  // ABSL_BAD_CALL_IF
253
254
}  // namespace substitute_internal
255
256
//
257
// PUBLIC API
258
//
259
260
// SubstituteAndAppend()
261
//
262
// Substitutes variables into a given format string and appends to a given
263
// output string. See file comments above for usage.
264
//
265
// The declarations of `SubstituteAndAppend()` below consist of overloads
266
// for passing 0 to 10 arguments, respectively.
267
//
268
// NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic
269
// templates to allow a variable number of arguments.
270
//
271
// Example:
272
//  template <typename... Args>
273
//  void VarMsg(std::string* boilerplate, absl::string_view format,
274
//      const Args&... args) {
275
//    absl::SubstituteAndAppend(boilerplate, format, args...);
276
//  }
277
//
278
inline void SubstituteAndAppend(std::string* absl_nonnull output,
279
0
                                absl::string_view format) {
280
0
  substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
281
0
}
282
283
inline void SubstituteAndAppend(std::string* absl_nonnull output,
284
                                absl::string_view format,
285
0
                                const substitute_internal::Arg& a0) {
286
0
  const absl::string_view args[] = {a0.piece()};
287
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
288
0
                                                ABSL_ARRAYSIZE(args));
289
0
}
290
291
inline void SubstituteAndAppend(std::string* absl_nonnull output,
292
                                absl::string_view format,
293
                                const substitute_internal::Arg& a0,
294
0
                                const substitute_internal::Arg& a1) {
295
0
  const absl::string_view args[] = {a0.piece(), a1.piece()};
296
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
297
0
                                                ABSL_ARRAYSIZE(args));
298
0
}
299
300
inline void SubstituteAndAppend(std::string* absl_nonnull output,
301
                                absl::string_view format,
302
                                const substitute_internal::Arg& a0,
303
                                const substitute_internal::Arg& a1,
304
0
                                const substitute_internal::Arg& a2) {
305
0
  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()};
306
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
307
0
                                                ABSL_ARRAYSIZE(args));
308
0
}
309
310
inline void SubstituteAndAppend(std::string* absl_nonnull output,
311
                                absl::string_view format,
312
                                const substitute_internal::Arg& a0,
313
                                const substitute_internal::Arg& a1,
314
                                const substitute_internal::Arg& a2,
315
0
                                const substitute_internal::Arg& a3) {
316
0
  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
317
0
                                    a3.piece()};
318
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
319
0
                                                ABSL_ARRAYSIZE(args));
320
0
}
321
322
inline void SubstituteAndAppend(std::string* absl_nonnull output,
323
                                absl::string_view format,
324
                                const substitute_internal::Arg& a0,
325
                                const substitute_internal::Arg& a1,
326
                                const substitute_internal::Arg& a2,
327
                                const substitute_internal::Arg& a3,
328
0
                                const substitute_internal::Arg& a4) {
329
0
  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
330
0
                                    a3.piece(), a4.piece()};
331
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
332
0
                                                ABSL_ARRAYSIZE(args));
333
0
}
334
335
inline void SubstituteAndAppend(
336
    std::string* absl_nonnull output, absl::string_view format,
337
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
338
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
339
0
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5) {
340
0
  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
341
0
                                    a3.piece(), a4.piece(), a5.piece()};
342
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
343
0
                                                ABSL_ARRAYSIZE(args));
344
0
}
345
346
inline void SubstituteAndAppend(
347
    std::string* absl_nonnull 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
0
    const substitute_internal::Arg& a6) {
352
0
  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
353
0
                                    a3.piece(), a4.piece(), a5.piece(),
354
0
                                    a6.piece()};
355
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
356
0
                                                ABSL_ARRAYSIZE(args));
357
0
}
358
359
inline void SubstituteAndAppend(
360
    std::string* absl_nonnull output, absl::string_view format,
361
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
362
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
363
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
364
0
    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) {
365
0
  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
366
0
                                    a3.piece(), a4.piece(), a5.piece(),
367
0
                                    a6.piece(), a7.piece()};
368
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
369
0
                                                ABSL_ARRAYSIZE(args));
370
0
}
371
372
inline void SubstituteAndAppend(
373
    std::string* absl_nonnull output, absl::string_view format,
374
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
375
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
376
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
377
    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
378
0
    const substitute_internal::Arg& a8) {
379
0
  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
380
0
                                    a3.piece(), a4.piece(), a5.piece(),
381
0
                                    a6.piece(), a7.piece(), a8.piece()};
382
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
383
0
                                                ABSL_ARRAYSIZE(args));
384
0
}
385
386
inline void SubstituteAndAppend(
387
    std::string* absl_nonnull output, absl::string_view format,
388
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
389
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
390
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
391
    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
392
0
    const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) {
393
0
  const absl::string_view args[] = {
394
0
      a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(),
395
0
      a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()};
396
0
  substitute_internal::SubstituteAndAppendArray(output, format, args,
397
0
                                                ABSL_ARRAYSIZE(args));
398
0
}
399
400
#if defined(ABSL_BAD_CALL_IF)
401
// This body of functions catches cases where the number of placeholders
402
// doesn't match the number of data arguments.
403
void SubstituteAndAppend(std::string* absl_nonnull output,
404
                         const char* absl_nonnull format)
405
    ABSL_BAD_CALL_IF(
406
        substitute_internal::PlaceholderBitmask(format) != 0,
407
        "There were no substitution arguments "
408
        "but this format string either has a $[0-9] in it or contains "
409
        "an unescaped $ character (use $$ instead)");
410
411
void SubstituteAndAppend(std::string* absl_nonnull output,
412
                         const char* absl_nonnull format,
413
                         const substitute_internal::Arg& a0)
414
    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
415
                     "There was 1 substitution argument given, but "
416
                     "this format string is missing its $0, contains "
417
                     "one of $1-$9, or contains an unescaped $ character (use "
418
                     "$$ instead)");
419
420
void SubstituteAndAppend(std::string* absl_nonnull output,
421
                         const char* absl_nonnull format,
422
                         const substitute_internal::Arg& a0,
423
                         const substitute_internal::Arg& a1)
424
    ABSL_BAD_CALL_IF(
425
        substitute_internal::PlaceholderBitmask(format) != 3,
426
        "There were 2 substitution arguments given, but this format string is "
427
        "missing its $0/$1, contains one of $2-$9, or contains an "
428
        "unescaped $ character (use $$ instead)");
429
430
void SubstituteAndAppend(std::string* absl_nonnull output,
431
                         const char* absl_nonnull format,
432
                         const substitute_internal::Arg& a0,
433
                         const substitute_internal::Arg& a1,
434
                         const substitute_internal::Arg& a2)
435
    ABSL_BAD_CALL_IF(
436
        substitute_internal::PlaceholderBitmask(format) != 7,
437
        "There were 3 substitution arguments given, but "
438
        "this format string is missing its $0/$1/$2, contains one of "
439
        "$3-$9, or contains an unescaped $ character (use $$ instead)");
440
441
void SubstituteAndAppend(std::string* absl_nonnull output,
442
                         const char* absl_nonnull format,
443
                         const substitute_internal::Arg& a0,
444
                         const substitute_internal::Arg& a1,
445
                         const substitute_internal::Arg& a2,
446
                         const substitute_internal::Arg& a3)
447
    ABSL_BAD_CALL_IF(
448
        substitute_internal::PlaceholderBitmask(format) != 15,
449
        "There were 4 substitution arguments given, but "
450
        "this format string is missing its $0-$3, contains one of "
451
        "$4-$9, or contains an unescaped $ character (use $$ instead)");
452
453
void SubstituteAndAppend(std::string* absl_nonnull output,
454
                         const char* absl_nonnull format,
455
                         const substitute_internal::Arg& a0,
456
                         const substitute_internal::Arg& a1,
457
                         const substitute_internal::Arg& a2,
458
                         const substitute_internal::Arg& a3,
459
                         const substitute_internal::Arg& a4)
460
    ABSL_BAD_CALL_IF(
461
        substitute_internal::PlaceholderBitmask(format) != 31,
462
        "There were 5 substitution arguments given, but "
463
        "this format string is missing its $0-$4, contains one of "
464
        "$5-$9, or contains an unescaped $ character (use $$ instead)");
465
466
void SubstituteAndAppend(
467
    std::string* absl_nonnull output, const char* absl_nonnull format,
468
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
469
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
470
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5)
471
    ABSL_BAD_CALL_IF(
472
        substitute_internal::PlaceholderBitmask(format) != 63,
473
        "There were 6 substitution arguments given, but "
474
        "this format string is missing its $0-$5, contains one of "
475
        "$6-$9, or contains an unescaped $ character (use $$ instead)");
476
477
void SubstituteAndAppend(
478
    std::string* absl_nonnull output, const char* absl_nonnull format,
479
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
480
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
481
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
482
    const substitute_internal::Arg& a6)
483
    ABSL_BAD_CALL_IF(
484
        substitute_internal::PlaceholderBitmask(format) != 127,
485
        "There were 7 substitution arguments given, but "
486
        "this format string is missing its $0-$6, contains one of "
487
        "$7-$9, or contains an unescaped $ character (use $$ instead)");
488
489
void SubstituteAndAppend(
490
    std::string* absl_nonnull output, const char* absl_nonnull format,
491
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
492
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
493
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
494
    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7)
495
    ABSL_BAD_CALL_IF(
496
        substitute_internal::PlaceholderBitmask(format) != 255,
497
        "There were 8 substitution arguments given, but "
498
        "this format string is missing its $0-$7, contains one of "
499
        "$8-$9, or contains an unescaped $ character (use $$ instead)");
500
501
void SubstituteAndAppend(
502
    std::string* absl_nonnull output, const char* absl_nonnull format,
503
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
504
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
505
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
506
    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
507
    const substitute_internal::Arg& a8)
508
    ABSL_BAD_CALL_IF(
509
        substitute_internal::PlaceholderBitmask(format) != 511,
510
        "There were 9 substitution arguments given, but "
511
        "this format string is missing its $0-$8, contains a $9, or "
512
        "contains an unescaped $ character (use $$ instead)");
513
514
void SubstituteAndAppend(
515
    std::string* absl_nonnull output, const char* absl_nonnull format,
516
    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
517
    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
518
    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
519
    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
520
    const substitute_internal::Arg& a8, const substitute_internal::Arg& a9)
521
    ABSL_BAD_CALL_IF(
522
        substitute_internal::PlaceholderBitmask(format) != 1023,
523
        "There were 10 substitution arguments given, but this "
524
        "format string either doesn't contain all of $0 through $9 or "
525
        "contains an unescaped $ character (use $$ instead)");
526
#endif  // ABSL_BAD_CALL_IF
527
528
// Substitute()
529
//
530
// Substitutes variables into a given format string. See file comments above
531
// for usage.
532
//
533
// The declarations of `Substitute()` below consist of overloads for passing 0
534
// to 10 arguments, respectively.
535
//
536
// NOTE: A zero-argument `Substitute()` may be used within variadic templates to
537
// allow a variable number of arguments.
538
//
539
// Example:
540
//  template <typename... Args>
541
//  void VarMsg(absl::string_view format, const Args&... args) {
542
//    std::string s = absl::Substitute(format, args...);
543
544
0
[[nodiscard]] inline std::string Substitute(absl::string_view format) {
545
0
  std::string result;
546
0
  SubstituteAndAppend(&result, format);
547
0
  return result;
548
0
}
549
550
[[nodiscard]] inline std::string Substitute(
551
0
    absl::string_view format, const substitute_internal::Arg& a0) {
552
0
  std::string result;
553
0
  SubstituteAndAppend(&result, format, a0);
554
0
  return result;
555
0
}
556
557
[[nodiscard]] inline std::string Substitute(
558
    absl::string_view format, const substitute_internal::Arg& a0,
559
0
    const substitute_internal::Arg& a1) {
560
0
  std::string result;
561
0
  SubstituteAndAppend(&result, format, a0, a1);
562
0
  return result;
563
0
}
564
565
[[nodiscard]] inline std::string Substitute(
566
    absl::string_view format, const substitute_internal::Arg& a0,
567
0
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) {
568
0
  std::string result;
569
0
  SubstituteAndAppend(&result, format, a0, a1, a2);
570
0
  return result;
571
0
}
572
573
[[nodiscard]] inline std::string Substitute(
574
    absl::string_view format, const substitute_internal::Arg& a0,
575
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
576
0
    const substitute_internal::Arg& a3) {
577
0
  std::string result;
578
0
  SubstituteAndAppend(&result, format, a0, a1, a2, a3);
579
0
  return result;
580
0
}
581
582
[[nodiscard]] inline std::string Substitute(
583
    absl::string_view format, const substitute_internal::Arg& a0,
584
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
585
0
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
586
0
  std::string result;
587
0
  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4);
588
0
  return result;
589
0
}
590
591
[[nodiscard]] inline std::string Substitute(
592
    absl::string_view format, const substitute_internal::Arg& a0,
593
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
594
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
595
0
    const substitute_internal::Arg& a5) {
596
0
  std::string result;
597
0
  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5);
598
0
  return result;
599
0
}
600
601
[[nodiscard]] inline std::string Substitute(
602
    absl::string_view format, const substitute_internal::Arg& a0,
603
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
604
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
605
0
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) {
606
0
  std::string result;
607
0
  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6);
608
0
  return result;
609
0
}
610
611
[[nodiscard]] inline std::string Substitute(
612
    absl::string_view format, const substitute_internal::Arg& a0,
613
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
614
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
615
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
616
0
    const substitute_internal::Arg& a7) {
617
0
  std::string result;
618
0
  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7);
619
0
  return result;
620
0
}
621
622
[[nodiscard]] inline std::string Substitute(
623
    absl::string_view format, const substitute_internal::Arg& a0,
624
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
625
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
626
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
627
0
    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) {
628
0
  std::string result;
629
0
  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8);
630
0
  return result;
631
0
}
632
633
[[nodiscard]] inline std::string Substitute(
634
    absl::string_view format, const substitute_internal::Arg& a0,
635
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
636
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
637
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
638
    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
639
0
    const substitute_internal::Arg& a9) {
640
0
  std::string result;
641
0
  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
642
0
  return result;
643
0
}
644
645
#if defined(ABSL_BAD_CALL_IF)
646
// This body of functions catches cases where the number of placeholders
647
// doesn't match the number of data arguments.
648
std::string Substitute(const char* absl_nonnull format)
649
    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
650
                     "There were no substitution arguments "
651
                     "but this format string either has a $[0-9] in it or "
652
                     "contains an unescaped $ character (use $$ instead)");
653
654
std::string Substitute(const char* absl_nonnull format,
655
                       const substitute_internal::Arg& a0)
656
    ABSL_BAD_CALL_IF(
657
        substitute_internal::PlaceholderBitmask(format) != 1,
658
        "There was 1 substitution argument given, but "
659
        "this format string is missing its $0, contains one of $1-$9, "
660
        "or contains an unescaped $ character (use $$ instead)");
661
662
std::string Substitute(const char* absl_nonnull format,
663
                       const substitute_internal::Arg& a0,
664
                       const substitute_internal::Arg& a1)
665
    ABSL_BAD_CALL_IF(
666
        substitute_internal::PlaceholderBitmask(format) != 3,
667
        "There were 2 substitution arguments given, but "
668
        "this format string is missing its $0/$1, contains one of "
669
        "$2-$9, or contains an unescaped $ character (use $$ instead)");
670
671
std::string Substitute(const char* absl_nonnull format,
672
                       const substitute_internal::Arg& a0,
673
                       const substitute_internal::Arg& a1,
674
                       const substitute_internal::Arg& a2)
675
    ABSL_BAD_CALL_IF(
676
        substitute_internal::PlaceholderBitmask(format) != 7,
677
        "There were 3 substitution arguments given, but "
678
        "this format string is missing its $0/$1/$2, contains one of "
679
        "$3-$9, or contains an unescaped $ character (use $$ instead)");
680
681
std::string Substitute(const char* absl_nonnull format,
682
                       const substitute_internal::Arg& a0,
683
                       const substitute_internal::Arg& a1,
684
                       const substitute_internal::Arg& a2,
685
                       const substitute_internal::Arg& a3)
686
    ABSL_BAD_CALL_IF(
687
        substitute_internal::PlaceholderBitmask(format) != 15,
688
        "There were 4 substitution arguments given, but "
689
        "this format string is missing its $0-$3, contains one of "
690
        "$4-$9, or contains an unescaped $ character (use $$ instead)");
691
692
std::string Substitute(const char* absl_nonnull format,
693
                       const substitute_internal::Arg& a0,
694
                       const substitute_internal::Arg& a1,
695
                       const substitute_internal::Arg& a2,
696
                       const substitute_internal::Arg& a3,
697
                       const substitute_internal::Arg& a4)
698
    ABSL_BAD_CALL_IF(
699
        substitute_internal::PlaceholderBitmask(format) != 31,
700
        "There were 5 substitution arguments given, but "
701
        "this format string is missing its $0-$4, contains one of "
702
        "$5-$9, or contains an unescaped $ character (use $$ instead)");
703
704
std::string Substitute(const char* absl_nonnull format,
705
                       const substitute_internal::Arg& a0,
706
                       const substitute_internal::Arg& a1,
707
                       const substitute_internal::Arg& a2,
708
                       const substitute_internal::Arg& a3,
709
                       const substitute_internal::Arg& a4,
710
                       const substitute_internal::Arg& a5)
711
    ABSL_BAD_CALL_IF(
712
        substitute_internal::PlaceholderBitmask(format) != 63,
713
        "There were 6 substitution arguments given, but "
714
        "this format string is missing its $0-$5, contains one of "
715
        "$6-$9, or contains an unescaped $ character (use $$ instead)");
716
717
std::string Substitute(
718
    const char* absl_nonnull format, const substitute_internal::Arg& a0,
719
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
720
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
721
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
722
    ABSL_BAD_CALL_IF(
723
        substitute_internal::PlaceholderBitmask(format) != 127,
724
        "There were 7 substitution arguments given, but "
725
        "this format string is missing its $0-$6, contains one of "
726
        "$7-$9, or contains an unescaped $ character (use $$ instead)");
727
728
std::string Substitute(
729
    const char* absl_nonnull format, const substitute_internal::Arg& a0,
730
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
731
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
732
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
733
    const substitute_internal::Arg& a7)
734
    ABSL_BAD_CALL_IF(
735
        substitute_internal::PlaceholderBitmask(format) != 255,
736
        "There were 8 substitution arguments given, but "
737
        "this format string is missing its $0-$7, contains one of "
738
        "$8-$9, or contains an unescaped $ character (use $$ instead)");
739
740
std::string Substitute(
741
    const char* absl_nonnull format, const substitute_internal::Arg& a0,
742
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
743
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
744
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
745
    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
746
    ABSL_BAD_CALL_IF(
747
        substitute_internal::PlaceholderBitmask(format) != 511,
748
        "There were 9 substitution arguments given, but "
749
        "this format string is missing its $0-$8, contains a $9, or "
750
        "contains an unescaped $ character (use $$ instead)");
751
752
std::string Substitute(
753
    const char* absl_nonnull format, const substitute_internal::Arg& a0,
754
    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
755
    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
756
    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
757
    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
758
    const substitute_internal::Arg& a9)
759
    ABSL_BAD_CALL_IF(
760
        substitute_internal::PlaceholderBitmask(format) != 1023,
761
        "There were 10 substitution arguments given, but this "
762
        "format string either doesn't contain all of $0 through $9 or "
763
        "contains an unescaped $ character (use $$ instead)");
764
#endif  // ABSL_BAD_CALL_IF
765
766
ABSL_NAMESPACE_END
767
}  // namespace absl
768
769
#endif  // ABSL_STRINGS_SUBSTITUTE_H_