LogCabin
Core/StringUtil.cc
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines