tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

substitute.h (35718B)


      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(absl::Nullable<const char*> value)  // NOLINT(google-explicit-constructor)
    110      : 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      : piece_(value) {}
    116  Arg(absl::string_view value)  // NOLINT(google-explicit-constructor)
    117      : 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      : piece_(scratch_, 1) {
    128    scratch_[0] = value;
    129  }
    130  Arg(short value)  // NOLINT(*)
    131      : piece_(scratch_,
    132               static_cast<size_t>(
    133                   numbers_internal::FastIntToBuffer(value, scratch_) -
    134                   scratch_)) {}
    135  Arg(unsigned short value)  // NOLINT(*)
    136      : piece_(scratch_,
    137               static_cast<size_t>(
    138                   numbers_internal::FastIntToBuffer(value, scratch_) -
    139                   scratch_)) {}
    140  Arg(int value)  // NOLINT(google-explicit-constructor)
    141      : piece_(scratch_,
    142               static_cast<size_t>(
    143                   numbers_internal::FastIntToBuffer(value, scratch_) -
    144                   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                   scratch_)) {}
    150  Arg(long value)  // NOLINT(*)
    151      : piece_(scratch_,
    152               static_cast<size_t>(
    153                   numbers_internal::FastIntToBuffer(value, scratch_) -
    154                   scratch_)) {}
    155  Arg(unsigned long value)  // NOLINT(*)
    156      : piece_(scratch_,
    157               static_cast<size_t>(
    158                   numbers_internal::FastIntToBuffer(value, scratch_) -
    159                   scratch_)) {}
    160  Arg(long long value)  // NOLINT(*)
    161      : piece_(scratch_,
    162               static_cast<size_t>(
    163                   numbers_internal::FastIntToBuffer(value, scratch_) -
    164                   scratch_)) {}
    165  Arg(unsigned long long value)  // NOLINT(*)
    166      : piece_(scratch_,
    167               static_cast<size_t>(
    168                   numbers_internal::FastIntToBuffer(value, scratch_) -
    169                   scratch_)) {}
    170  Arg(float value)  // NOLINT(google-explicit-constructor)
    171      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
    172  }
    173  Arg(double value)  // NOLINT(google-explicit-constructor)
    174      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
    175  }
    176  Arg(bool value)  // NOLINT(google-explicit-constructor)
    177      : 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      : 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 <typename T,
    191            absl::enable_if_t<
    192                std::is_class<T>::value &&
    193                (std::is_same<T, std::vector<bool>::reference>::value ||
    194                 std::is_same<T, std::vector<bool>::const_reference>::value)>* =
    195                nullptr>
    196  Arg(T value)  // NOLINT(google-explicit-constructor)
    197      : Arg(static_cast<bool>(value)) {}
    198 
    199  // `void*` values, with the exception of `char*`, are printed as
    200  // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
    201  Arg(  // NOLINT(google-explicit-constructor)
    202      absl::Nullable<const void*> value);
    203 
    204  // Normal enums are already handled by the integer formatters.
    205  // This overload matches only scoped enums.
    206  template <typename T,
    207            typename = typename std::enable_if<
    208                std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
    209                !HasAbslStringify<T>::value>::type>
    210  Arg(T value)  // NOLINT(google-explicit-constructor)
    211      : Arg(static_cast<typename std::underlying_type<T>::type>(value)) {}
    212 
    213  Arg(const Arg&) = delete;
    214  Arg& operator=(const Arg&) = delete;
    215 
    216  absl::string_view piece() const { return piece_; }
    217 
    218 private:
    219  absl::string_view piece_;
    220  char scratch_[numbers_internal::kFastToBufferSize];
    221 };
    222 
    223 // Internal helper function. Don't call this from outside this implementation.
    224 // This interface may change without notice.
    225 void SubstituteAndAppendArray(
    226    absl::Nonnull<std::string*> output, absl::string_view format,
    227    absl::Nullable<const absl::string_view*> args_array, size_t num_args);
    228 
    229 #if defined(ABSL_BAD_CALL_IF)
    230 constexpr int CalculateOneBit(absl::Nonnull<const char*> format) {
    231  // Returns:
    232  // * 2^N for '$N' when N is in [0-9]
    233  // * 0 for correct '$' escaping: '$$'.
    234  // * -1 otherwise.
    235  return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1)
    236                                          : (1 << (*format - '0'));
    237 }
    238 
    239 constexpr const char* SkipNumber(absl::Nonnull<const char*> format) {
    240  return !*format ? format : (format + 1);
    241 }
    242 
    243 constexpr int PlaceholderBitmask(absl::Nonnull<const char*> format) {
    244  return !*format
    245             ? 0
    246             : *format != '$' ? PlaceholderBitmask(format + 1)
    247                              : (CalculateOneBit(format + 1) |
    248                                 PlaceholderBitmask(SkipNumber(format + 1)));
    249 }
    250 #endif  // ABSL_BAD_CALL_IF
    251 
    252 }  // namespace substitute_internal
    253 
    254 //
    255 // PUBLIC API
    256 //
    257 
    258 // SubstituteAndAppend()
    259 //
    260 // Substitutes variables into a given format string and appends to a given
    261 // output string. See file comments above for usage.
    262 //
    263 // The declarations of `SubstituteAndAppend()` below consist of overloads
    264 // for passing 0 to 10 arguments, respectively.
    265 //
    266 // NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic
    267 // templates to allow a variable number of arguments.
    268 //
    269 // Example:
    270 //  template <typename... Args>
    271 //  void VarMsg(std::string* boilerplate, absl::string_view format,
    272 //      const Args&... args) {
    273 //    absl::SubstituteAndAppend(boilerplate, format, args...);
    274 //  }
    275 //
    276 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    277                                absl::string_view format) {
    278  substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
    279 }
    280 
    281 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    282                                absl::string_view format,
    283                                const substitute_internal::Arg& a0) {
    284  const absl::string_view args[] = {a0.piece()};
    285  substitute_internal::SubstituteAndAppendArray(output, format, args,
    286                                                ABSL_ARRAYSIZE(args));
    287 }
    288 
    289 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    290                                absl::string_view format,
    291                                const substitute_internal::Arg& a0,
    292                                const substitute_internal::Arg& a1) {
    293  const absl::string_view args[] = {a0.piece(), a1.piece()};
    294  substitute_internal::SubstituteAndAppendArray(output, format, args,
    295                                                ABSL_ARRAYSIZE(args));
    296 }
    297 
    298 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    299                                absl::string_view format,
    300                                const substitute_internal::Arg& a0,
    301                                const substitute_internal::Arg& a1,
    302                                const substitute_internal::Arg& a2) {
    303  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()};
    304  substitute_internal::SubstituteAndAppendArray(output, format, args,
    305                                                ABSL_ARRAYSIZE(args));
    306 }
    307 
    308 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    309                                absl::string_view format,
    310                                const substitute_internal::Arg& a0,
    311                                const substitute_internal::Arg& a1,
    312                                const substitute_internal::Arg& a2,
    313                                const substitute_internal::Arg& a3) {
    314  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
    315                                    a3.piece()};
    316  substitute_internal::SubstituteAndAppendArray(output, format, args,
    317                                                ABSL_ARRAYSIZE(args));
    318 }
    319 
    320 inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    321                                absl::string_view format,
    322                                const substitute_internal::Arg& a0,
    323                                const substitute_internal::Arg& a1,
    324                                const substitute_internal::Arg& a2,
    325                                const substitute_internal::Arg& a3,
    326                                const substitute_internal::Arg& a4) {
    327  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
    328                                    a3.piece(), a4.piece()};
    329  substitute_internal::SubstituteAndAppendArray(output, format, args,
    330                                                ABSL_ARRAYSIZE(args));
    331 }
    332 
    333 inline void SubstituteAndAppend(
    334    absl::Nonnull<std::string*> output, absl::string_view format,
    335    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    336    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    337    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5) {
    338  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
    339                                    a3.piece(), a4.piece(), a5.piece()};
    340  substitute_internal::SubstituteAndAppendArray(output, format, args,
    341                                                ABSL_ARRAYSIZE(args));
    342 }
    343 
    344 inline void SubstituteAndAppend(
    345    absl::Nonnull<std::string*> output, absl::string_view format,
    346    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    347    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    348    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    349    const substitute_internal::Arg& a6) {
    350  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
    351                                    a3.piece(), a4.piece(), a5.piece(),
    352                                    a6.piece()};
    353  substitute_internal::SubstituteAndAppendArray(output, format, args,
    354                                                ABSL_ARRAYSIZE(args));
    355 }
    356 
    357 inline void SubstituteAndAppend(
    358    absl::Nonnull<std::string*> output, absl::string_view format,
    359    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    360    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    361    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    362    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) {
    363  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
    364                                    a3.piece(), a4.piece(), a5.piece(),
    365                                    a6.piece(), a7.piece()};
    366  substitute_internal::SubstituteAndAppendArray(output, format, args,
    367                                                ABSL_ARRAYSIZE(args));
    368 }
    369 
    370 inline void SubstituteAndAppend(
    371    absl::Nonnull<std::string*> output, absl::string_view format,
    372    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    373    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    374    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    375    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
    376    const substitute_internal::Arg& a8) {
    377  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
    378                                    a3.piece(), a4.piece(), a5.piece(),
    379                                    a6.piece(), a7.piece(), a8.piece()};
    380  substitute_internal::SubstituteAndAppendArray(output, format, args,
    381                                                ABSL_ARRAYSIZE(args));
    382 }
    383 
    384 inline void SubstituteAndAppend(
    385    absl::Nonnull<std::string*> output, absl::string_view format,
    386    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    387    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    388    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    389    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
    390    const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) {
    391  const absl::string_view args[] = {
    392      a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(),
    393      a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()};
    394  substitute_internal::SubstituteAndAppendArray(output, format, args,
    395                                                ABSL_ARRAYSIZE(args));
    396 }
    397 
    398 #if defined(ABSL_BAD_CALL_IF)
    399 // This body of functions catches cases where the number of placeholders
    400 // doesn't match the number of data arguments.
    401 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    402                         absl::Nonnull<const char*> format)
    403    ABSL_BAD_CALL_IF(
    404        substitute_internal::PlaceholderBitmask(format) != 0,
    405        "There were no substitution arguments "
    406        "but this format string either has a $[0-9] in it or contains "
    407        "an unescaped $ character (use $$ instead)");
    408 
    409 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    410                         absl::Nonnull<const char*> format,
    411                         const substitute_internal::Arg& a0)
    412    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
    413                     "There was 1 substitution argument given, but "
    414                     "this format string is missing its $0, contains "
    415                     "one of $1-$9, or contains an unescaped $ character (use "
    416                     "$$ instead)");
    417 
    418 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    419                         absl::Nonnull<const char*> format,
    420                         const substitute_internal::Arg& a0,
    421                         const substitute_internal::Arg& a1)
    422    ABSL_BAD_CALL_IF(
    423        substitute_internal::PlaceholderBitmask(format) != 3,
    424        "There were 2 substitution arguments given, but this format string is "
    425        "missing its $0/$1, contains one of $2-$9, or contains an "
    426        "unescaped $ character (use $$ instead)");
    427 
    428 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    429                         absl::Nonnull<const char*> format,
    430                         const substitute_internal::Arg& a0,
    431                         const substitute_internal::Arg& a1,
    432                         const substitute_internal::Arg& a2)
    433    ABSL_BAD_CALL_IF(
    434        substitute_internal::PlaceholderBitmask(format) != 7,
    435        "There were 3 substitution arguments given, but "
    436        "this format string is missing its $0/$1/$2, contains one of "
    437        "$3-$9, or contains an unescaped $ character (use $$ instead)");
    438 
    439 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    440                         absl::Nonnull<const char*> format,
    441                         const substitute_internal::Arg& a0,
    442                         const substitute_internal::Arg& a1,
    443                         const substitute_internal::Arg& a2,
    444                         const substitute_internal::Arg& a3)
    445    ABSL_BAD_CALL_IF(
    446        substitute_internal::PlaceholderBitmask(format) != 15,
    447        "There were 4 substitution arguments given, but "
    448        "this format string is missing its $0-$3, contains one of "
    449        "$4-$9, or contains an unescaped $ character (use $$ instead)");
    450 
    451 void SubstituteAndAppend(absl::Nonnull<std::string*> output,
    452                         absl::Nonnull<const char*> format,
    453                         const substitute_internal::Arg& a0,
    454                         const substitute_internal::Arg& a1,
    455                         const substitute_internal::Arg& a2,
    456                         const substitute_internal::Arg& a3,
    457                         const substitute_internal::Arg& a4)
    458    ABSL_BAD_CALL_IF(
    459        substitute_internal::PlaceholderBitmask(format) != 31,
    460        "There were 5 substitution arguments given, but "
    461        "this format string is missing its $0-$4, contains one of "
    462        "$5-$9, or contains an unescaped $ character (use $$ instead)");
    463 
    464 void SubstituteAndAppend(
    465    absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
    466    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    467    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    468    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5)
    469    ABSL_BAD_CALL_IF(
    470        substitute_internal::PlaceholderBitmask(format) != 63,
    471        "There were 6 substitution arguments given, but "
    472        "this format string is missing its $0-$5, contains one of "
    473        "$6-$9, or contains an unescaped $ character (use $$ instead)");
    474 
    475 void SubstituteAndAppend(
    476    absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
    477    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    478    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    479    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    480    const substitute_internal::Arg& a6)
    481    ABSL_BAD_CALL_IF(
    482        substitute_internal::PlaceholderBitmask(format) != 127,
    483        "There were 7 substitution arguments given, but "
    484        "this format string is missing its $0-$6, contains one of "
    485        "$7-$9, or contains an unescaped $ character (use $$ instead)");
    486 
    487 void SubstituteAndAppend(
    488    absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
    489    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    490    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    491    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    492    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7)
    493    ABSL_BAD_CALL_IF(
    494        substitute_internal::PlaceholderBitmask(format) != 255,
    495        "There were 8 substitution arguments given, but "
    496        "this format string is missing its $0-$7, contains one of "
    497        "$8-$9, or contains an unescaped $ character (use $$ instead)");
    498 
    499 void SubstituteAndAppend(
    500    absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
    501    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    502    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    503    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    504    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
    505    const substitute_internal::Arg& a8)
    506    ABSL_BAD_CALL_IF(
    507        substitute_internal::PlaceholderBitmask(format) != 511,
    508        "There were 9 substitution arguments given, but "
    509        "this format string is missing its $0-$8, contains a $9, or "
    510        "contains an unescaped $ character (use $$ instead)");
    511 
    512 void SubstituteAndAppend(
    513    absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
    514    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
    515    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
    516    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
    517    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
    518    const substitute_internal::Arg& a8, const substitute_internal::Arg& a9)
    519    ABSL_BAD_CALL_IF(
    520        substitute_internal::PlaceholderBitmask(format) != 1023,
    521        "There were 10 substitution arguments given, but this "
    522        "format string either doesn't contain all of $0 through $9 or "
    523        "contains an unescaped $ character (use $$ instead)");
    524 #endif  // ABSL_BAD_CALL_IF
    525 
    526 // Substitute()
    527 //
    528 // Substitutes variables into a given format string. See file comments above
    529 // for usage.
    530 //
    531 // The declarations of `Substitute()` below consist of overloads for passing 0
    532 // to 10 arguments, respectively.
    533 //
    534 // NOTE: A zero-argument `Substitute()` may be used within variadic templates to
    535 // allow a variable number of arguments.
    536 //
    537 // Example:
    538 //  template <typename... Args>
    539 //  void VarMsg(absl::string_view format, const Args&... args) {
    540 //    std::string s = absl::Substitute(format, args...);
    541 
    542 [[nodiscard]] inline std::string Substitute(absl::string_view format) {
    543  std::string result;
    544  SubstituteAndAppend(&result, format);
    545  return result;
    546 }
    547 
    548 [[nodiscard]] inline std::string Substitute(
    549    absl::string_view format, const substitute_internal::Arg& a0) {
    550  std::string result;
    551  SubstituteAndAppend(&result, format, a0);
    552  return result;
    553 }
    554 
    555 [[nodiscard]] inline std::string Substitute(
    556    absl::string_view format, const substitute_internal::Arg& a0,
    557    const substitute_internal::Arg& a1) {
    558  std::string result;
    559  SubstituteAndAppend(&result, format, a0, a1);
    560  return result;
    561 }
    562 
    563 [[nodiscard]] 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  std::string result;
    567  SubstituteAndAppend(&result, format, a0, a1, a2);
    568  return result;
    569 }
    570 
    571 [[nodiscard]] inline std::string Substitute(
    572    absl::string_view format, const substitute_internal::Arg& a0,
    573    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    574    const substitute_internal::Arg& a3) {
    575  std::string result;
    576  SubstituteAndAppend(&result, format, a0, a1, a2, a3);
    577  return result;
    578 }
    579 
    580 [[nodiscard]] inline std::string Substitute(
    581    absl::string_view format, const substitute_internal::Arg& a0,
    582    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    583    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
    584  std::string result;
    585  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4);
    586  return result;
    587 }
    588 
    589 [[nodiscard]] inline std::string Substitute(
    590    absl::string_view format, const substitute_internal::Arg& a0,
    591    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    592    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    593    const substitute_internal::Arg& a5) {
    594  std::string result;
    595  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5);
    596  return result;
    597 }
    598 
    599 [[nodiscard]] inline std::string Substitute(
    600    absl::string_view format, const substitute_internal::Arg& a0,
    601    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    602    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    603    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) {
    604  std::string result;
    605  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6);
    606  return result;
    607 }
    608 
    609 [[nodiscard]] inline std::string Substitute(
    610    absl::string_view format, const substitute_internal::Arg& a0,
    611    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    612    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    613    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
    614    const substitute_internal::Arg& a7) {
    615  std::string result;
    616  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7);
    617  return result;
    618 }
    619 
    620 [[nodiscard]] inline std::string Substitute(
    621    absl::string_view format, const substitute_internal::Arg& a0,
    622    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    623    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    624    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
    625    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) {
    626  std::string result;
    627  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8);
    628  return result;
    629 }
    630 
    631 [[nodiscard]] inline std::string Substitute(
    632    absl::string_view format, const substitute_internal::Arg& a0,
    633    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    634    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    635    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
    636    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
    637    const substitute_internal::Arg& a9) {
    638  std::string result;
    639  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
    640  return result;
    641 }
    642 
    643 #if defined(ABSL_BAD_CALL_IF)
    644 // This body of functions catches cases where the number of placeholders
    645 // doesn't match the number of data arguments.
    646 std::string Substitute(absl::Nonnull<const char*> format)
    647    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
    648                     "There were no substitution arguments "
    649                     "but this format string either has a $[0-9] in it or "
    650                     "contains an unescaped $ character (use $$ instead)");
    651 
    652 std::string Substitute(absl::Nonnull<const char*> format,
    653                       const substitute_internal::Arg& a0)
    654    ABSL_BAD_CALL_IF(
    655        substitute_internal::PlaceholderBitmask(format) != 1,
    656        "There was 1 substitution argument given, but "
    657        "this format string is missing its $0, contains one of $1-$9, "
    658        "or contains an unescaped $ character (use $$ instead)");
    659 
    660 std::string Substitute(absl::Nonnull<const char*> format,
    661                       const substitute_internal::Arg& a0,
    662                       const substitute_internal::Arg& a1)
    663    ABSL_BAD_CALL_IF(
    664        substitute_internal::PlaceholderBitmask(format) != 3,
    665        "There were 2 substitution arguments given, but "
    666        "this format string is missing its $0/$1, contains one of "
    667        "$2-$9, or contains an unescaped $ character (use $$ instead)");
    668 
    669 std::string Substitute(absl::Nonnull<const char*> format,
    670                       const substitute_internal::Arg& a0,
    671                       const substitute_internal::Arg& a1,
    672                       const substitute_internal::Arg& a2)
    673    ABSL_BAD_CALL_IF(
    674        substitute_internal::PlaceholderBitmask(format) != 7,
    675        "There were 3 substitution arguments given, but "
    676        "this format string is missing its $0/$1/$2, contains one of "
    677        "$3-$9, or contains an unescaped $ character (use $$ instead)");
    678 
    679 std::string Substitute(absl::Nonnull<const char*> format,
    680                       const substitute_internal::Arg& a0,
    681                       const substitute_internal::Arg& a1,
    682                       const substitute_internal::Arg& a2,
    683                       const substitute_internal::Arg& a3)
    684    ABSL_BAD_CALL_IF(
    685        substitute_internal::PlaceholderBitmask(format) != 15,
    686        "There were 4 substitution arguments given, but "
    687        "this format string is missing its $0-$3, contains one of "
    688        "$4-$9, or contains an unescaped $ character (use $$ instead)");
    689 
    690 std::string Substitute(absl::Nonnull<const char*> format,
    691                       const substitute_internal::Arg& a0,
    692                       const substitute_internal::Arg& a1,
    693                       const substitute_internal::Arg& a2,
    694                       const substitute_internal::Arg& a3,
    695                       const substitute_internal::Arg& a4)
    696    ABSL_BAD_CALL_IF(
    697        substitute_internal::PlaceholderBitmask(format) != 31,
    698        "There were 5 substitution arguments given, but "
    699        "this format string is missing its $0-$4, contains one of "
    700        "$5-$9, or contains an unescaped $ character (use $$ instead)");
    701 
    702 std::string Substitute(absl::Nonnull<const char*> format,
    703                       const substitute_internal::Arg& a0,
    704                       const substitute_internal::Arg& a1,
    705                       const substitute_internal::Arg& a2,
    706                       const substitute_internal::Arg& a3,
    707                       const substitute_internal::Arg& a4,
    708                       const substitute_internal::Arg& a5)
    709    ABSL_BAD_CALL_IF(
    710        substitute_internal::PlaceholderBitmask(format) != 63,
    711        "There were 6 substitution arguments given, but "
    712        "this format string is missing its $0-$5, contains one of "
    713        "$6-$9, or contains an unescaped $ character (use $$ instead)");
    714 
    715 std::string Substitute(
    716    absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
    717    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    718    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    719    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
    720    ABSL_BAD_CALL_IF(
    721        substitute_internal::PlaceholderBitmask(format) != 127,
    722        "There were 7 substitution arguments given, but "
    723        "this format string is missing its $0-$6, contains one of "
    724        "$7-$9, or contains an unescaped $ character (use $$ instead)");
    725 
    726 std::string Substitute(
    727    absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
    728    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    729    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    730    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
    731    const substitute_internal::Arg& a7)
    732    ABSL_BAD_CALL_IF(
    733        substitute_internal::PlaceholderBitmask(format) != 255,
    734        "There were 8 substitution arguments given, but "
    735        "this format string is missing its $0-$7, contains one of "
    736        "$8-$9, or contains an unescaped $ character (use $$ instead)");
    737 
    738 std::string Substitute(
    739    absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
    740    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    741    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    742    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
    743    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
    744    ABSL_BAD_CALL_IF(
    745        substitute_internal::PlaceholderBitmask(format) != 511,
    746        "There were 9 substitution arguments given, but "
    747        "this format string is missing its $0-$8, contains a $9, or "
    748        "contains an unescaped $ character (use $$ instead)");
    749 
    750 std::string Substitute(
    751    absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
    752    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
    753    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
    754    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
    755    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
    756    const substitute_internal::Arg& a9)
    757    ABSL_BAD_CALL_IF(
    758        substitute_internal::PlaceholderBitmask(format) != 1023,
    759        "There were 10 substitution arguments given, but this "
    760        "format string either doesn't contain all of $0 through $9 or "
    761        "contains an unescaped $ character (use $$ instead)");
    762 #endif  // ABSL_BAD_CALL_IF
    763 
    764 ABSL_NAMESPACE_END
    765 }  // namespace absl
    766 
    767 #endif  // ABSL_STRINGS_SUBSTITUTE_H_