string_util.cc 10 KB

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