From 54186c4a898daecb062a489565d5930dd2039cbe Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Sat, 22 Feb 2020 22:23:19 -0400 Subject: [PATCH] Replace absl string_view with string_view from lokimq When we add loki-mq has a dependency we can just alias it, but for now it's easier to copy the header than add the whole submodule library. --- libabyss/src/http.cpp | 7 +- llarp/CMakeLists.txt | 5 - llarp/config/config.cpp | 77 +++++----- llarp/config/ini.cpp | 30 ++-- llarp/config/ini.hpp | 9 +- llarp/handlers/tun.cpp | 2 +- llarp/net/net_addr.cpp | 8 +- llarp/rpc/rpc.cpp | 4 +- llarp/service/config.cpp | 17 ++- llarp/util/printer.hpp | 1 + llarp/util/str.cpp | 26 ++-- llarp/util/str.hpp | 11 +- llarp/util/string_view.hpp | 224 ++++++++++++++++++++++++++++-- test/util/test_llarp_util_str.cpp | 4 +- 14 files changed, 301 insertions(+), 124 deletions(-) diff --git a/libabyss/src/http.cpp b/libabyss/src/http.cpp index 7a1f20cfb..e85775fc2 100644 --- a/libabyss/src/http.cpp +++ b/libabyss/src/http.cpp @@ -22,14 +22,13 @@ namespace abyss auto itr = header.begin(); while(itr != header.end()) { - lowerHeader += ::tolower(*itr); + lowerHeader += std::tolower(*itr); ++itr; } - if(ShouldProcessHeader(string_view(lowerHeader))) + if(ShouldProcessHeader(lowerHeader)) { val = val.substr(val.find_first_not_of(' ')); - Header.Headers.emplace(lowerHeader.c_str(), - llarp::string_view_string(val)); + Header.Headers.emplace(lowerHeader.c_str(), val); } return true; } diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 26f863d9c..eb1ce749a 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -50,11 +50,6 @@ target_link_libraries(${UTIL_LIB} PUBLIC date::date ) -# cut back on fluff -if (NOT WIN32) - target_link_libraries(${UTIL_LIB} PUBLIC absl::strings) -endif(NOT WIN32) - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(ISOLATE_PROC_SRC linux/netns.cpp) endif() diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index c46a867bc..1704bd4d2 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -72,17 +72,10 @@ namespace llarp return val; } - std::string - tostr(string_view val) - { - return {val.begin(), val.end()}; - } - int svtoi(string_view val) { - auto str = tostr(val); - return std::atoi(str.c_str()); + return std::atoi(val.data()); } nonstd::optional< bool > @@ -113,14 +106,14 @@ namespace llarp } if(key == "default-protocol") { - m_DefaultLinkProto = tostr(val); + m_DefaultLinkProto = val; LogInfo("overriding default link protocol to '", val, "'"); } if(key == "netid") { if(val.size() <= NetID::size()) { - m_netId = tostr(val); + m_netId = val; LogInfo("setting netid to '", val, "'"); } else @@ -148,29 +141,29 @@ namespace llarp } if(key == "nickname") { - m_nickname = tostr(val); + m_nickname = val; // set logger name here LogContext::Instance().nodeName = nickname(); LogInfo("nickname set"); } if(key == "encryption-privkey") { - m_encryptionKeyfile = tostr(val); + m_encryptionKeyfile = val; LogDebug("encryption key set to ", m_encryptionKeyfile); } if(key == "contact-file") { - m_ourRcFile = tostr(val); + m_ourRcFile = val; LogDebug("rc file set to ", m_ourRcFile); } if(key == "transport-privkey") { - m_transportKeyfile = tostr(val); + m_transportKeyfile = val; LogDebug("transport key set to ", m_transportKeyfile); } if((key == "identity-privkey" || key == "ident-privkey")) { - m_identKeyfile = tostr(val); + m_identKeyfile = val; LogDebug("identity key set to ", m_identKeyfile); } if(key == "public-address" || key == "public-ip") @@ -236,16 +229,16 @@ namespace llarp } else if(key == "profiles") { - m_routerProfilesFile = tostr(val); + m_routerProfilesFile = val; llarp::LogInfo("setting profiles to ", routerProfilesFile()); } else if(key == "strict-connect") { - m_strictConnect = tostr(val); + m_strictConnect = val; } else { - m_netConfig.emplace(tostr(key), tostr(val)); + m_netConfig.emplace(key, val); } } @@ -254,7 +247,7 @@ namespace llarp { if(key == "dir") { - m_nodedbDir = tostr(val); + m_nodedbDir = val; } } @@ -264,12 +257,12 @@ namespace llarp if(key == "upstream") { llarp::LogInfo("add upstream resolver ", val); - netConfig.emplace("upstream-dns", tostr(val)); + netConfig.emplace("upstream-dns", val); } if(key == "bind") { llarp::LogInfo("set local dns to ", val); - netConfig.emplace("local-dns", tostr(val)); + netConfig.emplace("local-dns", val); } } @@ -279,25 +272,21 @@ namespace llarp uint16_t proto = 0; std::unordered_set< std::string > parsed_opts; - std::string v = tostr(val); std::string::size_type idx; static constexpr char delimiter = ','; do { - idx = v.find_first_of(delimiter); - if(idx != std::string::npos) + idx = val.find_first_of(delimiter); + if(idx != string_view::npos) { - std::string data = v.substr(0, idx); - TrimWhiteSpace(data); - parsed_opts.emplace(std::move(data)); - v = v.substr(idx + 1); + parsed_opts.insert(TrimWhiteSpace(val.substr(0, idx))); + val.remove_prefix(idx + 1); } else { - TrimWhiteSpace(v); - parsed_opts.insert(std::move(v)); + parsed_opts.insert(TrimWhiteSpace(val)); } - } while(idx != std::string::npos); + } while(idx != string_view::npos); std::unordered_set< std::string > opts; /// for each option for(const auto &item : parsed_opts) @@ -325,7 +314,7 @@ namespace llarp } else { - m_InboundLinks.emplace_back(tostr(key), AF_INET, proto, std::move(opts)); + m_InboundLinks.emplace_back(key, AF_INET, proto, std::move(opts)); } } @@ -338,7 +327,7 @@ namespace llarp void ServicesConfig::fromSection(string_view key, string_view val) { - services.emplace_back(tostr(key), tostr(val)); + services.emplace_back(key, val); } void @@ -346,7 +335,7 @@ namespace llarp { if(key == "pidfile") { - pidfile = tostr(val); + pidfile = val; } } @@ -367,16 +356,16 @@ namespace llarp } else if(key == "json-metrics-path") { - jsonMetricsPath = tostr(val); + jsonMetricsPath = val; } else if(key == "metric-tank-host") { - metricTankHost = tostr(val); + metricTankHost = val; } else { // consume everything else as a metric tag - metricTags[tostr(key)] = tostr(val); + metricTags[key] = val; } } @@ -389,7 +378,7 @@ namespace llarp } if(key == "bind") { - m_rpcBindAddr = tostr(val); + m_rpcBindAddr = val; } if(key == "authkey") { @@ -403,7 +392,7 @@ namespace llarp if(key == "service-node-seed") { usingSNSeed = true; - ident_keyfile = tostr(val); + ident_keyfile = std::string{val}; } if(key == "enabled") { @@ -411,15 +400,15 @@ namespace llarp } if(key == "jsonrpc" || key == "addr") { - lokidRPCAddr = tostr(val); + lokidRPCAddr = val; } if(key == "username") { - lokidRPCUser = tostr(val); + lokidRPCUser = val; } if(key == "password") { - lokidRPCPassword = tostr(val); + lokidRPCPassword = val; } } @@ -447,7 +436,7 @@ namespace llarp } if(key == "level") { - const auto maybe = LogLevelFromString(tostr(val)); + const auto maybe = LogLevelFromString(val); if(not maybe.has_value()) { LogError("bad log level: ", val); @@ -464,7 +453,7 @@ namespace llarp if(key == "file") { LogInfo("open log file: ", val); - std::string fname = tostr(val); + std::string fname = val; FILE *const logfile = ::fopen(fname.c_str(), "a"); if(logfile) { diff --git a/llarp/config/ini.cpp b/llarp/config/ini.cpp index e2c0d0245..d30a81af0 100644 --- a/llarp/config/ini.cpp +++ b/llarp/config/ini.cpp @@ -53,7 +53,7 @@ namespace llarp bool ConfigParser::Parse() { - std::list< String_t > lines; + std::list< string_view > lines; { auto itr = m_Data.begin(); // split into lines @@ -69,16 +69,16 @@ namespace llarp } } - String_t sectName; + string_view sectName; size_t lineno = 0; for(const auto& line : lines) { lineno++; - String_t realLine; + string_view realLine; auto comment = line.find_first_of(';'); - if(comment == String_t::npos) + if(comment == string_view::npos) comment = line.find_first_of('#'); - if(comment == String_t::npos) + if(comment == string_view::npos) realLine = line; else realLine = line.substr(0, comment); @@ -89,8 +89,8 @@ namespace llarp auto sectOpenPos = realLine.find_first_of('['); auto sectClosPos = realLine.find_first_of(']'); auto kvDelim = realLine.find_first_of('='); - if(sectOpenPos != String_t::npos && sectClosPos != String_t::npos - && kvDelim == String_t::npos) + if(sectOpenPos != string_view::npos && sectClosPos != string_view::npos + && kvDelim == string_view::npos) { // section header @@ -104,13 +104,13 @@ namespace llarp // set section name sectName = realLine.substr(sectOpenPos, sectClosPos); } - else if(kvDelim != String_t::npos) + else if(kvDelim != string_view::npos) { // key value pair - String_t::size_type k_start = 0; - String_t::size_type k_end = kvDelim; - String_t::size_type v_start = kvDelim + 1; - String_t::size_type v_end = realLine.size() - 1; + string_view::size_type k_start = 0; + string_view::size_type k_end = kvDelim; + string_view::size_type v_start = kvDelim + 1; + string_view::size_type v_end = realLine.size() - 1; // clamp whitespaces while(whitespace(realLine[k_start]) && k_start != kvDelim) ++k_start; @@ -122,8 +122,8 @@ namespace llarp --v_end; // sect.k = v - String_t k = realLine.substr(k_start, k_end - k_start); - String_t v = realLine.substr(v_start, 1 + (v_end - v_start)); + string_view k = realLine.substr(k_start, k_end - k_start); + string_view v = realLine.substr(v_start, 1 + (v_end - v_start)); if(k.size() == 0 || v.size() == 0) { LogError(m_FileName, " invalid line (", lineno, "): '", line, "'"); @@ -144,7 +144,7 @@ namespace llarp void ConfigParser::IterAll( - std::function< void(const String_t&, const Section_t&) > visit) + std::function< void(string_view, const Section_t&) > visit) { for(const auto& item : m_Config) visit(item.first, item.second); diff --git a/llarp/config/ini.hpp b/llarp/config/ini.hpp index 3fa9ad2b9..41352c724 100644 --- a/llarp/config/ini.hpp +++ b/llarp/config/ini.hpp @@ -12,11 +12,8 @@ namespace llarp { struct ConfigParser { - using String_t = llarp::string_view; - using Section_t = - std::unordered_multimap< String_t, String_t, string_view_hash >; - using Config_impl_t = - std::unordered_map< String_t, Section_t, string_view_hash >; + using Section_t = std::unordered_multimap< std::string, std::string >; + using Config_impl_t = std::unordered_map< std::string, Section_t >; /// clear parser void Clear(); @@ -35,7 +32,7 @@ namespace llarp /// iterate all sections and thier values void - IterAll(std::function< void(const String_t&, const Section_t&) > visit); + IterAll(std::function< void(string_view, const Section_t&) > visit); /// visit a section in config read only by name /// return false if no section or value propagated from visitor diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index ef6a48578..b7a337a6c 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -191,7 +191,7 @@ namespace llarp { routerStr = v; } - TrimWhiteSpace(routerStr); + routerStr = TrimWhiteSpace(routerStr); if(!(exitRouter.FromString(routerStr) || HexDecode(routerStr.c_str(), exitRouter.begin(), exitRouter.size()))) diff --git a/llarp/net/net_addr.cpp b/llarp/net/net_addr.cpp index 6145c6cfd..d4a9a4df5 100644 --- a/llarp/net/net_addr.cpp +++ b/llarp/net/net_addr.cpp @@ -64,16 +64,14 @@ namespace llarp this->from_char_array(str); } - Addr::Addr(string_view str, const uint16_t p_port) : Addr() + Addr::Addr(string_view str, const uint16_t p_port) : Addr(str) { - this->from_char_array(str); this->port(p_port); } - Addr::Addr(string_view addr_str, string_view port_str) : Addr() + Addr::Addr(string_view addr_str, string_view port_str) + : Addr(addr_str, std::strtoul(port_str.data(), nullptr, 10)) { - this->from_char_array(string_view_string(addr_str).c_str()); - this->port(std::strtoul(string_view_string(port_str).c_str(), nullptr, 10)); } bool diff --git a/llarp/rpc/rpc.cpp b/llarp/rpc/rpc.cpp index 4fe6f6576..23d5f9ebb 100644 --- a/llarp/rpc/rpc.cpp +++ b/llarp/rpc/rpc.cpp @@ -286,9 +286,7 @@ namespace llarp struct Handler : public ::abyss::httpd::IRPCHandler { AbstractRouter* router; - std::unordered_map< absl::string_view, std::function< Response() >, - absl::Hash< absl::string_view > > - m_dispatch; + std::unordered_map< std::string, std::function< Response() > > m_dispatch; Handler(::abyss::httpd::ConnImpl* conn, AbstractRouter* r) : ::abyss::httpd::IRPCHandler(conn) , router(r) diff --git a/llarp/service/config.cpp b/llarp/service/config.cpp index a33dcfd95..7d0e3d65f 100644 --- a/llarp/service/config.cpp +++ b/llarp/service/config.cpp @@ -12,15 +12,14 @@ namespace llarp ConfigParser parser; if(!parser.LoadFile(fname)) return false; - parser.IterAll([&](const ConfigParser::String_t& name, - const ConfigParser::Section_t& section) { - Config::section_t values; - values.first.assign(name.begin(), name.end()); - for(const auto& item : section) - values.second.emplace_back(string_view_string(item.first), - string_view_string(item.second)); - services.emplace_back(values); - }); + parser.IterAll( + [&](string_view name, const ConfigParser::Section_t& section) { + Config::section_t values; + values.first.assign(name.begin(), name.end()); + for(const auto& item : section) + values.second.emplace_back(item.first, item.second); + services.emplace_back(values); + }); return services.size() > 0; } diff --git a/llarp/util/printer.hpp b/llarp/util/printer.hpp index 7ff8247e3..00296b3a7 100644 --- a/llarp/util/printer.hpp +++ b/llarp/util/printer.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace llarp { diff --git a/llarp/util/str.cpp b/llarp/util/str.cpp index 5676c222b..94e1926fa 100644 --- a/llarp/util/str.cpp +++ b/llarp/util/str.cpp @@ -62,22 +62,22 @@ namespace llarp } constexpr static char whitespace[] = " \t\n\r\f\v"; - void - TrimWhiteSpace(std::string& str) + + string_view + TrimWhiteSpace(string_view str) { size_t begin = str.find_first_not_of(whitespace); - if(begin == std::string::npos) - { - str.clear(); - return; - } - size_t end = str.find_last_not_of(whitespace) + 1; - if(begin == 0) - str.resize(end); - else + if(begin == string_view::npos) { - std::copy(str.begin() + begin, str.begin() + end, str.begin()); - str.resize(end - begin); + str.remove_prefix(str.size()); + return str; } + str.remove_prefix(begin); + + size_t end = str.find_last_not_of(whitespace); + if(end != string_view::npos) + str.remove_suffix(str.size() - end - 1); + + return str; } } // namespace llarp diff --git a/llarp/util/str.hpp b/llarp/util/str.hpp index fdb006233..01e5b8f70 100644 --- a/llarp/util/str.hpp +++ b/llarp/util/str.hpp @@ -20,10 +20,13 @@ namespace llarp bool IsTrueValue(string_view str); - /// Trim leading and trailing (ascii) whitespace from the given string; the - /// string is modified in-place. - void - TrimWhiteSpace(std::string &str); + /// Trim leading and trailing (ascii) whitespace from the given string; + /// returns a string_view of the trimmed part of the string. +#ifdef __GNUG__ + [[gnu::warn_unused_result]] +#endif + string_view + TrimWhiteSpace(string_view str); } // namespace llarp diff --git a/llarp/util/string_view.hpp b/llarp/util/string_view.hpp index 8478ef927..84d750d7d 100644 --- a/llarp/util/string_view.hpp +++ b/llarp/util/string_view.hpp @@ -1,17 +1,215 @@ #ifndef LLARP_STRING_VIEW_HPP #define LLARP_STRING_VIEW_HPP -#include -#include -namespace llarp -{ - using string_view = absl::string_view; - using string_view_hash = absl::Hash< string_view >; - - static std::string - string_view_string(const string_view& v) - { - return std::string(v); - } -} // namespace llarp +// Copied from loki-mq (with namespaces modified); when we fully import loki-mq +// we can just use it directly. + +// To keep this identical to loki-mq's copy (e.g. to be able to diff it): +// +// clang-format off + +#include + +#ifdef __cpp_lib_string_view + +#include +namespace llarp { using string_view = std::string_view; } + +#else + +#include +#include + +namespace llarp { + +/// Basic implementation of std::string_view (except for std::hash support). +class simple_string_view { + const char *data_; + size_t size_; +public: + using traits_type = std::char_traits; + using value_type = char; + using pointer = char*; + using const_pointer = const char*; + using reference = char&; + using const_reference = const char&; + using const_iterator = const_pointer; + using iterator = const_iterator; + using const_reverse_iterator = std::reverse_iterator; + using reverse_iterator = const_reverse_iterator; + using size_type = std::size_t; + using different_type = std::ptrdiff_t; + + static constexpr auto& npos = std::string::npos; + + constexpr simple_string_view() noexcept : data_{nullptr}, size_{0} {} + constexpr simple_string_view(const simple_string_view&) noexcept = default; + simple_string_view(const std::string& str) : data_{str.data()}, size_{str.size()} {} + constexpr simple_string_view(const char* data, size_t size) noexcept : data_{data}, size_{size} {} + simple_string_view(const char* data) : data_{data}, size_{traits_type::length(data)} {} + simple_string_view& operator=(const simple_string_view&) = default; + constexpr const char* data() const noexcept { return data_; } + constexpr size_t size() const noexcept { return size_; } + constexpr size_t length() const noexcept { return size_; } + constexpr size_t max_size() const noexcept { return std::numeric_limits::max(); } + constexpr bool empty() const noexcept { return size_ == 0; } + operator std::string() const { return {data_, size_}; } + const char* begin() const noexcept { return data_; } + const char* cbegin() const noexcept { return data_; } + const char* end() const noexcept { return data_ + size_; } + const char* cend() const noexcept { return data_ + size_; } + reverse_iterator rbegin() const { return reverse_iterator{end()}; } + reverse_iterator crbegin() const { return reverse_iterator{end()}; } + reverse_iterator rend() const { return reverse_iterator{begin()}; } + reverse_iterator crend() const { return reverse_iterator{begin()}; } + constexpr const char& operator[](size_t pos) const { return data_[pos]; } + constexpr const char& front() const { return *data_; } + constexpr const char& back() const { return data_[size_ - 1]; } + int compare(simple_string_view s) const; + constexpr void remove_prefix(size_t n) { data_ += n; size_ -= n; } + constexpr void remove_suffix(size_t n) { size_ -= n; } + void swap(simple_string_view &s) noexcept { std::swap(data_, s.data_); std::swap(size_, s.size_); } + + constexpr const char& at(size_t pos) const { + if (pos >= size()) + throw std::out_of_range{"invalid string_view index"}; + return data_[pos]; + }; + + size_t copy(char* dest, size_t count, size_t pos = 0) const { + if (pos > size()) throw std::out_of_range{"invalid copy pos"}; + size_t rcount = std::min(count, size_ - pos); + traits_type::copy(dest, data_ + pos, rcount); + return rcount; + } + + constexpr simple_string_view substr(size_t pos = 0, size_t count = npos) const { + if (pos > size()) throw std::out_of_range{"invalid substr range"}; + simple_string_view result = *this; + if (pos > 0) result.remove_prefix(pos); + if (count < result.size()) result.remove_suffix(result.size() - count); + return result; + } + + constexpr size_t find(simple_string_view v, size_t pos = 0) const noexcept { + if (pos > size_ || v.size_ > size_) return npos; + for (const size_t max_pos = size_ - v.size_; pos <= max_pos; ++pos) { + if (0 == traits_type::compare(v.data_, data_ + pos, v.size_)) + return pos; + } + return npos; + } + constexpr size_t find(char c, size_t pos = 0) const noexcept { return find({&c, 1}, pos); } + constexpr size_t find(const char* c, size_t pos, size_t count) const { return find({c, count}, pos); } + size_t find(const char* c, size_t pos = 0) const { return find(simple_string_view(c), pos); } + + constexpr size_t rfind(simple_string_view v, size_t pos = npos) const noexcept { + if (v.size_ > size_) return npos; + const size_t max_pos = size_ - v.size_; + for (pos = std::min(pos, max_pos); pos <= max_pos; --pos) { + if (0 == traits_type::compare(v.data_, data_ + pos, v.size_)) + return pos; + } + return npos; + } + constexpr size_t rfind(char c, size_t pos = npos) const noexcept { return rfind({&c, 1}, pos); } + constexpr size_t rfind(const char* c, size_t pos, size_t count) const { return rfind({c, count}, pos); } + size_t rfind(const char* c, size_t pos = npos) const { return rfind(simple_string_view(c), pos); } + + constexpr size_t find_first_of(simple_string_view v, size_t pos = 0) const noexcept { + for (; pos < size_; ++pos) + for (char c : v) + if (data_[pos] == c) + return pos; + return npos; + } + constexpr size_t find_first_of(char c, size_t pos = 0) const noexcept { return find_first_of({&c, 1}, pos); } + constexpr size_t find_first_of(const char* c, size_t pos, size_t count) const { return find_first_of({c, count}, pos); } + size_t find_first_of(const char* c, size_t pos = 0) const { return find_first_of(simple_string_view(c), pos); } + + constexpr size_t find_last_of(simple_string_view v, const size_t pos = npos) const noexcept { + if (size_ == 0) return npos; + const size_t last_pos = std::min(pos, size_-1); + for (size_t i = last_pos; i <= last_pos; --i) + for (char c : v) + if (data_[i] == c) + return i; + return npos; + } + constexpr size_t find_last_of(char c, size_t pos = npos) const noexcept { return find_last_of({&c, 1}, pos); } + constexpr size_t find_last_of(const char* c, size_t pos, size_t count) const { return find_last_of({c, count}, pos); } + size_t find_last_of(const char* c, size_t pos = npos) const { return find_last_of(simple_string_view(c), pos); } + + constexpr size_t find_first_not_of(simple_string_view v, size_t pos = 0) const noexcept { + for (; pos < size_; ++pos) { + bool none = true; + for (char c : v) { + if (data_[pos] == c) { + none = false; + break; + } + } + if (none) return pos; + } + return npos; + } + constexpr size_t find_first_not_of(char c, size_t pos = 0) const noexcept { return find_first_not_of({&c, 1}, pos); } + constexpr size_t find_first_not_of(const char* c, size_t pos, size_t count) const { return find_first_not_of({c, count}, pos); } + size_t find_first_not_of(const char* c, size_t pos = 0) const { return find_first_not_of(simple_string_view(c), pos); } + + constexpr size_t find_last_not_of(simple_string_view v, const size_t pos = npos) const noexcept { + if (size_ == 0) return npos; + const size_t last_pos = std::min(pos, size_-1); + for (size_t i = last_pos; i <= last_pos; --i) { + bool none = true; + for (char c : v) { + if (data_[i] == c) { + none = false; + break; + } + } + if (none) return i; + } + return npos; + } + constexpr size_t find_last_not_of(char c, size_t pos = npos) const noexcept { return find_last_not_of({&c, 1}, pos); } + constexpr size_t find_last_not_of(const char* c, size_t pos, size_t count) const { return find_last_not_of({c, count}, pos); } + size_t find_last_not_of(const char* c, size_t pos = npos) const { return find_last_not_of(simple_string_view(c), pos); } +}; +inline bool operator==(simple_string_view lhs, simple_string_view rhs) { + return lhs.size() == rhs.size() && 0 == std::char_traits::compare(lhs.data(), rhs.data(), lhs.size()); +}; +inline bool operator!=(simple_string_view lhs, simple_string_view rhs) { + return !(lhs == rhs); +} +inline int simple_string_view::compare(simple_string_view s) const { + int cmp = std::char_traits::compare(data_, s.data(), std::min(size_, s.size())); + if (cmp) return cmp; + if (size_ < s.size()) return -1; + else if (size_ > s.size()) return 1; + return 0; +} +inline bool operator<(simple_string_view lhs, simple_string_view rhs) { + return lhs.compare(rhs) < 0; +}; +inline bool operator<=(simple_string_view lhs, simple_string_view rhs) { + return lhs.compare(rhs) <= 0; +}; +inline bool operator>(simple_string_view lhs, simple_string_view rhs) { + return lhs.compare(rhs) > 0; +}; +inline bool operator>=(simple_string_view lhs, simple_string_view rhs) { + return lhs.compare(rhs) >= 0; +}; +inline std::ostream& operator<<(std::ostream& os, const simple_string_view& s) { + os.write(s.data(), s.size()); + return os; +} + +using string_view = simple_string_view; + +} + +#endif + #endif diff --git a/test/util/test_llarp_util_str.cpp b/test/util/test_llarp_util_str.cpp index d06ca3db1..9a6ec49bd 100644 --- a/test/util/test_llarp_util_str.cpp +++ b/test/util/test_llarp_util_str.cpp @@ -11,7 +11,7 @@ TEST_CASE("TrimWhiteSpace -- positive tests", "[str][trim]") auto fo = "\fthe "s; auto fum = " \t\r\n\v\f Beanstalk\n\n\n\t\r\f\v \n\n\r\f\f\f\f\v"s; for (auto* s: {&fee, &fi, &fo, &fum}) - llarp::TrimWhiteSpace(*s); + *s = llarp::TrimWhiteSpace(*s); REQUIRE( fee == "J a c k" ); REQUIRE( fi == "a\nd" ); @@ -24,7 +24,7 @@ TEST_CASE("TrimWhitespace -- negative tests", "[str][trim]") // Test that things that shouldn't be trimmed don't get trimmed auto c = GENERATE(range(std::numeric_limits::min(), std::numeric_limits::max())); std::string plant = c + "bean"s + c; - llarp::TrimWhiteSpace(plant); + plant = llarp::TrimWhiteSpace(plant); if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v') REQUIRE( plant == "bean" ); else