/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 |