/proc/self/cwd/external/abseil-cpp~/absl/strings/substitute.cc
Line | Count | Source |
1 | | // Copyright 2017 The Abseil Authors. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include "absl/strings/substitute.h" |
16 | | |
17 | | #include <algorithm> |
18 | | #include <cassert> |
19 | | #include <cstddef> |
20 | | #include <cstdint> |
21 | | #include <limits> |
22 | | #include <string> |
23 | | |
24 | | #include "absl/base/config.h" |
25 | | #include "absl/base/internal/raw_logging.h" |
26 | | #include "absl/base/nullability.h" |
27 | | #include "absl/strings/ascii.h" |
28 | | #include "absl/strings/escaping.h" |
29 | | #include "absl/strings/internal/resize_uninitialized.h" |
30 | | #include "absl/strings/numbers.h" |
31 | | #include "absl/strings/str_cat.h" |
32 | | #include "absl/strings/string_view.h" |
33 | | |
34 | | namespace absl { |
35 | | ABSL_NAMESPACE_BEGIN |
36 | | namespace substitute_internal { |
37 | | |
38 | | void SubstituteAndAppendArray(std::string* absl_nonnull output, |
39 | | absl::string_view format, |
40 | | const absl::string_view* absl_nullable args_array, |
41 | 0 | size_t num_args) { |
42 | | // Determine total size needed. |
43 | 0 | size_t size = 0; |
44 | 0 | for (size_t i = 0; i < format.size(); i++) { |
45 | 0 | if (format[i] == '$') { |
46 | 0 | if (i + 1 >= format.size()) { |
47 | | #ifndef NDEBUG |
48 | | ABSL_RAW_LOG(FATAL, |
49 | | "Invalid absl::Substitute() format string: \"%s\".", |
50 | | absl::CEscape(format).c_str()); |
51 | | #endif |
52 | 0 | return; |
53 | 0 | } else if (absl::ascii_isdigit( |
54 | 0 | static_cast<unsigned char>(format[i + 1]))) { |
55 | 0 | int index = format[i + 1] - '0'; |
56 | 0 | if (static_cast<size_t>(index) >= num_args) { |
57 | | #ifndef NDEBUG |
58 | | ABSL_RAW_LOG( |
59 | | FATAL, |
60 | | "Invalid absl::Substitute() format string: asked for \"$" |
61 | | "%d\", but only %d args were given. Full format string was: " |
62 | | "\"%s\".", |
63 | | index, static_cast<int>(num_args), absl::CEscape(format).c_str()); |
64 | | #endif |
65 | 0 | return; |
66 | 0 | } |
67 | 0 | size += args_array[index].size(); |
68 | 0 | ++i; // Skip next char. |
69 | 0 | } else if (format[i + 1] == '$') { |
70 | 0 | ++size; |
71 | 0 | ++i; // Skip next char. |
72 | 0 | } else { |
73 | | #ifndef NDEBUG |
74 | | ABSL_RAW_LOG(FATAL, |
75 | | "Invalid absl::Substitute() format string: \"%s\".", |
76 | | absl::CEscape(format).c_str()); |
77 | | #endif |
78 | 0 | return; |
79 | 0 | } |
80 | 0 | } else { |
81 | 0 | ++size; |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | 0 | if (size == 0) return; |
86 | | |
87 | | // Build the string. |
88 | 0 | size_t original_size = output->size(); |
89 | 0 | ABSL_INTERNAL_CHECK( |
90 | 0 | size <= std::numeric_limits<size_t>::max() - original_size, |
91 | 0 | "size_t overflow"); |
92 | 0 | strings_internal::STLStringResizeUninitializedAmortized(output, |
93 | 0 | original_size + size); |
94 | 0 | char* target = &(*output)[original_size]; |
95 | 0 | for (size_t i = 0; i < format.size(); i++) { |
96 | 0 | if (format[i] == '$') { |
97 | 0 | if (absl::ascii_isdigit(static_cast<unsigned char>(format[i + 1]))) { |
98 | 0 | const absl::string_view src = args_array[format[i + 1] - '0']; |
99 | 0 | target = std::copy(src.begin(), src.end(), target); |
100 | 0 | ++i; // Skip next char. |
101 | 0 | } else if (format[i + 1] == '$') { |
102 | 0 | *target++ = '$'; |
103 | 0 | ++i; // Skip next char. |
104 | 0 | } |
105 | 0 | } else { |
106 | 0 | *target++ = format[i]; |
107 | 0 | } |
108 | 0 | } |
109 | |
|
110 | 0 | assert(target == output->data() + output->size()); |
111 | 0 | } |
112 | | |
113 | 0 | Arg::Arg(const void* absl_nullable value) { |
114 | 0 | static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, |
115 | 0 | "fix sizeof(scratch_)"); |
116 | 0 | if (value == nullptr) { |
117 | 0 | piece_ = "NULL"; |
118 | 0 | } else { |
119 | 0 | char* ptr = scratch_ + sizeof(scratch_); |
120 | 0 | uintptr_t num = reinterpret_cast<uintptr_t>(value); |
121 | 0 | do { |
122 | 0 | *--ptr = absl::numbers_internal::kHexChar[num & 0xf]; |
123 | 0 | num >>= 4; |
124 | 0 | } while (num != 0); |
125 | 0 | *--ptr = 'x'; |
126 | 0 | *--ptr = '0'; |
127 | 0 | piece_ = absl::string_view( |
128 | 0 | ptr, static_cast<size_t>(scratch_ + sizeof(scratch_) - ptr)); |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | | // TODO(jorg): Don't duplicate so much code between here and str_cat.cc |
133 | 0 | Arg::Arg(Hex hex) { |
134 | 0 | char* const end = &scratch_[numbers_internal::kFastToBufferSize]; |
135 | 0 | char* writer = end; |
136 | 0 | uint64_t value = hex.value; |
137 | 0 | do { |
138 | 0 | *--writer = absl::numbers_internal::kHexChar[value & 0xF]; |
139 | 0 | value >>= 4; |
140 | 0 | } while (value != 0); |
141 | |
|
142 | 0 | char* beg; |
143 | 0 | if (end - writer < hex.width) { |
144 | 0 | beg = end - hex.width; |
145 | 0 | std::fill_n(beg, writer - beg, hex.fill); |
146 | 0 | } else { |
147 | 0 | beg = writer; |
148 | 0 | } |
149 | |
|
150 | 0 | piece_ = absl::string_view(beg, static_cast<size_t>(end - beg)); |
151 | 0 | } |
152 | | |
153 | | // TODO(jorg): Don't duplicate so much code between here and str_cat.cc |
154 | 0 | Arg::Arg(Dec dec) { |
155 | 0 | assert(dec.width <= numbers_internal::kFastToBufferSize); |
156 | 0 | char* const end = &scratch_[numbers_internal::kFastToBufferSize]; |
157 | 0 | char* const minfill = end - dec.width; |
158 | 0 | char* writer = end; |
159 | 0 | uint64_t value = dec.value; |
160 | 0 | bool neg = dec.neg; |
161 | 0 | while (value > 9) { |
162 | 0 | *--writer = '0' + (value % 10); |
163 | 0 | value /= 10; |
164 | 0 | } |
165 | 0 | *--writer = '0' + static_cast<char>(value); |
166 | 0 | if (neg) *--writer = '-'; |
167 | |
|
168 | 0 | ptrdiff_t fillers = writer - minfill; |
169 | 0 | if (fillers > 0) { |
170 | | // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> |
171 | | // But...: if the fill character is '0', then it's <+/-><fill><digits> |
172 | 0 | bool add_sign_again = false; |
173 | 0 | if (neg && dec.fill == '0') { // If filling with '0', |
174 | 0 | ++writer; // ignore the sign we just added |
175 | 0 | add_sign_again = true; // and re-add the sign later. |
176 | 0 | } |
177 | 0 | writer -= fillers; |
178 | 0 | std::fill_n(writer, fillers, dec.fill); |
179 | 0 | if (add_sign_again) *--writer = '-'; |
180 | 0 | } |
181 | |
|
182 | 0 | piece_ = absl::string_view(writer, static_cast<size_t>(end - writer)); |
183 | 0 | } |
184 | | |
185 | | } // namespace substitute_internal |
186 | | ABSL_NAMESPACE_END |
187 | | } // namespace absl |