]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/util/string_util.cc
import 14.2.4 nautilus point release
[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
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"
494da23a 24#include "port/port.h"
7c673cae
FG
25#include "rocksdb/slice.h"
26
27namespace rocksdb {
28
29const std::string kNullptrString = "nullptr";
30
31std::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".
46int 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
71int 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
86void AppendNumberTo(std::string* str, uint64_t num) {
87 char buf[30];
88 snprintf(buf, sizeof(buf), "%" PRIu64, num);
89 str->append(buf);
90}
91
92void 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
106std::string NumberToString(uint64_t num) {
107 std::string r;
108 AppendNumberTo(&r, num);
109 return r;
110}
111
112std::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
127std::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
146std::string EscapeString(const Slice& value) {
147 std::string r;
148 AppendEscapedStringTo(&r, value);
149 return r;
150}
151
152bool 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
176bool isSpecialChar(const char c) {
177 if (c == '\\' || c == '#' || c == ':' || c == '\r' || c == '\n') {
178 return true;
179 }
180 return false;
181}
182
183namespace {
184using CharMap = std::pair<char, char>;
185}
186
187char 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
199char 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
211std::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
225std::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
244std::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;
11fdf7f2 248 while (isspace(str[start]) != 0 && start < end) {
7c673cae
FG
249 ++start;
250 }
11fdf7f2 251 while (isspace(str[end]) != 0 && start < end) {
7c673cae
FG
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
262bool 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
271uint32_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
494da23a
TL
280int32_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
7c673cae
FG
289#endif
290
291uint64_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
494da23a
TL
316int64_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
7c673cae
FG
341int 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
364double 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
372size_t ParseSizeT(const std::string& value) {
373 return static_cast<size_t>(ParseUint64(value));
374}
375
376std::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
392bool 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