#include "common.hh" #include "strutil.hh" #include #include #include namespace str { namespace { // Sadly strtoul(l) doesn't treat negative values an error but instead returns // ULONG_MAX - value which is indistinguable from ULONG_MAX - value the positive // way. bool is_negative(std::string const& str) { for (auto i = str.begin(); i != str.end(); ++i) { if (!isspace(*i)) { return *i == '-'; } } return false; } } // namespace std::optional parse_uint16(std::string const& str) { static_assert(sizeof(unsigned long) >= sizeof(uint16_t), "Need unsigned long to be >= uint16_t"); if (str.empty() || is_negative(str)) return std::nullopt; char* end = nullptr; errno = 0; auto tmp = strtoul(str.c_str(), &end, 10); if (errno || end != str.c_str() + str.size() || tmp > std::numeric_limits::max()) return std::nullopt; return static_cast(tmp); } std::optional parse_uint32(std::string const& str) { static_assert(sizeof(unsigned long long) >= sizeof(uint32_t), "Need unsigned long long to be >= uint32_t"); if (str.empty() || is_negative(str)) return std::nullopt; char* end = nullptr; errno = 0; auto tmp = strtoull(str.c_str(), &end, 10); if (errno || end != str.c_str() + str.size() || tmp > std::numeric_limits::max()) return std::nullopt; return static_cast(tmp); } std::optional parse_uint64(std::string const& str) { static_assert(sizeof(unsigned long long) >= sizeof(uint64_t), "Need unsigned long long to be >= uint64_t"); if (str.empty() || is_negative(str)) return std::nullopt; char* end = nullptr; errno = 0; auto tmp = strtoull(str.c_str(), &end, 10); if (errno || end != str.c_str() + str.size() || tmp > std::numeric_limits::max()) return std::nullopt; return static_cast(tmp); } std::vector split(std::string_view str, char delim) { std::vector ret; size_t last = 0; while (true) { size_t next = str.find(delim, last); if (next == std::string::npos) break; if (next > last) ret.push_back(str.substr(last, next - last)); last = next + 1; } if (last < str.size() || ret.empty()) ret.push_back(str.substr(last)); return ret; } std::vector split(std::string const& str, char delim) { std::vector ret; size_t last = 0; while (true) { size_t next = str.find(delim, last); if (next == std::string::npos) break; if (next > last) ret.push_back(str.substr(last, next - last)); last = next + 1; } if (last < str.size() || ret.empty()) ret.push_back(str.substr(last)); return ret; } std::string join(std::vector const& in, char delim) { std::string ret; join(in, delim, ret); return ret; } std::string join(std::vector const& in, std::string_view delim) { std::string ret; join(in, delim, ret); return ret; } void join(std::vector const& in, char delim, std::string& out) { join(in, std::string_view(&delim, 1), out); } void join(std::vector const& in, std::string_view delim, std::string& out) { auto it = in.begin(); if (it == in.end()) return; out.append(*it); for (++it; it != in.end(); ++it) { out.append(delim); out.append(*it); } } std::string join(std::vector const& in, char delim) { std::string ret; join(in, delim, ret); return ret; } std::string join(std::vector const& in, std::string_view delim) { std::string ret; join(in, delim, ret); return ret; } void join(std::vector const& in, char delim, std::string& out) { join(in, std::string_view(&delim, 1), out); } void join(std::vector const& in, std::string_view delim, std::string& out) { auto it = in.begin(); if (it == in.end()) return; out.append(*it); for (++it; it != in.end(); ++it) { out.append(delim); out.append(*it); } } bool starts_with(std::string_view str, std::string_view prefix) { return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0; } bool ends_with(std::string_view str, std::string_view suffix) { return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } std::string_view trim(std::string_view str) { return ltrim(rtrim(str)); } std::string_view ltrim(std::string_view str) { size_t start = 0; while (start < str.size() && str[start] == ' ') ++start; return str.substr(start); } std::string_view rtrim(std::string_view str) { size_t end = str.size(); while (end > 0 && str[end - 1] == ' ') --end; return str.substr(0, end); } std::string trim(std::string const& str) { size_t start = 0; while (start < str.size() && str[start] == ' ') ++start; size_t end = str.size(); while (end > start && str[end - 1] == ' ') --end; return str.substr(start, end - start); } std::string ltrim(std::string const& str) { size_t start = 0; while (start < str.size() && str[start] == ' ') ++start; return str.substr(start); } std::string rtrim(std::string const& str) { size_t end = str.size(); while (end > 0 && str[end - 1] == ' ') --end; return str.substr(0, end); } } // namespace str