LogCabin
|
00001 /* Copyright (c) 2011-2012 Stanford University 00002 * 00003 * Copyright (c) 2011 Facebook 00004 * startsWith() and endsWith() functions 00005 * 00006 * Copyright (c) 2015 Diego Ongaro 00007 * 00008 * Permission to use, copy, modify, and distribute this software for any 00009 * purpose with or without fee is hereby granted, provided that the above 00010 * copyright notice and this permission notice appear in all copies. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00013 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00014 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00015 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00016 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00017 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00018 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00019 */ 00020 00021 #include <algorithm> 00022 #include <cassert> 00023 #include <cctype> 00024 #include <cstdarg> 00025 #include <cstring> 00026 #include <functional> 00027 #include <locale> 00028 #include <sstream> 00029 00030 #include "Core/StringUtil.h" 00031 00032 namespace LogCabin { 00033 namespace Core { 00034 namespace StringUtil { 00035 00036 namespace { 00037 00038 /** 00039 * Returns true for the ASCII characters that one would want to display in a 00040 * single line of text. 00041 */ 00042 bool 00043 display(char c) 00044 { 00045 return (32 <= c && c < 127); 00046 } 00047 00048 } // anonymous namespace 00049 00050 std::string 00051 flags(int value, 00052 std::initializer_list<std::pair<int, const char*>> flags) 00053 { 00054 if (value == 0) 00055 return "0"; 00056 std::vector<std::string> strings; 00057 for (auto it = flags.begin(); it != flags.end(); ++it) { 00058 if (value & it->first) { 00059 strings.push_back(it->second); 00060 value &= ~it->first; 00061 } 00062 } 00063 if (value) 00064 strings.push_back(format("0x%x", value)); 00065 return join(strings, "|"); 00066 } 00067 00068 // This comes from the RAMCloud project. 00069 std::string 00070 format(const char* format, ...) 00071 { 00072 std::string s; 00073 va_list ap; 00074 va_start(ap, format); 00075 00076 // We're not really sure how big of a buffer will be necessary. 00077 // Try 1K, if not the return value will tell us how much is necessary. 00078 size_t bufSize = 1024; 00079 while (true) { 00080 char buf[bufSize]; 00081 // vsnprintf trashes the va_list, so copy it first 00082 va_list aq; 00083 va_copy(aq, ap); 00084 int r = vsnprintf(buf, bufSize, format, aq); 00085 va_end(aq); 00086 assert(r >= 0); // old glibc versions returned -1 00087 size_t r2 = size_t(r); 00088 if (r2 < bufSize) { 00089 s = buf; 00090 break; 00091 } 00092 bufSize = r2 + 1; 00093 } 00094 00095 va_end(ap); 00096 return s; 00097 } 00098 00099 bool 00100 isPrintable(const char* str) 00101 { 00102 return isPrintable(str, strlen(str) + 1); 00103 } 00104 00105 bool 00106 isPrintable(const void* data, size_t length) 00107 { 00108 const char* begin = static_cast<const char*>(data); 00109 const char* end = begin + length - 1; 00110 return (length >= 1 && 00111 *end == '\0' && 00112 std::all_of(begin, end, display)); 00113 } 00114 00115 std::string 00116 join(const std::vector<std::string>& components, const std::string& glue) 00117 { 00118 std::string r; 00119 for (uint64_t i = 0; i < components.size(); ++i) { 00120 r += components.at(i); 00121 if (i < components.size() - 1) 00122 r += glue; 00123 } 00124 return r; 00125 } 00126 00127 void 00128 replaceAll(std::string& haystack, 00129 const std::string& needle, 00130 const std::string& replacement) 00131 { 00132 size_t startPos = 0; 00133 while (true) { 00134 size_t replacePos = haystack.find(needle, startPos); 00135 if (replacePos == haystack.npos) 00136 return; 00137 haystack.replace(replacePos, needle.length(), replacement); 00138 startPos = replacePos + replacement.length(); 00139 } 00140 } 00141 00142 std::vector<std::string> 00143 split(const std::string& subject, char delimiter) 00144 { 00145 std::vector<std::string> items; 00146 std::istringstream stream(subject); 00147 std::string item; 00148 while (std::getline(stream, item, delimiter)) 00149 items.push_back(std::move(item)); 00150 return items; 00151 } 00152 00153 bool 00154 startsWith(const std::string& haystack, const std::string& needle) 00155 { 00156 return (haystack.compare(0, needle.length(), needle) == 0); 00157 } 00158 00159 bool 00160 endsWith(const std::string& haystack, const std::string& needle) 00161 { 00162 if (haystack.length() < needle.length()) 00163 return false; 00164 return (haystack.compare(haystack.length() - needle.length(), 00165 needle.length(), needle) == 0); 00166 } 00167 00168 std::string 00169 trim(const std::string& original) 00170 { 00171 // The black magic is from https://stackoverflow.com/a/217605 00172 std::string s = original; 00173 00174 // trim whitespace at end of string 00175 s.erase(std::find_if(s.rbegin(), s.rend(), 00176 std::not1(std::ptr_fun<int, int>(std::isspace))) 00177 .base(), 00178 s.end()); 00179 00180 // trim whitespace at beginning of string 00181 s.erase(s.begin(), 00182 std::find_if(s.begin(), s.end(), 00183 std::not1(std::ptr_fun<int, int>(std::isspace)))); 00184 00185 return s; 00186 } 00187 00188 00189 } // namespace LogCabin::Core::StringUtil 00190 } // namespace LogCabin::Core 00191 } // namespace LogCabin