]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/util/string_util.cc
bump version to 15.2.11-pve1
[ceph.git] / ceph / src / rocksdb / util / string_util.cc
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 //
6 #include "util/string_util.h"
7
8 #ifndef __STDC_FORMAT_MACROS
9 #define __STDC_FORMAT_MACROS
10 #endif
11
12 #include <errno.h>
13 #include <inttypes.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <algorithm>
18 #include <cmath>
19 #include <sstream>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 #include "rocksdb/env.h"
24 #include "port/port.h"
25 #include "rocksdb/slice.h"
26
27 namespace rocksdb {
28
29 const std::string kNullptrString = "nullptr";
30
31 std::vector<std::string> StringSplit(const std::string& arg, char delim) {
32 std::vector<std::string> splits;
33 std::stringstream ss(arg);
34 std::string item;
35 while (std::getline(ss, item, delim)) {
36 splits.push_back(item);
37 }
38 return splits;
39 }
40
41 // for micros < 10ms, print "XX us".
42 // for micros < 10sec, print "XX ms".
43 // for micros >= 10 sec, print "XX sec".
44 // for micros <= 1 hour, print Y:X M:S".
45 // for micros > 1 hour, print Z:Y:X H:M:S".
46 int AppendHumanMicros(uint64_t micros, char* output, int len,
47 bool fixed_format) {
48 if (micros < 10000 && !fixed_format) {
49 return snprintf(output, len, "%" PRIu64 " us", micros);
50 } else if (micros < 10000000 && !fixed_format) {
51 return snprintf(output, len, "%.3lf ms",
52 static_cast<double>(micros) / 1000);
53 } else if (micros < 1000000l * 60 && !fixed_format) {
54 return snprintf(output, len, "%.3lf sec",
55 static_cast<double>(micros) / 1000000);
56 } else if (micros < 1000000ll * 60 * 60 && !fixed_format) {
57 return snprintf(output, len, "%02" PRIu64 ":%05.3f M:S",
58 micros / 1000000 / 60,
59 static_cast<double>(micros % 60000000) / 1000000);
60 } else {
61 return snprintf(output, len, "%02" PRIu64 ":%02" PRIu64 ":%05.3f H:M:S",
62 micros / 1000000 / 3600, (micros / 1000000 / 60) % 60,
63 static_cast<double>(micros % 60000000) / 1000000);
64 }
65 }
66
67 // for sizes >=10TB, print "XXTB"
68 // for sizes >=10GB, print "XXGB"
69 // etc.
70 // append file size summary to output and return the len
71 int AppendHumanBytes(uint64_t bytes, char* output, int len) {
72 const uint64_t ull10 = 10;
73 if (bytes >= ull10 << 40) {
74 return snprintf(output, len, "%" PRIu64 "TB", bytes >> 40);
75 } else if (bytes >= ull10 << 30) {
76 return snprintf(output, len, "%" PRIu64 "GB", bytes >> 30);
77 } else if (bytes >= ull10 << 20) {
78 return snprintf(output, len, "%" PRIu64 "MB", bytes >> 20);
79 } else if (bytes >= ull10 << 10) {
80 return snprintf(output, len, "%" PRIu64 "KB", bytes >> 10);
81 } else {
82 return snprintf(output, len, "%" PRIu64 "B", bytes);
83 }
84 }
85
86 void AppendNumberTo(std::string* str, uint64_t num) {
87 char buf[30];
88 snprintf(buf, sizeof(buf), "%" PRIu64, num);
89 str->append(buf);
90 }
91
92 void AppendEscapedStringTo(std::string* str, const Slice& value) {
93 for (size_t i = 0; i < value.size(); i++) {
94 char c = value[i];
95 if (c >= ' ' && c <= '~') {
96 str->push_back(c);
97 } else {
98 char buf[10];
99 snprintf(buf, sizeof(buf), "\\x%02x",
100 static_cast<unsigned int>(c) & 0xff);
101 str->append(buf);
102 }
103 }
104 }
105
106 std::string NumberToString(uint64_t num) {
107 std::string r;
108 AppendNumberTo(&r, num);
109 return r;
110 }
111
112 std::string NumberToHumanString(int64_t num) {
113 char buf[19];
114 int64_t absnum = num < 0 ? -num : num;
115 if (absnum < 10000) {
116 snprintf(buf, sizeof(buf), "%" PRIi64, num);
117 } else if (absnum < 10000000) {
118 snprintf(buf, sizeof(buf), "%" PRIi64 "K", num / 1000);
119 } else if (absnum < 10000000000LL) {
120 snprintf(buf, sizeof(buf), "%" PRIi64 "M", num / 1000000);
121 } else {
122 snprintf(buf, sizeof(buf), "%" PRIi64 "G", num / 1000000000);
123 }
124 return std::string(buf);
125 }
126
127 std::string BytesToHumanString(uint64_t bytes) {
128 const char* size_name[] = {"KB", "MB", "GB", "TB"};
129 double final_size = static_cast<double>(bytes);
130 size_t size_idx;
131
132 // always start with KB
133 final_size /= 1024;
134 size_idx = 0;
135
136 while (size_idx < 3 && final_size >= 1024) {
137 final_size /= 1024;
138 size_idx++;
139 }
140
141 char buf[20];
142 snprintf(buf, sizeof(buf), "%.2f %s", final_size, size_name[size_idx]);
143 return std::string(buf);
144 }
145
146 std::string EscapeString(const Slice& value) {
147 std::string r;
148 AppendEscapedStringTo(&r, value);
149 return r;
150 }
151
152 bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
153 uint64_t v = 0;
154 int digits = 0;
155 while (!in->empty()) {
156 char c = (*in)[0];
157 if (c >= '0' && c <= '9') {
158 ++digits;
159 const unsigned int delta = (c - '0');
160 static const uint64_t kMaxUint64 = ~static_cast<uint64_t>(0);
161 if (v > kMaxUint64 / 10 ||
162 (v == kMaxUint64 / 10 && delta > kMaxUint64 % 10)) {
163 // Overflow
164 return false;
165 }
166 v = (v * 10) + delta;
167 in->remove_prefix(1);
168 } else {
169 break;
170 }
171 }
172 *val = v;
173 return (digits > 0);
174 }
175
176 bool isSpecialChar(const char c) {
177 if (c == '\\' || c == '#' || c == ':' || c == '\r' || c == '\n') {
178 return true;
179 }
180 return false;
181 }
182
183 namespace {
184 using CharMap = std::pair<char, char>;
185 }
186
187 char UnescapeChar(const char c) {
188 static const CharMap convert_map[] = {{'r', '\r'}, {'n', '\n'}};
189
190 auto iter = std::find_if(std::begin(convert_map), std::end(convert_map),
191 [c](const CharMap& p) { return p.first == c; });
192
193 if (iter == std::end(convert_map)) {
194 return c;
195 }
196 return iter->second;
197 }
198
199 char EscapeChar(const char c) {
200 static const CharMap convert_map[] = {{'\n', 'n'}, {'\r', 'r'}};
201
202 auto iter = std::find_if(std::begin(convert_map), std::end(convert_map),
203 [c](const CharMap& p) { return p.first == c; });
204
205 if (iter == std::end(convert_map)) {
206 return c;
207 }
208 return iter->second;
209 }
210
211 std::string EscapeOptionString(const std::string& raw_string) {
212 std::string output;
213 for (auto c : raw_string) {
214 if (isSpecialChar(c)) {
215 output += '\\';
216 output += EscapeChar(c);
217 } else {
218 output += c;
219 }
220 }
221
222 return output;
223 }
224
225 std::string UnescapeOptionString(const std::string& escaped_string) {
226 bool escaped = false;
227 std::string output;
228
229 for (auto c : escaped_string) {
230 if (escaped) {
231 output += UnescapeChar(c);
232 escaped = false;
233 } else {
234 if (c == '\\') {
235 escaped = true;
236 continue;
237 }
238 output += c;
239 }
240 }
241 return output;
242 }
243
244 std::string trim(const std::string& str) {
245 if (str.empty()) return std::string();
246 size_t start = 0;
247 size_t end = str.size() - 1;
248 while (isspace(str[start]) != 0 && start < end) {
249 ++start;
250 }
251 while (isspace(str[end]) != 0 && start < end) {
252 --end;
253 }
254 if (start <= end) {
255 return str.substr(start, end - start + 1);
256 }
257 return std::string();
258 }
259
260 #ifndef ROCKSDB_LITE
261
262 bool ParseBoolean(const std::string& type, const std::string& value) {
263 if (value == "true" || value == "1") {
264 return true;
265 } else if (value == "false" || value == "0") {
266 return false;
267 }
268 throw std::invalid_argument(type);
269 }
270
271 uint32_t ParseUint32(const std::string& value) {
272 uint64_t num = ParseUint64(value);
273 if ((num >> 32LL) == 0) {
274 return static_cast<uint32_t>(num);
275 } else {
276 throw std::out_of_range(value);
277 }
278 }
279
280 int32_t ParseInt32(const std::string& value) {
281 int64_t num = ParseInt64(value);
282 if (num <= port::kMaxInt32 && num >= port::kMinInt32) {
283 return static_cast<int32_t>(num);
284 } else {
285 throw std::out_of_range(value);
286 }
287 }
288
289 #endif
290
291 uint64_t ParseUint64(const std::string& value) {
292 size_t endchar;
293 #ifndef CYGWIN
294 uint64_t num = std::stoull(value.c_str(), &endchar);
295 #else
296 char* endptr;
297 uint64_t num = std::strtoul(value.c_str(), &endptr, 0);
298 endchar = endptr - value.c_str();
299 #endif
300
301 if (endchar < value.length()) {
302 char c = value[endchar];
303 if (c == 'k' || c == 'K')
304 num <<= 10LL;
305 else if (c == 'm' || c == 'M')
306 num <<= 20LL;
307 else if (c == 'g' || c == 'G')
308 num <<= 30LL;
309 else if (c == 't' || c == 'T')
310 num <<= 40LL;
311 }
312
313 return num;
314 }
315
316 int64_t ParseInt64(const std::string& value) {
317 size_t endchar;
318 #ifndef CYGWIN
319 int64_t num = std::stoll(value.c_str(), &endchar);
320 #else
321 char* endptr;
322 int64_t num = std::strtoll(value.c_str(), &endptr, 0);
323 endchar = endptr - value.c_str();
324 #endif
325
326 if (endchar < value.length()) {
327 char c = value[endchar];
328 if (c == 'k' || c == 'K')
329 num <<= 10LL;
330 else if (c == 'm' || c == 'M')
331 num <<= 20LL;
332 else if (c == 'g' || c == 'G')
333 num <<= 30LL;
334 else if (c == 't' || c == 'T')
335 num <<= 40LL;
336 }
337
338 return num;
339 }
340
341 int ParseInt(const std::string& value) {
342 size_t endchar;
343 #ifndef CYGWIN
344 int num = std::stoi(value.c_str(), &endchar);
345 #else
346 char* endptr;
347 int num = std::strtoul(value.c_str(), &endptr, 0);
348 endchar = endptr - value.c_str();
349 #endif
350
351 if (endchar < value.length()) {
352 char c = value[endchar];
353 if (c == 'k' || c == 'K')
354 num <<= 10;
355 else if (c == 'm' || c == 'M')
356 num <<= 20;
357 else if (c == 'g' || c == 'G')
358 num <<= 30;
359 }
360
361 return num;
362 }
363
364 double ParseDouble(const std::string& value) {
365 #ifndef CYGWIN
366 return std::stod(value);
367 #else
368 return std::strtod(value.c_str(), 0);
369 #endif
370 }
371
372 size_t ParseSizeT(const std::string& value) {
373 return static_cast<size_t>(ParseUint64(value));
374 }
375
376 std::vector<int> ParseVectorInt(const std::string& value) {
377 std::vector<int> result;
378 size_t start = 0;
379 while (start < value.size()) {
380 size_t end = value.find(':', start);
381 if (end == std::string::npos) {
382 result.push_back(ParseInt(value.substr(start)));
383 break;
384 } else {
385 result.push_back(ParseInt(value.substr(start, end - start)));
386 start = end + 1;
387 }
388 }
389 return result;
390 }
391
392 bool SerializeIntVector(const std::vector<int>& vec, std::string* value) {
393 *value = "";
394 for (size_t i = 0; i < vec.size(); ++i) {
395 if (i > 0) {
396 *value += ":";
397 }
398 *value += ToString(vec[i]);
399 }
400 return true;
401 }
402
403 } // namespace rocksdb