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