YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/gutil/strings/substitute.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2008 Google Inc.  All rights reserved.
2
//
3
// The following only applies to changes made to this file as part of YugaByte development.
4
//
5
// Portions Copyright (c) YugaByte, Inc.
6
//
7
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8
// in compliance with the License.  You may obtain a copy of the License at
9
//
10
// http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software distributed under the License
13
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14
// or implied.  See the License for the specific language governing permissions and limitations
15
// under the License.
16
//
17
18
#include <string.h>
19
20
#include <string>
21
22
#include "yb/gutil/strings/numbers.h"
23
#include "yb/gutil/strings/stringpiece.h"
24
25
using std::string;
26
27
28
29
#ifndef YB_GUTIL_STRINGS_SUBSTITUTE_H
30
#define YB_GUTIL_STRINGS_SUBSTITUTE_H
31
32
namespace strings {
33
34
// ----------------------------------------------------------------------
35
// strings::Substitute()
36
// strings::SubstituteAndAppend()
37
//   Kind of like StringPrintf, but different.
38
//
39
//   Example:
40
//     string GetMessage(string first_name, string last_name, int age) {
41
//       return strings::Substitute("My name is $0 $1 and I am $2 years old.",
42
//                                  first_name, last_name, age);
43
//     }
44
//
45
//   Differences from StringPrintf:
46
//   * The format string does not identify the types of arguments.
47
//     Instead, the magic of C++ deals with this for us.  See below
48
//     for a list of accepted types.
49
//   * Substitutions in the format string are identified by a '$'
50
//     followed by a digit.  So, you can use arguments out-of-order and
51
//     use the same argument multiple times.
52
//   * '$$' in the format string means output a literal '$' character.
53
//   * It's much faster than StringPrintf.
54
//
55
//   Supported types:
56
//   * GStringPiece (const char*, const string&) (NULL is equivalent to "")
57
//     * Note that this means you do not have to add .c_str() to all of
58
//       your strings.  In fact, you shouldn't; it will be slower.
59
//   * int32, int64, uint32, uint64
60
//   * float, double
61
//   * bool:  Printed as "true" or "false".
62
//   * pointer types other than char*: Printed as "0x<lower case hex string>",
63
//             except that NULL is printed as "NULL".
64
//
65
//   If not enough arguments are supplied, a LOG(DFATAL) will be issued and
66
//   the empty string will be returned. If too many arguments are supplied,
67
//   just the first ones will be used (no warning).
68
//
69
//   SubstituteAndAppend() is like Substitute() but appends the result to
70
//   *output.  Example:
71
//
72
//     string str;
73
//     strings::SubstituteAndAppend(&str,
74
//                                  "My name is $0 $1 and I am $2 years old.",
75
//                                  first_name, last_name, age);
76
//
77
//   Substitute() is significantly faster than StringPrintf().  For very
78
//   large strings, it may be orders of magnitude faster.
79
// ----------------------------------------------------------------------
80
81
namespace internal {  // Implementation details.
82
83
// This class has implicit constructors.
84
// Style guide exception granted:
85
// http://goto/style-guide-exception-20978288
86
87
class SubstituteArg {
88
 public:
89
  // We must explicitly overload char* so that the compiler doesn't try to
90
  // cast it to bool to construct a DynamicSubstituteArg.  Might as well
91
  // overload const string& as well, since this allows us to avoid a temporary
92
  // object.
93
  // Tell PVS Studio it is OK that scratch_ is uninitialized.
94
  // -V:scratch_:730
95
  inline SubstituteArg(const char* value)  // NOLINT(runtime/explicit)
96
14.8M
    : text_(value), size_(value == NULL ? 0 : strlen(text_)) {}
97
  inline SubstituteArg(const string& value)  // NOLINT(runtime/explicit)
98
545M
    : text_(value.data()), size_(value.size()) {}
99
  inline SubstituteArg(const GStringPiece& value)  // NOLINT(runtime/explicit)
100
0
    : text_(value.data()), size_(value.size()) {}
101
102
  // Primitives
103
  // We don't overload for signed and unsigned char because if people are
104
  // explicitly declaring their chars as signed or unsigned then they are
105
  // probably actually using them as 8-bit integers and would probably
106
  // prefer an integer representation.  But, we don't really know.  So, we
107
  // make the caller decide what to do.
108
  // -V:scratch_:730
109
  inline SubstituteArg(char value)  // NOLINT(runtime/explicit)
110
0
    : text_(scratch_), size_(1) { scratch_[0] = value; }
111
  // -V:scratch_:730
112
  inline SubstituteArg(short value)  // NOLINT
113
    : text_(scratch_),
114
      size_(FastInt32ToBufferLeft(value, scratch_) - scratch_) {}
115
  // -V:scratch_:730
116
  inline SubstituteArg(unsigned short value)  // NOLINT
117
    : text_(scratch_),
118
29.5k
      size_(FastUInt32ToBufferLeft(value, scratch_) - scratch_) {}
119
  // -V:scratch_:730
120
  inline SubstituteArg(int value)  // NOLINT
121
    : text_(scratch_),
122
26.5M
      size_(FastInt32ToBufferLeft(value, scratch_) - scratch_) {}
123
  // -V:scratch_:730
124
  inline SubstituteArg(unsigned int value)  // NOLINT
125
    : text_(scratch_),
126
212k
      size_(FastUInt32ToBufferLeft(value, scratch_) - scratch_) {}
127
  // -V:scratch_:730
128
  inline SubstituteArg(long value)  // NOLINT
129
    : text_(scratch_),
130
      size_((sizeof(value) == 4 ? FastInt32ToBufferLeft(static_cast<int32_t>(value), scratch_)
131
                                : FastInt64ToBufferLeft(value, scratch_))
132
12
            - scratch_) {}
133
  // -V:scratch_:730
134
  inline SubstituteArg(unsigned long value)  // NOLINT
135
    : text_(scratch_),
136
      size_((sizeof(value) == 4 ? FastUInt32ToBufferLeft(value, scratch_)
137
                                : FastUInt64ToBufferLeft(value, scratch_))
138
7.12M
            - scratch_) {}
139
  // -V:scratch_:730
140
  inline SubstituteArg(long long value)  // NOLINT
141
    : text_(scratch_),
142
27.5M
      size_(FastInt64ToBufferLeft(value, scratch_) - scratch_) {}
143
  // -V:scratch_:730
144
  inline SubstituteArg(unsigned long long value)  // NOLINT
145
    : text_(scratch_),
146
24.2k
      size_(FastUInt64ToBufferLeft(value, scratch_) - scratch_) {}
147
  // -V:scratch_:730
148
  inline SubstituteArg(float value)  // NOLINT(runtime/explicit)
149
0
    : text_(FloatToBuffer(value, scratch_)), size_(strlen(text_)) {}
150
  // -V:scratch_:730
151
  inline SubstituteArg(double value)  // NOLINT(runtime/explicit)
152
20
    : text_(DoubleToBuffer(value, scratch_)), size_(strlen(text_)) {}
153
  // -V:scratch_:730
154
  inline SubstituteArg(bool value)  // NOLINT(runtime/explicit)
155
490
    : text_(value ? "true" : "false"), size_(strlen(text_)) {}
156
  // void* values, with the exception of char*, are printed as
157
  // StringPrintf with format "%p" would ("0x<hex value>"), with the
158
  // exception of NULL, which is printed as "NULL".
159
  SubstituteArg(const void* value);  // NOLINT(runtime/explicit)
160
161
626M
  inline const char* data() const { return text_; }
162
2.50G
  inline ptrdiff_t size() const { return size_; }
163
164
  // Indicates that no argument was given.
165
  static const SubstituteArg NoArg;
166
167
 private:
168
32.7k
  inline SubstituteArg() : text_(NULL), size_(-1) {}
169
170
  const char* text_;
171
  ptrdiff_t size_;
172
  char scratch_[kFastToBufferSize];
173
};
174
175
// Return the length of the resulting string after performing the given
176
// substitution.
177
int SubstitutedSize(GStringPiece format,
178
                    const SubstituteArg* const* args_array);
179
180
// Perform the given substitution into 'target'. 'target' must have
181
// space for the result -- use SubstitutedSize() to determine how many
182
// bytes are required.  Returns a pointer to the next byte following
183
// the result in 'target'.
184
char* SubstituteToBuffer(GStringPiece format,
185
                         const SubstituteArg* const* args_array,
186
                         char* target);
187
188
}  // namespace internal
189
190
void SubstituteAndAppend(
191
  string* output, GStringPiece format,
192
  const internal::SubstituteArg& arg0 = internal::SubstituteArg::NoArg,
193
  const internal::SubstituteArg& arg1 = internal::SubstituteArg::NoArg,
194
  const internal::SubstituteArg& arg2 = internal::SubstituteArg::NoArg,
195
  const internal::SubstituteArg& arg3 = internal::SubstituteArg::NoArg,
196
  const internal::SubstituteArg& arg4 = internal::SubstituteArg::NoArg,
197
  const internal::SubstituteArg& arg5 = internal::SubstituteArg::NoArg,
198
  const internal::SubstituteArg& arg6 = internal::SubstituteArg::NoArg,
199
  const internal::SubstituteArg& arg7 = internal::SubstituteArg::NoArg,
200
  const internal::SubstituteArg& arg8 = internal::SubstituteArg::NoArg,
201
  const internal::SubstituteArg& arg9 = internal::SubstituteArg::NoArg);
202
203
inline string Substitute(
204
  GStringPiece format,
205
  const internal::SubstituteArg& arg0 = internal::SubstituteArg::NoArg,
206
  const internal::SubstituteArg& arg1 = internal::SubstituteArg::NoArg,
207
  const internal::SubstituteArg& arg2 = internal::SubstituteArg::NoArg,
208
  const internal::SubstituteArg& arg3 = internal::SubstituteArg::NoArg,
209
  const internal::SubstituteArg& arg4 = internal::SubstituteArg::NoArg,
210
  const internal::SubstituteArg& arg5 = internal::SubstituteArg::NoArg,
211
  const internal::SubstituteArg& arg6 = internal::SubstituteArg::NoArg,
212
  const internal::SubstituteArg& arg7 = internal::SubstituteArg::NoArg,
213
  const internal::SubstituteArg& arg8 = internal::SubstituteArg::NoArg,
214
236M
  const internal::SubstituteArg& arg9 = internal::SubstituteArg::NoArg) {
215
236M
  string result;
216
236M
  SubstituteAndAppend(&result, format, arg0, arg1, arg2, arg3, arg4,
217
236M
                                       arg5, arg6, arg7, arg8, arg9);
218
236M
  return result;
219
236M
}
220
221
}  // namespace strings
222
223
#endif // YB_GUTIL_STRINGS_SUBSTITUTE_H