mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
Use std::string_view and fmtlib across all libraries (#3402)
- Twine, StringRef, Format, and NativeFormatting have been removed - Logging now uses fmtlib style formatting - Nearly all uses of wpi::outs/errs have been replaced with fmt::print() or std::puts()/std::fputs() (for unformatted strings). - A wpi/fmt/raw_ostream.h header has been added to enable fmt::print() with wpi::raw_ostream
This commit is contained in:
@@ -80,17 +80,19 @@ static const unsigned char pr2six[256] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64};
|
||||
|
||||
size_t Base64Decode(raw_ostream& os, StringRef encoded) {
|
||||
const unsigned char* end = encoded.bytes_begin();
|
||||
while (pr2six[*end] <= 63 && end != encoded.bytes_end()) {
|
||||
size_t Base64Decode(raw_ostream& os, std::string_view encoded) {
|
||||
auto bytes_begin = reinterpret_cast<const unsigned char*>(encoded.data());
|
||||
auto bytes_end = bytes_begin + encoded.size();
|
||||
const unsigned char* end = bytes_begin;
|
||||
while (pr2six[*end] <= 63 && end != bytes_end) {
|
||||
++end;
|
||||
}
|
||||
size_t nprbytes = end - encoded.bytes_begin();
|
||||
size_t nprbytes = end - bytes_begin;
|
||||
if (nprbytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const unsigned char* cur = encoded.bytes_begin();
|
||||
const unsigned char* cur = bytes_begin;
|
||||
|
||||
while (nprbytes > 4) {
|
||||
os << static_cast<unsigned char>(pr2six[cur[0]] << 2 | pr2six[cur[1]] >> 4);
|
||||
@@ -111,10 +113,10 @@ size_t Base64Decode(raw_ostream& os, StringRef encoded) {
|
||||
os << static_cast<unsigned char>(pr2six[cur[2]] << 6 | pr2six[cur[3]]);
|
||||
}
|
||||
|
||||
return (end - encoded.bytes_begin()) + ((4 - nprbytes) & 3);
|
||||
return (end - bytes_begin) + ((4 - nprbytes) & 3);
|
||||
}
|
||||
|
||||
size_t Base64Decode(StringRef encoded, std::string* plain) {
|
||||
size_t Base64Decode(std::string_view encoded, std::string* plain) {
|
||||
plain->resize(0);
|
||||
raw_string_ostream os(*plain);
|
||||
size_t rv = Base64Decode(os, encoded);
|
||||
@@ -122,8 +124,8 @@ size_t Base64Decode(StringRef encoded, std::string* plain) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
StringRef Base64Decode(StringRef encoded, size_t* num_read,
|
||||
SmallVectorImpl<char>& buf) {
|
||||
std::string_view Base64Decode(std::string_view encoded, size_t* num_read,
|
||||
SmallVectorImpl<char>& buf) {
|
||||
buf.clear();
|
||||
raw_svector_ostream os(buf);
|
||||
*num_read = Base64Decode(os, encoded);
|
||||
@@ -133,7 +135,7 @@ StringRef Base64Decode(StringRef encoded, size_t* num_read,
|
||||
static const char basis_64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
void Base64Encode(raw_ostream& os, StringRef plain) {
|
||||
void Base64Encode(raw_ostream& os, std::string_view plain) {
|
||||
if (plain.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -162,14 +164,15 @@ void Base64Encode(raw_ostream& os, StringRef plain) {
|
||||
}
|
||||
}
|
||||
|
||||
void Base64Encode(StringRef plain, std::string* encoded) {
|
||||
void Base64Encode(std::string_view plain, std::string* encoded) {
|
||||
encoded->resize(0);
|
||||
raw_string_ostream os(*encoded);
|
||||
Base64Encode(os, plain);
|
||||
os.flush();
|
||||
}
|
||||
|
||||
StringRef Base64Encode(StringRef plain, SmallVectorImpl<char>& buf) {
|
||||
std::string_view Base64Encode(std::string_view plain,
|
||||
SmallVectorImpl<char>& buf) {
|
||||
buf.clear();
|
||||
raw_svector_ostream os(buf);
|
||||
Base64Encode(os, plain);
|
||||
|
||||
@@ -37,7 +37,7 @@ HttpParser::HttpParser(Type type) {
|
||||
if ((self.m_urlBuf.size() + length) > self.m_maxLength) {
|
||||
return 1;
|
||||
}
|
||||
self.m_urlBuf += StringRef{at, length};
|
||||
self.m_urlBuf += std::string_view{at, length};
|
||||
self.m_state = kUrl;
|
||||
return 0;
|
||||
};
|
||||
@@ -50,7 +50,7 @@ HttpParser::HttpParser(Type type) {
|
||||
if ((self.m_valueBuf.size() + length) > self.m_maxLength) {
|
||||
return 1;
|
||||
}
|
||||
self.m_valueBuf += StringRef{at, length};
|
||||
self.m_valueBuf += std::string_view{at, length};
|
||||
self.m_state = kStatus;
|
||||
return 0;
|
||||
};
|
||||
@@ -95,7 +95,7 @@ HttpParser::HttpParser(Type type) {
|
||||
if ((self.m_fieldBuf.size() + length) > self.m_maxLength) {
|
||||
return 1;
|
||||
}
|
||||
self.m_fieldBuf += StringRef{at, length};
|
||||
self.m_fieldBuf += std::string_view{at, length};
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -114,7 +114,7 @@ HttpParser::HttpParser(Type type) {
|
||||
if ((self.m_valueBuf.size() + length) > self.m_maxLength) {
|
||||
return 1;
|
||||
}
|
||||
self.m_valueBuf += StringRef{at, length};
|
||||
self.m_valueBuf += std::string_view{at, length};
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -154,7 +154,7 @@ HttpParser::HttpParser(Type type) {
|
||||
m_settings.on_body = [](http_parser* p, const char* at,
|
||||
size_t length) -> int {
|
||||
auto& self = *static_cast<HttpParser*>(p->data);
|
||||
self.body(StringRef{at, length}, self.IsBodyFinal());
|
||||
self.body(std::string_view{at, length}, self.IsBodyFinal());
|
||||
return self.m_aborted;
|
||||
};
|
||||
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
|
||||
#include "wpi/HttpServerConnection.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/fmt/raw_ostream.h"
|
||||
#include "wpi/raw_uv_ostream.h"
|
||||
|
||||
using namespace wpi;
|
||||
@@ -21,16 +24,18 @@ HttpServerConnection::HttpServerConnection(std::shared_ptr<uv::Stream> stream)
|
||||
|
||||
// look for Accept-Encoding headers to determine if gzip is acceptable
|
||||
m_request.messageBegin.connect([this] { m_acceptGzip = false; });
|
||||
m_request.header.connect([this](StringRef name, StringRef value) {
|
||||
if (name.equals_lower("accept-encoding") && value.contains("gzip")) {
|
||||
m_acceptGzip = true;
|
||||
}
|
||||
});
|
||||
m_request.header.connect(
|
||||
[this](std::string_view name, std::string_view value) {
|
||||
if (wpi::equals_lower(name, "accept-encoding") &&
|
||||
wpi::contains(value, "gzip")) {
|
||||
m_acceptGzip = true;
|
||||
}
|
||||
});
|
||||
|
||||
// pass incoming data to HTTP parser
|
||||
m_dataConn =
|
||||
stream->data.connect_connection([this](uv::Buffer& buf, size_t size) {
|
||||
m_request.Execute(StringRef{buf.base, size});
|
||||
m_request.Execute({buf.base, size});
|
||||
if (m_request.HasError()) {
|
||||
// could not parse; just close the connection
|
||||
m_stream.Close();
|
||||
@@ -54,12 +59,12 @@ void HttpServerConnection::BuildCommonHeaders(raw_ostream& os) {
|
||||
}
|
||||
|
||||
void HttpServerConnection::BuildHeader(raw_ostream& os, int code,
|
||||
const Twine& codeText,
|
||||
const Twine& contentType,
|
||||
std::string_view codeText,
|
||||
std::string_view contentType,
|
||||
uint64_t contentLength,
|
||||
const Twine& extra) {
|
||||
os << "HTTP/" << m_request.GetMajor() << '.' << m_request.GetMinor() << ' '
|
||||
<< code << ' ' << codeText << "\r\n";
|
||||
std::string_view extra) {
|
||||
fmt::print(os, "HTTP/{}.{} {} {}\r\n", m_request.GetMajor(),
|
||||
m_request.GetMinor(), code, codeText);
|
||||
if (contentLength == 0) {
|
||||
m_keepAlive = false;
|
||||
}
|
||||
@@ -69,13 +74,11 @@ void HttpServerConnection::BuildHeader(raw_ostream& os, int code,
|
||||
BuildCommonHeaders(os);
|
||||
os << "Content-Type: " << contentType << "\r\n";
|
||||
if (contentLength != 0) {
|
||||
os << "Content-Length: " << contentLength << "\r\n";
|
||||
fmt::print(os, "Content-Length: {}\r\n", contentLength);
|
||||
}
|
||||
os << "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: *\r\n";
|
||||
SmallString<128> extraBuf;
|
||||
StringRef extraStr = extra.toStringRef(extraBuf);
|
||||
if (!extraStr.empty()) {
|
||||
os << extraStr;
|
||||
if (!extra.empty()) {
|
||||
os << extra;
|
||||
}
|
||||
os << "\r\n"; // header ends with a blank line
|
||||
}
|
||||
@@ -93,10 +96,10 @@ void HttpServerConnection::SendData(ArrayRef<uv::Buffer> bufs,
|
||||
});
|
||||
}
|
||||
|
||||
void HttpServerConnection::SendResponse(int code, const Twine& codeText,
|
||||
const Twine& contentType,
|
||||
StringRef content,
|
||||
const Twine& extraHeader) {
|
||||
void HttpServerConnection::SendResponse(int code, std::string_view codeText,
|
||||
std::string_view contentType,
|
||||
std::string_view content,
|
||||
std::string_view extraHeader) {
|
||||
SmallVector<uv::Buffer, 4> toSend;
|
||||
raw_uv_ostream os{toSend, 4096};
|
||||
BuildHeader(os, code, codeText, contentType, content.size(), extraHeader);
|
||||
@@ -105,13 +108,12 @@ void HttpServerConnection::SendResponse(int code, const Twine& codeText,
|
||||
SendData(os.bufs(), !m_keepAlive);
|
||||
}
|
||||
|
||||
void HttpServerConnection::SendStaticResponse(int code, const Twine& codeText,
|
||||
const Twine& contentType,
|
||||
StringRef content, bool gzipped,
|
||||
const Twine& extraHeader) {
|
||||
void HttpServerConnection::SendStaticResponse(
|
||||
int code, std::string_view codeText, std::string_view contentType,
|
||||
std::string_view content, bool gzipped, std::string_view extraHeader) {
|
||||
// TODO: handle remote side not accepting gzip (very rare)
|
||||
|
||||
StringRef contentEncodingHeader;
|
||||
std::string_view contentEncodingHeader;
|
||||
if (gzipped /* && m_acceptGzip*/) {
|
||||
contentEncodingHeader = "Content-Encoding: gzip\r\n";
|
||||
}
|
||||
@@ -119,7 +121,7 @@ void HttpServerConnection::SendStaticResponse(int code, const Twine& codeText,
|
||||
SmallVector<uv::Buffer, 4> bufs;
|
||||
raw_uv_ostream os{bufs, 4096};
|
||||
BuildHeader(os, code, codeText, contentType, content.size(),
|
||||
extraHeader + contentEncodingHeader);
|
||||
fmt::format("{}{}", extraHeader, contentEncodingHeader));
|
||||
// can send content without copying
|
||||
bufs.emplace_back(content);
|
||||
|
||||
@@ -135,8 +137,8 @@ void HttpServerConnection::SendStaticResponse(int code, const Twine& codeText,
|
||||
});
|
||||
}
|
||||
|
||||
void HttpServerConnection::SendError(int code, const Twine& message) {
|
||||
StringRef codeText, extra, baseMessage;
|
||||
void HttpServerConnection::SendError(int code, std::string_view message) {
|
||||
std::string_view codeText, extra, baseMessage;
|
||||
switch (code) {
|
||||
case 401:
|
||||
codeText = "Unauthorized";
|
||||
@@ -169,8 +171,8 @@ void HttpServerConnection::SendError(int code, const Twine& message) {
|
||||
baseMessage = "501: Not Implemented!";
|
||||
break;
|
||||
}
|
||||
SmallString<256> content = baseMessage;
|
||||
SmallString<256> content{baseMessage};
|
||||
content += "\r\n";
|
||||
message.toVector(content);
|
||||
SendResponse(code, codeText, "text/plain", content, extra);
|
||||
content += message;
|
||||
SendResponse(code, codeText, "text/plain", content.str(), extra);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <cctype>
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/Base64.h"
|
||||
#include "wpi/STLExtras.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
@@ -14,12 +15,10 @@
|
||||
|
||||
namespace wpi {
|
||||
|
||||
StringRef UnescapeURI(const Twine& str, SmallVectorImpl<char>& buf,
|
||||
bool* error) {
|
||||
SmallString<128> strBuf;
|
||||
StringRef strStr = str.toStringRef(strBuf);
|
||||
std::string_view UnescapeURI(std::string_view str, SmallVectorImpl<char>& buf,
|
||||
bool* error) {
|
||||
buf.clear();
|
||||
for (auto i = strStr.begin(), end = strStr.end(); i != end; ++i) {
|
||||
for (auto i = str.begin(), end = str.end(); i != end; ++i) {
|
||||
// pass non-escaped characters to output
|
||||
if (*i != '%') {
|
||||
// decode + to space
|
||||
@@ -34,35 +33,33 @@ StringRef UnescapeURI(const Twine& str, SmallVectorImpl<char>& buf,
|
||||
// are there enough characters left?
|
||||
if (i + 2 >= end) {
|
||||
*error = true;
|
||||
return StringRef{};
|
||||
return {};
|
||||
}
|
||||
|
||||
// replace %xx with the corresponding character
|
||||
unsigned val1 = hexDigitValue(*++i);
|
||||
if (val1 == -1U) {
|
||||
*error = true;
|
||||
return StringRef{};
|
||||
return {};
|
||||
}
|
||||
unsigned val2 = hexDigitValue(*++i);
|
||||
if (val2 == -1U) {
|
||||
*error = true;
|
||||
return StringRef{};
|
||||
return {};
|
||||
}
|
||||
buf.push_back((val1 << 4) | val2);
|
||||
}
|
||||
|
||||
*error = false;
|
||||
return StringRef{buf.data(), buf.size()};
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
StringRef EscapeURI(const Twine& str, SmallVectorImpl<char>& buf,
|
||||
bool spacePlus) {
|
||||
std::string_view EscapeURI(std::string_view str, SmallVectorImpl<char>& buf,
|
||||
bool spacePlus) {
|
||||
static const char* const hexLut = "0123456789ABCDEF";
|
||||
|
||||
SmallString<128> strBuf;
|
||||
StringRef strStr = str.toStringRef(strBuf);
|
||||
buf.clear();
|
||||
for (auto i = strStr.begin(), end = strStr.end(); i != end; ++i) {
|
||||
for (auto i = str.begin(), end = str.end(); i != end; ++i) {
|
||||
// pass unreserved characters to output
|
||||
if (std::isalnum(*i) || *i == '-' || *i == '_' || *i == '.' || *i == '~') {
|
||||
buf.push_back(*i);
|
||||
@@ -81,15 +78,15 @@ StringRef EscapeURI(const Twine& str, SmallVectorImpl<char>& buf,
|
||||
buf.push_back(hexLut[(*i) & 0x0f]);
|
||||
}
|
||||
|
||||
return StringRef{buf.data(), buf.size()};
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
HttpQueryMap::HttpQueryMap(wpi::StringRef query) {
|
||||
wpi::SmallVector<wpi::StringRef, 16> queryElems;
|
||||
query.split(queryElems, '&', 100, false);
|
||||
HttpQueryMap::HttpQueryMap(std::string_view query) {
|
||||
SmallVector<std::string_view, 16> queryElems;
|
||||
split(query, queryElems, '&', 100, false);
|
||||
for (auto elem : queryElems) {
|
||||
auto [nameEsc, valueEsc] = elem.split('=');
|
||||
wpi::SmallString<64> nameBuf;
|
||||
auto [nameEsc, valueEsc] = split(elem, '=');
|
||||
SmallString<64> nameBuf;
|
||||
bool err = false;
|
||||
auto name = wpi::UnescapeURI(nameEsc, nameBuf, &err);
|
||||
// note: ignores duplicates
|
||||
@@ -99,8 +96,8 @@ HttpQueryMap::HttpQueryMap(wpi::StringRef query) {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<wpi::StringRef> HttpQueryMap::Get(
|
||||
wpi::StringRef name, wpi::SmallVectorImpl<char>& buf) const {
|
||||
std::optional<std::string_view> HttpQueryMap::Get(
|
||||
std::string_view name, wpi::SmallVectorImpl<char>& buf) const {
|
||||
auto it = m_elems.find(name);
|
||||
if (it == m_elems.end()) {
|
||||
return {};
|
||||
@@ -113,16 +110,16 @@ std::optional<wpi::StringRef> HttpQueryMap::Get(
|
||||
return val;
|
||||
}
|
||||
|
||||
HttpPath::HttpPath(wpi::StringRef path) {
|
||||
HttpPath::HttpPath(std::string_view path) {
|
||||
// special-case root path to be a single empty element
|
||||
if (path == "/") {
|
||||
m_pathEnds.emplace_back(0);
|
||||
return;
|
||||
}
|
||||
wpi::SmallVector<wpi::StringRef, 16> pathElems;
|
||||
path.split(pathElems, '/', 100, false);
|
||||
wpi::SmallVector<std::string_view, 16> pathElems;
|
||||
split(path, pathElems, '/', 100, false);
|
||||
for (auto elem : pathElems) {
|
||||
wpi::SmallString<64> buf;
|
||||
SmallString<64> buf;
|
||||
bool err = false;
|
||||
auto val = wpi::UnescapeURI(elem, buf, &err);
|
||||
if (err) {
|
||||
@@ -134,14 +131,15 @@ HttpPath::HttpPath(wpi::StringRef path) {
|
||||
}
|
||||
}
|
||||
|
||||
bool HttpPath::startswith(size_t start, ArrayRef<StringRef> match) const {
|
||||
bool HttpPath::startswith(size_t start,
|
||||
ArrayRef<std::string_view> match) const {
|
||||
if (m_pathEnds.size() < (start + match.size())) {
|
||||
return false;
|
||||
}
|
||||
bool first = start == 0;
|
||||
auto p = m_pathEnds.begin() + start;
|
||||
for (auto m : match) {
|
||||
auto val = m_pathBuf.slice(first ? 0 : *(p - 1), *p);
|
||||
auto val = slice(m_pathBuf, first ? 0 : *(p - 1), *p);
|
||||
if (val != m) {
|
||||
return false;
|
||||
}
|
||||
@@ -151,6 +149,10 @@ bool HttpPath::startswith(size_t start, ArrayRef<StringRef> match) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string_view HttpPath::operator[](size_t n) const {
|
||||
return slice(m_pathBuf, n == 0 ? 0 : m_pathEnds[n - 1], m_pathEnds[n]);
|
||||
}
|
||||
|
||||
bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
|
||||
SmallVectorImpl<char>* contentLength) {
|
||||
if (contentType) {
|
||||
@@ -164,7 +166,7 @@ bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
|
||||
bool inContentLength = false;
|
||||
SmallString<64> lineBuf;
|
||||
for (;;) {
|
||||
StringRef line = is.getline(lineBuf, 1024).rtrim();
|
||||
std::string_view line = rtrim(is.getline(lineBuf, 1024));
|
||||
if (is.has_error()) {
|
||||
return false;
|
||||
}
|
||||
@@ -176,12 +178,12 @@ bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
|
||||
if (!std::isspace(line[0])) {
|
||||
inContentType = false;
|
||||
inContentLength = false;
|
||||
StringRef field;
|
||||
std::tie(field, line) = line.split(':');
|
||||
field = field.rtrim();
|
||||
if (field.equals_lower("content-type")) {
|
||||
std::string_view field;
|
||||
std::tie(field, line) = split(line, ':');
|
||||
field = rtrim(field);
|
||||
if (equals_lower(field, "content-type")) {
|
||||
inContentType = true;
|
||||
} else if (field.equals_lower("content-length")) {
|
||||
} else if (equals_lower(field, "content-length")) {
|
||||
inContentLength = true;
|
||||
} else {
|
||||
continue; // ignore other fields
|
||||
@@ -189,7 +191,7 @@ bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
|
||||
}
|
||||
|
||||
// collapse whitespace
|
||||
line = line.ltrim();
|
||||
line = ltrim(line);
|
||||
|
||||
// save field data
|
||||
if (inContentType && contentType) {
|
||||
@@ -200,7 +202,7 @@ bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
|
||||
}
|
||||
}
|
||||
|
||||
bool FindMultipartBoundary(raw_istream& is, StringRef boundary,
|
||||
bool FindMultipartBoundary(raw_istream& is, std::string_view boundary,
|
||||
std::string* saveBuf) {
|
||||
SmallString<64> searchBuf;
|
||||
searchBuf.resize(boundary.size() + 2);
|
||||
@@ -237,7 +239,7 @@ bool FindMultipartBoundary(raw_istream& is, StringRef boundary,
|
||||
|
||||
// Fast-scan for '-'
|
||||
size_t pos = searchBuf.find('-', searchBuf[0] == '-' ? 1 : 0);
|
||||
if (pos == StringRef::npos) {
|
||||
if (pos == std::string_view::npos) {
|
||||
if (saveBuf) {
|
||||
saveBuf->append(searchBuf.data(), searchBuf.size());
|
||||
}
|
||||
@@ -254,63 +256,58 @@ bool FindMultipartBoundary(raw_istream& is, StringRef boundary,
|
||||
}
|
||||
}
|
||||
|
||||
HttpLocation::HttpLocation(const Twine& url_, bool* error,
|
||||
HttpLocation::HttpLocation(std::string_view url_, bool* error,
|
||||
std::string* errorMsg)
|
||||
: url{url_.str()} {
|
||||
: url{url_} {
|
||||
// Split apart into components
|
||||
StringRef query{url};
|
||||
std::string_view query{url};
|
||||
|
||||
// scheme:
|
||||
StringRef scheme;
|
||||
std::tie(scheme, query) = query.split(':');
|
||||
if (!scheme.equals_lower("http")) {
|
||||
std::string_view scheme;
|
||||
std::tie(scheme, query) = split(query, ':');
|
||||
if (!equals_lower(scheme, "http")) {
|
||||
*errorMsg = "only supports http URLs";
|
||||
*error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// "//"
|
||||
if (!query.startswith("//")) {
|
||||
if (!starts_with(query, "//")) {
|
||||
*errorMsg = "expected http://...";
|
||||
*error = true;
|
||||
return;
|
||||
}
|
||||
query = query.drop_front(2);
|
||||
query.remove_prefix(2);
|
||||
|
||||
// user:password@host:port/
|
||||
StringRef authority;
|
||||
std::tie(authority, query) = query.split('/');
|
||||
std::string_view authority;
|
||||
std::tie(authority, query) = split(query, '/');
|
||||
|
||||
StringRef userpass, hostport;
|
||||
std::tie(userpass, hostport) = authority.split('@');
|
||||
auto [userpass, hostport] = split(authority, '@');
|
||||
// split leaves the RHS empty if the split char isn't present...
|
||||
if (hostport.empty()) {
|
||||
hostport = userpass;
|
||||
userpass = StringRef{};
|
||||
userpass = {};
|
||||
}
|
||||
|
||||
if (!userpass.empty()) {
|
||||
StringRef rawUser, rawPassword;
|
||||
std::tie(rawUser, rawPassword) = userpass.split(':');
|
||||
auto [rawUser, rawPassword] = split(userpass, ':');
|
||||
SmallString<64> userBuf, passBuf;
|
||||
user = UnescapeURI(rawUser, userBuf, error);
|
||||
if (*error) {
|
||||
raw_string_ostream oss(*errorMsg);
|
||||
oss << "could not unescape user \"" << rawUser << "\"";
|
||||
oss.flush();
|
||||
*errorMsg = fmt::format("could not unescape user \"{}\"", rawUser);
|
||||
return;
|
||||
}
|
||||
password = UnescapeURI(rawPassword, passBuf, error);
|
||||
if (*error) {
|
||||
raw_string_ostream oss(*errorMsg);
|
||||
oss << "could not unescape password \"" << rawPassword << "\"";
|
||||
oss.flush();
|
||||
*errorMsg =
|
||||
fmt::format("could not unescape password \"{}\"", rawPassword);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StringRef portStr;
|
||||
std::tie(host, portStr) = hostport.rsplit(':');
|
||||
std::string_view portStr;
|
||||
std::tie(host, portStr) = rsplit(hostport, ':');
|
||||
if (host.empty()) {
|
||||
*errorMsg = "host is empty";
|
||||
*error = true;
|
||||
@@ -318,46 +315,42 @@ HttpLocation::HttpLocation(const Twine& url_, bool* error,
|
||||
}
|
||||
if (portStr.empty()) {
|
||||
port = 80;
|
||||
} else if (portStr.getAsInteger(10, port)) {
|
||||
raw_string_ostream oss(*errorMsg);
|
||||
oss << "port \"" << portStr << "\" is not an integer";
|
||||
oss.flush();
|
||||
} else if (auto p = parse_integer<int>(portStr, 10)) {
|
||||
port = p.value();
|
||||
} else {
|
||||
*errorMsg = fmt::format("port \"{}\" is not an integer", portStr);
|
||||
*error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// path?query#fragment
|
||||
std::tie(query, fragment) = query.split('#');
|
||||
std::tie(path, query) = query.split('?');
|
||||
std::tie(query, fragment) = split(query, '#');
|
||||
std::tie(path, query) = split(query, '?');
|
||||
|
||||
// Split query string into parameters
|
||||
while (!query.empty()) {
|
||||
// split out next param and value
|
||||
StringRef rawParam, rawValue;
|
||||
std::tie(rawParam, query) = query.split('&');
|
||||
std::string_view rawParam, rawValue;
|
||||
std::tie(rawParam, query) = split(query, '&');
|
||||
if (rawParam.empty()) {
|
||||
continue; // ignore "&&"
|
||||
}
|
||||
std::tie(rawParam, rawValue) = rawParam.split('=');
|
||||
std::tie(rawParam, rawValue) = split(rawParam, '=');
|
||||
|
||||
// unescape param
|
||||
*error = false;
|
||||
SmallString<64> paramBuf;
|
||||
StringRef param = UnescapeURI(rawParam, paramBuf, error);
|
||||
std::string_view param = UnescapeURI(rawParam, paramBuf, error);
|
||||
if (*error) {
|
||||
raw_string_ostream oss(*errorMsg);
|
||||
oss << "could not unescape parameter \"" << rawParam << "\"";
|
||||
oss.flush();
|
||||
*errorMsg = fmt::format("could not unescape parameter \"{}\"", rawParam);
|
||||
return;
|
||||
}
|
||||
|
||||
// unescape value
|
||||
SmallString<64> valueBuf;
|
||||
StringRef value = UnescapeURI(rawValue, valueBuf, error);
|
||||
std::string_view value = UnescapeURI(rawValue, valueBuf, error);
|
||||
if (*error) {
|
||||
raw_string_ostream oss(*errorMsg);
|
||||
oss << "could not unescape value \"" << rawValue << "\"";
|
||||
oss.flush();
|
||||
*errorMsg = fmt::format("could not unescape value \"{}\"", rawValue);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -373,7 +366,7 @@ void HttpRequest::SetAuth(const HttpLocation& loc) {
|
||||
userpass += loc.user;
|
||||
userpass += ':';
|
||||
userpass += loc.password;
|
||||
Base64Encode(userpass, &auth);
|
||||
Base64Encode(userpass.str(), &auth);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,24 +383,22 @@ bool HttpConnection::Handshake(const HttpRequest& request,
|
||||
|
||||
// read first line of response
|
||||
SmallString<64> lineBuf;
|
||||
StringRef line = is.getline(lineBuf, 1024).rtrim();
|
||||
std::string_view line = rtrim(is.getline(lineBuf, 1024));
|
||||
if (is.has_error()) {
|
||||
*warnMsg = "disconnected before response";
|
||||
return false;
|
||||
}
|
||||
|
||||
// see if we got a HTTP 200 response
|
||||
StringRef httpver, code, codeText;
|
||||
std::tie(httpver, line) = line.split(' ');
|
||||
std::tie(code, codeText) = line.split(' ');
|
||||
if (!httpver.startswith("HTTP")) {
|
||||
std::string_view httpver, code, codeText;
|
||||
std::tie(httpver, line) = split(line, ' ');
|
||||
std::tie(code, codeText) = split(line, ' ');
|
||||
if (!starts_with(httpver, "HTTP")) {
|
||||
*warnMsg = "did not receive HTTP response";
|
||||
return false;
|
||||
}
|
||||
if (code != "200") {
|
||||
raw_string_ostream oss(*warnMsg);
|
||||
oss << "received " << code << " " << codeText << " response";
|
||||
oss.flush();
|
||||
*warnMsg = fmt::format("received {} {} response", code, codeText);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -420,7 +411,7 @@ bool HttpConnection::Handshake(const HttpRequest& request,
|
||||
return true;
|
||||
}
|
||||
|
||||
void HttpMultipartScanner::SetBoundary(StringRef boundary) {
|
||||
void HttpMultipartScanner::SetBoundary(std::string_view boundary) {
|
||||
m_boundaryWith = "\n--";
|
||||
m_boundaryWith += boundary;
|
||||
m_boundaryWithout = "\n";
|
||||
@@ -436,7 +427,7 @@ void HttpMultipartScanner::Reset(bool saveSkipped) {
|
||||
m_buf.resize(0);
|
||||
}
|
||||
|
||||
StringRef HttpMultipartScanner::Execute(StringRef in) {
|
||||
std::string_view HttpMultipartScanner::Execute(std::string_view in) {
|
||||
if (m_state == kDone) {
|
||||
Reset(m_saveSkipped);
|
||||
}
|
||||
@@ -483,7 +474,7 @@ StringRef HttpMultipartScanner::Execute(StringRef in) {
|
||||
}
|
||||
|
||||
if (m_state == kPadding) {
|
||||
for (char ch : in.drop_front(pos)) {
|
||||
for (char ch : drop_front(in, pos)) {
|
||||
++pos;
|
||||
if (ch == '\n') {
|
||||
// Found the LF; return remaining input buffer (following it)
|
||||
@@ -491,13 +482,13 @@ StringRef HttpMultipartScanner::Execute(StringRef in) {
|
||||
if (m_saveSkipped) {
|
||||
m_buf.resize(m_buf.size() - in.size() + pos);
|
||||
}
|
||||
return in.drop_front(pos);
|
||||
return drop_front(in, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We consumed the entire input
|
||||
return StringRef{};
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
26
wpiutil/src/main/native/cpp/Logger.cpp
Normal file
26
wpiutil/src/main/native/cpp/Logger.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpi/Logger.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
void Logger::DoLog(unsigned int level, const char* file, unsigned int line,
|
||||
const char* msg) {
|
||||
if (!m_func || level < m_min_level) {
|
||||
return;
|
||||
}
|
||||
m_func(level, file, line, msg);
|
||||
}
|
||||
|
||||
void Logger::LogV(unsigned int level, const char* file, unsigned int line,
|
||||
fmt::string_view format, fmt::format_args args) {
|
||||
if (!m_func || level < m_min_level) {
|
||||
return;
|
||||
}
|
||||
fmt::memory_buffer out;
|
||||
fmt::vformat_to(out, format, args);
|
||||
out.push_back('\0');
|
||||
m_func(level, file, line, out.data());
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace wpi {
|
||||
|
||||
// derived partially from
|
||||
// https://github.com/DEGoodmanWilson/libmime/blob/stable/0.1.2/mime/mime.cpp
|
||||
StringRef MimeTypeFromPath(StringRef path) {
|
||||
std::string_view MimeTypeFromPath(std::string_view path) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
|
||||
static StringMap<const char*> mimeTypes{
|
||||
// text
|
||||
@@ -52,11 +52,11 @@ StringRef MimeTypeFromPath(StringRef path) {
|
||||
static const char* defaultType = "application/octet-stream";
|
||||
|
||||
auto pos = path.find_last_of("/");
|
||||
if (pos != StringRef::npos) {
|
||||
if (pos != std::string_view::npos) {
|
||||
path = path.substr(pos + 1);
|
||||
}
|
||||
auto dot_pos = path.find_last_of(".");
|
||||
if (dot_pos > 0 && dot_pos != StringRef::npos) {
|
||||
if (dot_pos > 0 && dot_pos != std::string_view::npos) {
|
||||
auto type = mimeTypes.find(path.substr(dot_pos + 1));
|
||||
if (type != mimeTypes.end()) {
|
||||
return type->getValue();
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
|
||||
#include "wpi/PortForwarder.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/DenseMap.h"
|
||||
#include "wpi/EventLoopRunner.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "wpi/uv/GetAddrInfo.h"
|
||||
#include "wpi/uv/Tcp.h"
|
||||
#include "wpi/uv/Timer.h"
|
||||
@@ -45,7 +44,7 @@ static void CopyStream(uv::Stream& in, std::weak_ptr<uv::Stream> outWeak) {
|
||||
});
|
||||
}
|
||||
|
||||
void PortForwarder::Add(unsigned int port, const Twine& remoteHost,
|
||||
void PortForwarder::Add(unsigned int port, std::string_view remoteHost,
|
||||
unsigned int remotePort) {
|
||||
m_impl->runner.ExecSync([&](uv::Loop& loop) {
|
||||
auto server = uv::Tcp::Create(loop);
|
||||
@@ -55,7 +54,7 @@ void PortForwarder::Add(unsigned int port, const Twine& remoteHost,
|
||||
|
||||
// when we get a connection, accept it
|
||||
server->connection.connect([serverPtr = server.get(),
|
||||
host = remoteHost.str(), remotePort] {
|
||||
host = std::string{remoteHost}, remotePort] {
|
||||
auto& loop = serverPtr->GetLoopRef();
|
||||
auto client = serverPtr->Accept();
|
||||
if (!client) {
|
||||
@@ -80,10 +79,6 @@ void PortForwarder::Add(unsigned int port, const Twine& remoteHost,
|
||||
}
|
||||
});
|
||||
|
||||
// convert port to string
|
||||
SmallString<16> remotePortStr;
|
||||
raw_svector_ostream(remotePortStr) << remotePort;
|
||||
|
||||
// resolve address
|
||||
uv::GetAddrInfo(
|
||||
loop,
|
||||
@@ -125,7 +120,7 @@ void PortForwarder::Add(unsigned int port, const Twine& remoteHost,
|
||||
CopyStream(*remotePtr, clientWeak);
|
||||
});
|
||||
},
|
||||
host, remotePortStr);
|
||||
host, fmt::to_string(remotePort));
|
||||
|
||||
// time out for connection
|
||||
uv::Timer::SingleShot(loop, uv::Timer::Time{500},
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
|
||||
// strncasecmp() is not available on non-POSIX systems, so define an
|
||||
// alternative function here.
|
||||
@@ -178,34 +177,143 @@ void wpi::split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
}
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsUnsignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
unsigned long long& result) noexcept { // NOLINT(runtime/int)
|
||||
return wpi::getAsUnsignedInteger(str, radix, result);
|
||||
}
|
||||
static unsigned GetAutoSenseRadix(std::string_view& str) noexcept {
|
||||
if (str.empty()) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsSignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
long long& result) noexcept { // NOLINT(runtime/int)
|
||||
return wpi::getAsSignedInteger(str, radix, result);
|
||||
if (wpi::starts_with(str, "0x") || wpi::starts_with(str, "0X")) {
|
||||
str.remove_prefix(2);
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0b") || wpi::starts_with(str, "0B")) {
|
||||
str.remove_prefix(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0o")) {
|
||||
str.remove_prefix(2);
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (str[0] == '0' && str.size() > 1 && wpi::isDigit(str[1])) {
|
||||
str.remove_prefix(1);
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
|
||||
bool wpi::detail::ConsumeUnsignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
unsigned long long& result) noexcept { // NOLINT(runtime/int)
|
||||
wpi::StringRef sref = str;
|
||||
bool rv = wpi::consumeUnsignedInteger(sref, radix, result);
|
||||
str = sref;
|
||||
return rv;
|
||||
// Autosense radix if not specified.
|
||||
if (radix == 0) {
|
||||
radix = GetAutoSenseRadix(str);
|
||||
}
|
||||
|
||||
// Empty strings (after the radix autosense) are invalid.
|
||||
if (str.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse all the bytes of the string given this radix. Watch for overflow.
|
||||
std::string_view str2 = str;
|
||||
result = 0;
|
||||
while (!str2.empty()) {
|
||||
unsigned charVal;
|
||||
if (str2[0] >= '0' && str2[0] <= '9') {
|
||||
charVal = str2[0] - '0';
|
||||
} else if (str2[0] >= 'a' && str2[0] <= 'z') {
|
||||
charVal = str2[0] - 'a' + 10;
|
||||
} else if (str2[0] >= 'A' && str2[0] <= 'Z') {
|
||||
charVal = str2[0] - 'A' + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// If the parsed value is larger than the integer radix, we cannot
|
||||
// consume any more characters.
|
||||
if (charVal >= radix) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add in this character.
|
||||
unsigned long long prevResult = result; // NOLINT(runtime/int)
|
||||
result = result * radix + charVal;
|
||||
|
||||
// Check for overflow by shifting back and seeing if bits were lost.
|
||||
if (result / radix < prevResult) {
|
||||
return true;
|
||||
}
|
||||
|
||||
str2.remove_prefix(1);
|
||||
}
|
||||
|
||||
// We consider the operation a failure if no characters were consumed
|
||||
// successfully.
|
||||
if (str.size() == str2.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
str = str2;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::detail::ConsumeSignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
long long& result) noexcept { // NOLINT(runtime/int)
|
||||
wpi::StringRef sref = str;
|
||||
bool rv = wpi::consumeSignedInteger(sref, radix, result);
|
||||
str = sref;
|
||||
return rv;
|
||||
unsigned long long ullVal; // NOLINT(runtime/int)
|
||||
|
||||
// Handle positive strings first.
|
||||
if (str.empty() || str.front() != '-') {
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str, radix, ullVal) ||
|
||||
// Check for value so large it overflows a signed value.
|
||||
static_cast<long long>(ullVal) < 0) { // NOLINT(runtime/int)
|
||||
return true;
|
||||
}
|
||||
result = ullVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the positive part of the value.
|
||||
std::string_view str2 = wpi::drop_front(str, 1);
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str2, radix, ullVal) ||
|
||||
// Reject values so large they'd overflow as negative signed, but allow
|
||||
// "-0". This negates the unsigned so that the negative isn't undefined
|
||||
// on signed overflow.
|
||||
static_cast<long long>(-ullVal) > 0) { // NOLINT(runtime/int)
|
||||
return true;
|
||||
}
|
||||
|
||||
str = str2;
|
||||
result = -ullVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsUnsignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
unsigned long long& result) noexcept { // NOLINT(runtime/int)
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str, radix, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For getAsUnsignedInteger, we require the whole string to be consumed or
|
||||
// else we consider it a failure.
|
||||
return !str.empty();
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsSignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
long long& result) noexcept { // NOLINT(runtime/int)
|
||||
if (wpi::detail::ConsumeSignedInteger(str, radix, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For getAsSignedInteger, we require the whole string to be consumed or else
|
||||
// we consider it a failure.
|
||||
return !str.empty();
|
||||
}
|
||||
|
||||
template <>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
TCPAcceptor::TCPAcceptor(int port, const char* address, Logger& logger)
|
||||
TCPAcceptor::TCPAcceptor(int port, std::string_view address, Logger& logger)
|
||||
: m_lsd(0),
|
||||
m_port(port),
|
||||
m_address(address),
|
||||
@@ -79,7 +79,7 @@ int TCPAcceptor::start() {
|
||||
|
||||
m_lsd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (m_lsd < 0) {
|
||||
WPI_ERROR(m_logger, "could not create socket");
|
||||
WPI_ERROR(m_logger, "{}", "could not create socket");
|
||||
return -1;
|
||||
}
|
||||
struct sockaddr_in address;
|
||||
@@ -95,7 +95,7 @@ int TCPAcceptor::start() {
|
||||
int res = inet_pton(PF_INET, m_address.c_str(), &(address.sin_addr));
|
||||
#endif
|
||||
if (res != 1) {
|
||||
WPI_ERROR(m_logger, "could not resolve " << m_address << " address");
|
||||
WPI_ERROR(m_logger, "could not resolve {} address", m_address);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -116,15 +116,15 @@ int TCPAcceptor::start() {
|
||||
int result = bind(m_lsd, reinterpret_cast<struct sockaddr*>(&address),
|
||||
sizeof(address));
|
||||
if (result != 0) {
|
||||
WPI_ERROR(m_logger,
|
||||
"bind() to port " << m_port << " failed: " << SocketStrerror());
|
||||
WPI_ERROR(m_logger, "bind() to port {} failed: {}", m_port,
|
||||
SocketStrerror());
|
||||
return result;
|
||||
}
|
||||
|
||||
result = listen(m_lsd, 5);
|
||||
if (result != 0) {
|
||||
WPI_ERROR(m_logger,
|
||||
"listen() on port " << m_port << " failed: " << SocketStrerror());
|
||||
WPI_ERROR(m_logger, "listen() on port {} failed: {}", m_port,
|
||||
SocketStrerror());
|
||||
return result;
|
||||
}
|
||||
m_listening = true;
|
||||
@@ -193,8 +193,8 @@ std::unique_ptr<NetworkStream> TCPAcceptor::accept() {
|
||||
int sd = ::accept(m_lsd, reinterpret_cast<struct sockaddr*>(&address), &len);
|
||||
if (sd < 0) {
|
||||
if (!m_shutdown) {
|
||||
WPI_ERROR(m_logger, "accept() on port "
|
||||
<< m_port << " failed: " << SocketStrerror());
|
||||
WPI_ERROR(m_logger, "accept() on port {} failed: {}", m_port,
|
||||
SocketStrerror());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
int res = inet_pton(PF_INET, server, &(address.sin_addr));
|
||||
#endif
|
||||
if (res != 1) {
|
||||
WPI_ERROR(logger, "could not resolve " << server << " address");
|
||||
WPI_ERROR(logger, "could not resolve {} address", server);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -105,13 +105,13 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
if (timeout == 0) {
|
||||
int sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sd < 0) {
|
||||
WPI_ERROR(logger, "could not create socket");
|
||||
WPI_ERROR(logger, "{}", "could not create socket");
|
||||
return nullptr;
|
||||
}
|
||||
if (::connect(sd, reinterpret_cast<struct sockaddr*>(&address),
|
||||
sizeof(address)) != 0) {
|
||||
WPI_ERROR(logger, "connect() to " << server << " port " << port
|
||||
<< " failed: " << SocketStrerror());
|
||||
WPI_ERROR(logger, "connect() to {} port {} failed: {}", server, port,
|
||||
SocketStrerror());
|
||||
#ifdef _WIN32
|
||||
closesocket(sd);
|
||||
#else
|
||||
@@ -127,7 +127,7 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
socklen_t len;
|
||||
int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sd < 0) {
|
||||
WPI_ERROR(logger, "could not create socket");
|
||||
WPI_ERROR(logger, "{}", "could not create socket");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -135,19 +135,19 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1;
|
||||
if (ioctlsocket(sd, FIONBIO, &mode) == SOCKET_ERROR)
|
||||
WPI_WARNING(logger,
|
||||
"could not set socket to non-blocking: " << SocketStrerror());
|
||||
WPI_WARNING(logger, "could not set socket to non-blocking: {}",
|
||||
SocketStrerror());
|
||||
#else
|
||||
int arg;
|
||||
arg = fcntl(sd, F_GETFL, nullptr);
|
||||
if (arg < 0) {
|
||||
WPI_WARNING(logger,
|
||||
"could not set socket to non-blocking: " << SocketStrerror());
|
||||
WPI_WARNING(logger, "could not set socket to non-blocking: {}",
|
||||
SocketStrerror());
|
||||
} else {
|
||||
arg |= O_NONBLOCK;
|
||||
if (fcntl(sd, F_SETFL, arg) < 0) {
|
||||
WPI_WARNING(logger,
|
||||
"could not set socket to non-blocking: " << SocketStrerror());
|
||||
WPI_WARNING(logger, "could not set socket to non-blocking: {}",
|
||||
SocketStrerror());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -170,21 +170,18 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
getsockopt(sd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&valopt),
|
||||
&len);
|
||||
if (valopt) {
|
||||
WPI_ERROR(logger, "select() to " << server << " port " << port
|
||||
<< " error " << valopt << " - "
|
||||
<< SocketStrerror(valopt));
|
||||
WPI_ERROR(logger, "select() to {} port {} error {} - {}", server,
|
||||
port, valopt, SocketStrerror(valopt));
|
||||
} else {
|
||||
// connection established
|
||||
result = 0;
|
||||
}
|
||||
} else {
|
||||
WPI_INFO(logger,
|
||||
"connect() to " << server << " port " << port << " timed out");
|
||||
WPI_INFO(logger, "connect() to {} port {} timed out", server, port);
|
||||
}
|
||||
} else {
|
||||
WPI_ERROR(logger, "connect() to " << server << " port " << port
|
||||
<< " error " << SocketErrno() << " - "
|
||||
<< SocketStrerror());
|
||||
WPI_ERROR(logger, "connect() to {} port {} error {} - {}", server, port,
|
||||
SocketErrno(), SocketStrerror());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,18 +189,18 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
#ifdef _WIN32
|
||||
mode = 0;
|
||||
if (ioctlsocket(sd, FIONBIO, &mode) == SOCKET_ERROR)
|
||||
WPI_WARNING(logger,
|
||||
"could not set socket to blocking: " << SocketStrerror());
|
||||
WPI_WARNING(logger, "could not set socket to blocking: {}",
|
||||
SocketStrerror());
|
||||
#else
|
||||
arg = fcntl(sd, F_GETFL, nullptr);
|
||||
if (arg < 0) {
|
||||
WPI_WARNING(logger,
|
||||
"could not set socket to blocking: " << SocketStrerror());
|
||||
WPI_WARNING(logger, "could not set socket to blocking: {}",
|
||||
SocketStrerror());
|
||||
} else {
|
||||
arg &= (~O_NONBLOCK);
|
||||
if (fcntl(sd, F_SETFL, arg) < 0) {
|
||||
WPI_WARNING(logger,
|
||||
"could not set socket to blocking: " << SocketStrerror());
|
||||
WPI_WARNING(logger, "could not set socket to blocking: {}",
|
||||
SocketStrerror());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -168,7 +168,7 @@ void TCPStream::close() {
|
||||
m_sd = -1;
|
||||
}
|
||||
|
||||
StringRef TCPStream::getPeerIP() const {
|
||||
std::string_view TCPStream::getPeerIP() const {
|
||||
return m_peerIP;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
#endif
|
||||
|
||||
#include "wpi/Logger.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SocketError.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
UDPClient::UDPClient(Logger& logger) : UDPClient("", logger) {}
|
||||
|
||||
UDPClient::UDPClient(const Twine& address, Logger& logger)
|
||||
: m_lsd(0), m_port(0), m_address(address.str()), m_logger(logger) {}
|
||||
UDPClient::UDPClient(std::string_view address, Logger& logger)
|
||||
: m_lsd(0), m_port(0), m_address(address), m_logger(logger) {}
|
||||
|
||||
UDPClient::UDPClient(UDPClient&& other)
|
||||
: m_lsd(other.m_lsd),
|
||||
@@ -72,7 +73,7 @@ int UDPClient::start(int port) {
|
||||
m_lsd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
if (m_lsd < 0) {
|
||||
WPI_ERROR(m_logger, "could not create socket");
|
||||
WPI_ERROR(m_logger, "{}", "could not create socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -88,7 +89,7 @@ int UDPClient::start(int port) {
|
||||
int res = inet_pton(PF_INET, m_address.c_str(), &(addr.sin_addr));
|
||||
#endif
|
||||
if (res != 1) {
|
||||
WPI_ERROR(m_logger, "could not resolve " << m_address << " address");
|
||||
WPI_ERROR(m_logger, "could not resolve {} address", m_address);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -110,7 +111,7 @@ int UDPClient::start(int port) {
|
||||
|
||||
int result = bind(m_lsd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
|
||||
if (result != 0) {
|
||||
WPI_ERROR(m_logger, "bind() failed: " << SocketStrerror());
|
||||
WPI_ERROR(m_logger, "bind() failed: {}", SocketStrerror());
|
||||
return result;
|
||||
}
|
||||
m_port = port;
|
||||
@@ -132,25 +133,24 @@ void UDPClient::shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
int UDPClient::send(ArrayRef<uint8_t> data, const Twine& server, int port) {
|
||||
int UDPClient::send(ArrayRef<uint8_t> data, std::string_view server, int port) {
|
||||
// server must be a resolvable IP address
|
||||
struct sockaddr_in addr;
|
||||
std::memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
SmallVector<char, 128> addr_store;
|
||||
StringRef remoteAddr = server.toNullTerminatedStringRef(addr_store);
|
||||
SmallString<128> remoteAddr{server};
|
||||
if (remoteAddr.empty()) {
|
||||
WPI_ERROR(m_logger, "server must be passed");
|
||||
WPI_ERROR(m_logger, "{}", "server must be passed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int res = InetPton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
|
||||
int res = InetPton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
|
||||
#else
|
||||
int res = inet_pton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
|
||||
int res = inet_pton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
|
||||
#endif
|
||||
if (res != 1) {
|
||||
WPI_ERROR(m_logger, "could not resolve " << server << " address");
|
||||
WPI_ERROR(m_logger, "could not resolve {} address", server);
|
||||
return -1;
|
||||
}
|
||||
addr.sin_port = htons(port);
|
||||
@@ -162,25 +162,24 @@ int UDPClient::send(ArrayRef<uint8_t> data, const Twine& server, int port) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int UDPClient::send(StringRef data, const Twine& server, int port) {
|
||||
int UDPClient::send(std::string_view data, std::string_view server, int port) {
|
||||
// server must be a resolvable IP address
|
||||
struct sockaddr_in addr;
|
||||
std::memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
SmallVector<char, 128> addr_store;
|
||||
StringRef remoteAddr = server.toNullTerminatedStringRef(addr_store);
|
||||
SmallString<128> remoteAddr{server};
|
||||
if (remoteAddr.empty()) {
|
||||
WPI_ERROR(m_logger, "server must be passed");
|
||||
WPI_ERROR(m_logger, "{}", "server must be passed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int res = InetPton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
|
||||
int res = InetPton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
|
||||
#else
|
||||
int res = inet_pton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
|
||||
int res = inet_pton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
|
||||
#endif
|
||||
if (res != 1) {
|
||||
WPI_ERROR(m_logger, "could not resolve " << server << " address");
|
||||
WPI_ERROR(m_logger, "could not resolve {} address", server);
|
||||
return -1;
|
||||
}
|
||||
addr.sin_port = htons(port);
|
||||
@@ -242,7 +241,7 @@ int UDPClient::set_timeout(double timeout) {
|
||||
int ret = setsockopt(m_lsd, SOL_SOCKET, SO_RCVTIMEO,
|
||||
reinterpret_cast<char*>(&tv), sizeof(tv));
|
||||
if (ret < 0) {
|
||||
WPI_ERROR(m_logger, "set timeout failed");
|
||||
WPI_ERROR(m_logger, "{}", "set timeout failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
|
||||
#include <random>
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/Base64.h"
|
||||
#include "wpi/HttpParser.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/raw_uv_ostream.h"
|
||||
#include "wpi/sha1.h"
|
||||
#include "wpi/uv/Stream.h"
|
||||
@@ -47,7 +49,7 @@ class WebSocket::ClientHandshakeData {
|
||||
v = static_cast<char>(dist(gen));
|
||||
}
|
||||
raw_svector_ostream os(key);
|
||||
Base64Encode(os, StringRef{nonce, 16});
|
||||
Base64Encode(os, {nonce, 16});
|
||||
}
|
||||
~ClientHandshakeData() {
|
||||
if (auto t = timer.lock()) {
|
||||
@@ -67,7 +69,8 @@ class WebSocket::ClientHandshakeData {
|
||||
std::weak_ptr<uv::Timer> timer;
|
||||
};
|
||||
|
||||
static StringRef AcceptHash(StringRef key, SmallVectorImpl<char>& buf) {
|
||||
static std::string_view AcceptHash(std::string_view key,
|
||||
SmallVectorImpl<char>& buf) {
|
||||
SHA1 hash;
|
||||
hash.Update(key);
|
||||
hash.Update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
@@ -80,7 +83,7 @@ WebSocket::WebSocket(uv::Stream& stream, bool server, const private_init&)
|
||||
// Connect closed and error signals to ourselves
|
||||
m_stream.closed.connect([this]() { SetClosed(1006, "handle closed"); });
|
||||
m_stream.error.connect([this](uv::Error err) {
|
||||
Terminate(1006, "stream error: " + Twine(err.name()));
|
||||
Terminate(1006, fmt::format("stream error: {}", err.name()));
|
||||
});
|
||||
|
||||
// Start reading
|
||||
@@ -95,8 +98,8 @@ WebSocket::WebSocket(uv::Stream& stream, bool server, const private_init&)
|
||||
WebSocket::~WebSocket() = default;
|
||||
|
||||
std::shared_ptr<WebSocket> WebSocket::CreateClient(
|
||||
uv::Stream& stream, const Twine& uri, const Twine& host,
|
||||
ArrayRef<StringRef> protocols, const ClientOptions& options) {
|
||||
uv::Stream& stream, std::string_view uri, std::string_view host,
|
||||
ArrayRef<std::string_view> protocols, const ClientOptions& options) {
|
||||
auto ws = std::make_shared<WebSocket>(stream, false, private_init{});
|
||||
stream.SetData(ws);
|
||||
ws->StartClient(uri, host, protocols, options);
|
||||
@@ -104,23 +107,23 @@ std::shared_ptr<WebSocket> WebSocket::CreateClient(
|
||||
}
|
||||
|
||||
std::shared_ptr<WebSocket> WebSocket::CreateServer(uv::Stream& stream,
|
||||
StringRef key,
|
||||
StringRef version,
|
||||
StringRef protocol) {
|
||||
std::string_view key,
|
||||
std::string_view version,
|
||||
std::string_view protocol) {
|
||||
auto ws = std::make_shared<WebSocket>(stream, true, private_init{});
|
||||
stream.SetData(ws);
|
||||
ws->StartServer(key, version, protocol);
|
||||
return ws;
|
||||
}
|
||||
|
||||
void WebSocket::Close(uint16_t code, const Twine& reason) {
|
||||
void WebSocket::Close(uint16_t code, std::string_view reason) {
|
||||
SendClose(code, reason);
|
||||
if (m_state != FAILED && m_state != CLOSED) {
|
||||
m_state = CLOSING;
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocket::Fail(uint16_t code, const Twine& reason) {
|
||||
void WebSocket::Fail(uint16_t code, std::string_view reason) {
|
||||
if (m_state == FAILED || m_state == CLOSED) {
|
||||
return;
|
||||
}
|
||||
@@ -129,7 +132,7 @@ void WebSocket::Fail(uint16_t code, const Twine& reason) {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void WebSocket::Terminate(uint16_t code, const Twine& reason) {
|
||||
void WebSocket::Terminate(uint16_t code, std::string_view reason) {
|
||||
if (m_state == FAILED || m_state == CLOSED) {
|
||||
return;
|
||||
}
|
||||
@@ -137,8 +140,8 @@ void WebSocket::Terminate(uint16_t code, const Twine& reason) {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void WebSocket::StartClient(const Twine& uri, const Twine& host,
|
||||
ArrayRef<StringRef> protocols,
|
||||
void WebSocket::StartClient(std::string_view uri, std::string_view host,
|
||||
ArrayRef<std::string_view> protocols,
|
||||
const ClientOptions& options) {
|
||||
// Create client handshake data
|
||||
m_clientHandshake = std::make_unique<ClientHandshakeData>();
|
||||
@@ -187,42 +190,42 @@ void WebSocket::StartClient(const Twine& uri, const Twine& host,
|
||||
});
|
||||
|
||||
// Set up client response handling
|
||||
m_clientHandshake->parser.status.connect([this](StringRef status) {
|
||||
m_clientHandshake->parser.status.connect([this](std::string_view status) {
|
||||
unsigned int code = m_clientHandshake->parser.GetStatusCode();
|
||||
if (code != 101) {
|
||||
Terminate(code, status);
|
||||
}
|
||||
});
|
||||
m_clientHandshake->parser.header.connect(
|
||||
[this](StringRef name, StringRef value) {
|
||||
value = value.trim();
|
||||
if (name.equals_lower("upgrade")) {
|
||||
if (!value.equals_lower("websocket")) {
|
||||
[this](std::string_view name, std::string_view value) {
|
||||
value = trim(value);
|
||||
if (equals_lower(name, "upgrade")) {
|
||||
if (!equals_lower(value, "websocket")) {
|
||||
return Terminate(1002, "invalid upgrade response value");
|
||||
}
|
||||
m_clientHandshake->hasUpgrade = true;
|
||||
} else if (name.equals_lower("connection")) {
|
||||
if (!value.equals_lower("upgrade")) {
|
||||
} else if (equals_lower(name, "connection")) {
|
||||
if (!equals_lower(value, "upgrade")) {
|
||||
return Terminate(1002, "invalid connection response value");
|
||||
}
|
||||
m_clientHandshake->hasConnection = true;
|
||||
} else if (name.equals_lower("sec-websocket-accept")) {
|
||||
} else if (equals_lower(name, "sec-websocket-accept")) {
|
||||
// Check against expected response
|
||||
SmallString<64> acceptBuf;
|
||||
if (!value.equals(AcceptHash(m_clientHandshake->key, acceptBuf))) {
|
||||
if (!equals(value, AcceptHash(m_clientHandshake->key, acceptBuf))) {
|
||||
return Terminate(1002, "invalid accept key");
|
||||
}
|
||||
m_clientHandshake->hasAccept = true;
|
||||
} else if (name.equals_lower("sec-websocket-extensions")) {
|
||||
} else if (equals_lower(name, "sec-websocket-extensions")) {
|
||||
// No extensions are supported
|
||||
if (!value.empty()) {
|
||||
return Terminate(1010, "unsupported extension");
|
||||
}
|
||||
} else if (name.equals_lower("sec-websocket-protocol")) {
|
||||
} else if (equals_lower(name, "sec-websocket-protocol")) {
|
||||
// Make sure it was one of the provided protocols
|
||||
bool match = false;
|
||||
for (auto&& protocol : m_clientHandshake->protocols) {
|
||||
if (value.equals_lower(protocol)) {
|
||||
if (equals_lower(value, protocol)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
@@ -257,8 +260,8 @@ void WebSocket::StartClient(const Twine& uri, const Twine& host,
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocket::StartServer(StringRef key, StringRef version,
|
||||
StringRef protocol) {
|
||||
void WebSocket::StartServer(std::string_view key, std::string_view version,
|
||||
std::string_view protocol) {
|
||||
m_protocol = protocol;
|
||||
|
||||
// Build server response
|
||||
@@ -308,14 +311,14 @@ void WebSocket::StartServer(StringRef key, StringRef version,
|
||||
});
|
||||
}
|
||||
|
||||
void WebSocket::SendClose(uint16_t code, const Twine& reason) {
|
||||
void WebSocket::SendClose(uint16_t code, std::string_view reason) {
|
||||
SmallVector<uv::Buffer, 4> bufs;
|
||||
if (code != 1005) {
|
||||
raw_uv_ostream os{bufs, 4096};
|
||||
const uint8_t codeMsb[] = {static_cast<uint8_t>((code >> 8) & 0xff),
|
||||
static_cast<uint8_t>(code & 0xff)};
|
||||
os << ArrayRef<uint8_t>(codeMsb);
|
||||
reason.print(os);
|
||||
os << reason;
|
||||
}
|
||||
Send(kFlagFin | kOpClose, bufs, [](auto bufs, uv::Error) {
|
||||
for (auto&& buf : bufs) {
|
||||
@@ -324,13 +327,12 @@ void WebSocket::SendClose(uint16_t code, const Twine& reason) {
|
||||
});
|
||||
}
|
||||
|
||||
void WebSocket::SetClosed(uint16_t code, const Twine& reason, bool failed) {
|
||||
void WebSocket::SetClosed(uint16_t code, std::string_view reason, bool failed) {
|
||||
if (m_state == FAILED || m_state == CLOSED) {
|
||||
return;
|
||||
}
|
||||
m_state = failed ? FAILED : CLOSED;
|
||||
SmallString<64> reasonBuf;
|
||||
closed(code, reason.toStringRef(reasonBuf));
|
||||
closed(code, reason);
|
||||
}
|
||||
|
||||
void WebSocket::Shutdown() {
|
||||
@@ -343,7 +345,7 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef data{buf.base, size};
|
||||
std::string_view data{buf.base, size};
|
||||
|
||||
// Handle connecting state (mainly on client)
|
||||
if (m_state == CONNECTING) {
|
||||
@@ -372,8 +374,8 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
// Need at least two bytes to determine header length
|
||||
if (m_header.size() < 2u) {
|
||||
size_t toCopy = (std::min)(2u - m_header.size(), data.size());
|
||||
m_header.append(data.bytes_begin(), data.bytes_begin() + toCopy);
|
||||
data = data.drop_front(toCopy);
|
||||
m_header.append(data.data(), data.data() + toCopy);
|
||||
data.remove_prefix(toCopy);
|
||||
if (m_header.size() < 2u) {
|
||||
return; // need more data
|
||||
}
|
||||
@@ -410,8 +412,8 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
// Need to complete header to calculate message size
|
||||
if (m_header.size() < m_headerSize) {
|
||||
size_t toCopy = (std::min)(m_headerSize - m_header.size(), data.size());
|
||||
m_header.append(data.bytes_begin(), data.bytes_begin() + toCopy);
|
||||
data = data.drop_front(toCopy);
|
||||
m_header.append(data.data(), data.data() + toCopy);
|
||||
data.remove_prefix(toCopy);
|
||||
if (m_header.size() < m_headerSize) {
|
||||
return; // need more data
|
||||
}
|
||||
@@ -446,8 +448,8 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
if (m_frameSize != UINT64_MAX) {
|
||||
size_t need = m_frameStart + m_frameSize - m_payload.size();
|
||||
size_t toCopy = (std::min)(need, data.size());
|
||||
m_payload.append(data.bytes_begin(), data.bytes_begin() + toCopy);
|
||||
data = data.drop_front(toCopy);
|
||||
m_payload.append(data.data(), data.data() + toCopy);
|
||||
data.remove_prefix(toCopy);
|
||||
need -= toCopy;
|
||||
if (need == 0) {
|
||||
// We have a complete frame
|
||||
@@ -474,8 +476,9 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
switch (m_fragmentOpcode) {
|
||||
case kOpText:
|
||||
if (!m_combineFragments || fin) {
|
||||
text(StringRef{reinterpret_cast<char*>(m_payload.data()),
|
||||
m_payload.size()},
|
||||
text(std::string_view{reinterpret_cast<char*>(
|
||||
m_payload.data()),
|
||||
m_payload.size()},
|
||||
fin);
|
||||
}
|
||||
break;
|
||||
@@ -497,8 +500,8 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
return Fail(1002, "incomplete fragment");
|
||||
}
|
||||
if (!m_combineFragments || fin) {
|
||||
text(StringRef{reinterpret_cast<char*>(m_payload.data()),
|
||||
m_payload.size()},
|
||||
text(std::string_view{reinterpret_cast<char*>(m_payload.data()),
|
||||
m_payload.size()},
|
||||
fin);
|
||||
}
|
||||
if (!fin) {
|
||||
@@ -518,7 +521,7 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
break;
|
||||
case kOpClose: {
|
||||
uint16_t code;
|
||||
StringRef reason;
|
||||
std::string_view reason;
|
||||
if (!fin) {
|
||||
code = 1002;
|
||||
reason = "cannot fragment control frames";
|
||||
@@ -527,9 +530,9 @@ void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
|
||||
} else {
|
||||
code = (static_cast<uint16_t>(m_payload[0]) << 8) |
|
||||
static_cast<uint16_t>(m_payload[1]);
|
||||
reason = StringRef{reinterpret_cast<char*>(m_payload.data()),
|
||||
m_payload.size()}
|
||||
.drop_front(2);
|
||||
reason = drop_front(
|
||||
{reinterpret_cast<char*>(m_payload.data()), m_payload.size()},
|
||||
2);
|
||||
}
|
||||
// Echo the close if we didn't previously send it
|
||||
if (m_state != CLOSING) {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/fmt/raw_ostream.h"
|
||||
#include "wpi/raw_uv_ostream.h"
|
||||
#include "wpi/uv/Buffer.h"
|
||||
#include "wpi/uv/Stream.h"
|
||||
@@ -13,23 +15,23 @@
|
||||
using namespace wpi;
|
||||
|
||||
WebSocketServerHelper::WebSocketServerHelper(HttpParser& req) {
|
||||
req.header.connect([this](StringRef name, StringRef value) {
|
||||
if (name.equals_lower("host")) {
|
||||
req.header.connect([this](std::string_view name, std::string_view value) {
|
||||
if (equals_lower(name, "host")) {
|
||||
m_gotHost = true;
|
||||
} else if (name.equals_lower("upgrade")) {
|
||||
if (value.equals_lower("websocket")) {
|
||||
} else if (equals_lower(name, "upgrade")) {
|
||||
if (equals_lower(value, "websocket")) {
|
||||
m_websocket = true;
|
||||
}
|
||||
} else if (name.equals_lower("sec-websocket-key")) {
|
||||
} else if (equals_lower(name, "sec-websocket-key")) {
|
||||
m_key = value;
|
||||
} else if (name.equals_lower("sec-websocket-version")) {
|
||||
} else if (equals_lower(name, "sec-websocket-version")) {
|
||||
m_version = value;
|
||||
} else if (name.equals_lower("sec-websocket-protocol")) {
|
||||
} else if (equals_lower(name, "sec-websocket-protocol")) {
|
||||
// Protocols are comma delimited, repeated headers add to list
|
||||
SmallVector<StringRef, 2> protocols;
|
||||
value.split(protocols, ",", -1, false);
|
||||
SmallVector<std::string_view, 2> protocols;
|
||||
split(value, protocols, ",", -1, false);
|
||||
for (auto protocol : protocols) {
|
||||
protocol = protocol.trim();
|
||||
protocol = trim(protocol);
|
||||
if (!protocol.empty()) {
|
||||
m_protocols.emplace_back(protocol);
|
||||
}
|
||||
@@ -43,31 +45,31 @@ WebSocketServerHelper::WebSocketServerHelper(HttpParser& req) {
|
||||
});
|
||||
}
|
||||
|
||||
std::pair<bool, StringRef> WebSocketServerHelper::MatchProtocol(
|
||||
ArrayRef<StringRef> protocols) {
|
||||
std::pair<bool, std::string_view> WebSocketServerHelper::MatchProtocol(
|
||||
ArrayRef<std::string_view> protocols) {
|
||||
if (protocols.empty() && m_protocols.empty()) {
|
||||
return std::make_pair(true, StringRef{});
|
||||
return {true, {}};
|
||||
}
|
||||
for (auto protocol : protocols) {
|
||||
for (auto&& clientProto : m_protocols) {
|
||||
if (protocol == clientProto) {
|
||||
return std::make_pair(true, protocol);
|
||||
return {true, protocol};
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_pair(false, StringRef{});
|
||||
return {false, {}};
|
||||
}
|
||||
|
||||
WebSocketServer::WebSocketServer(uv::Stream& stream,
|
||||
ArrayRef<StringRef> protocols,
|
||||
ArrayRef<std::string_view> protocols,
|
||||
ServerOptions options, const private_init&)
|
||||
: m_stream{stream},
|
||||
m_helper{m_req},
|
||||
m_protocols{protocols.begin(), protocols.end()},
|
||||
m_options{std::move(options)} {
|
||||
// Header handling
|
||||
m_req.header.connect([this](StringRef name, StringRef value) {
|
||||
if (name.equals_lower("host")) {
|
||||
m_req.header.connect([this](std::string_view name, std::string_view value) {
|
||||
if (equals_lower(name, "host")) {
|
||||
if (m_options.checkHost) {
|
||||
if (!m_options.checkHost(value)) {
|
||||
Abort(401, "Unrecognized Host");
|
||||
@@ -75,7 +77,7 @@ WebSocketServer::WebSocketServer(uv::Stream& stream,
|
||||
}
|
||||
}
|
||||
});
|
||||
m_req.url.connect([this](StringRef name) {
|
||||
m_req.url.connect([this](std::string_view name) {
|
||||
if (m_options.checkUrl) {
|
||||
if (!m_options.checkUrl(name)) {
|
||||
Abort(404, "Not Found");
|
||||
@@ -96,8 +98,9 @@ WebSocketServer::WebSocketServer(uv::Stream& stream,
|
||||
}
|
||||
|
||||
// Negotiate sub-protocol
|
||||
SmallVector<StringRef, 2> protocols{m_protocols.begin(), m_protocols.end()};
|
||||
StringRef protocol = m_helper.MatchProtocol(protocols).second;
|
||||
SmallVector<std::string_view, 2> protocols{m_protocols.begin(),
|
||||
m_protocols.end()};
|
||||
std::string_view protocol = m_helper.MatchProtocol(protocols).second;
|
||||
|
||||
// Disconnect our header reader
|
||||
m_dataConn.disconnect();
|
||||
@@ -110,10 +113,11 @@ WebSocketServer::WebSocketServer(uv::Stream& stream,
|
||||
auto ws = m_helper.Accept(m_stream, protocol);
|
||||
|
||||
// Connect the websocket open event to our connected event.
|
||||
ws->open.connect_extended([self, s = ws.get()](auto conn, StringRef) {
|
||||
self->connected(self->m_req.GetUrl(), *s);
|
||||
conn.disconnect(); // one-shot
|
||||
});
|
||||
ws->open.connect_extended(
|
||||
[self, s = ws.get()](auto conn, std::string_view) {
|
||||
self->connected(self->m_req.GetUrl(), *s);
|
||||
conn.disconnect(); // one-shot
|
||||
});
|
||||
});
|
||||
|
||||
// Set up stream
|
||||
@@ -123,7 +127,7 @@ WebSocketServer::WebSocketServer(uv::Stream& stream,
|
||||
if (m_aborted) {
|
||||
return;
|
||||
}
|
||||
m_req.Execute(StringRef{buf.base, size});
|
||||
m_req.Execute(std::string_view{buf.base, size});
|
||||
if (m_req.HasError()) {
|
||||
Abort(400, "Bad Request");
|
||||
}
|
||||
@@ -134,7 +138,7 @@ WebSocketServer::WebSocketServer(uv::Stream& stream,
|
||||
}
|
||||
|
||||
std::shared_ptr<WebSocketServer> WebSocketServer::Create(
|
||||
uv::Stream& stream, ArrayRef<StringRef> protocols,
|
||||
uv::Stream& stream, ArrayRef<std::string_view> protocols,
|
||||
const ServerOptions& options) {
|
||||
auto server = std::make_shared<WebSocketServer>(stream, protocols, options,
|
||||
private_init{});
|
||||
@@ -142,7 +146,7 @@ std::shared_ptr<WebSocketServer> WebSocketServer::Create(
|
||||
return server;
|
||||
}
|
||||
|
||||
void WebSocketServer::Abort(uint16_t code, StringRef reason) {
|
||||
void WebSocketServer::Abort(uint16_t code, std::string_view reason) {
|
||||
if (m_aborted) {
|
||||
return;
|
||||
}
|
||||
@@ -153,7 +157,7 @@ void WebSocketServer::Abort(uint16_t code, StringRef reason) {
|
||||
raw_uv_ostream os{bufs, 1024};
|
||||
|
||||
// Handle unsupported version
|
||||
os << "HTTP/1.1 " << code << ' ' << reason << "\r\n";
|
||||
fmt::print(os, "HTTP/1.1 {} {}\r\n", code, reason);
|
||||
if (code == 426) {
|
||||
os << "Upgrade: WebSocket\r\n";
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "uv.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -33,7 +33,7 @@ std::string GetHostname() {
|
||||
return rv;
|
||||
}
|
||||
|
||||
StringRef GetHostname(SmallVectorImpl<char>& name) {
|
||||
std::string_view GetHostname(SmallVectorImpl<char>& name) {
|
||||
// Use a tmp array to not require the SmallVector to be too large.
|
||||
char tmpName[256];
|
||||
size_t size = sizeof(tmpName);
|
||||
@@ -51,7 +51,7 @@ StringRef GetHostname(SmallVectorImpl<char>& name) {
|
||||
}
|
||||
}
|
||||
|
||||
return StringRef{name.data(), size};
|
||||
return {name.data(), size};
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
@@ -34,39 +34,51 @@ SOFTWARE.
|
||||
#define WPI_JSON_IMPLEMENTATION
|
||||
#include "wpi/json.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace detail {
|
||||
|
||||
exception::exception(int id_, const Twine& what_arg)
|
||||
: id(id_), m(what_arg.str()) {}
|
||||
exception::exception(int id_, std::string_view what_arg)
|
||||
: id(id_), m(std::string{what_arg}) {}
|
||||
|
||||
parse_error parse_error::create(int id_, std::size_t byte_, const Twine& what_arg)
|
||||
parse_error parse_error::create(int id_, std::size_t byte_, std::string_view what_arg)
|
||||
{
|
||||
return parse_error(id_, byte_, "[json.exception.parse_error." + Twine(id_) + "] parse error" +
|
||||
(byte_ != 0 ? (" at " + Twine(byte_)) : Twine("")) +
|
||||
": " + what_arg);
|
||||
if (byte_ != 0)
|
||||
return parse_error(id_, byte_, fmt::format("[json.exception.parse_error.{}] parse error at {}: {}", id_, byte_, what_arg));
|
||||
else
|
||||
return parse_error(id_, byte_, fmt::format("[json.exception.parse_error.{}] parse error: {}", id_, what_arg));
|
||||
}
|
||||
|
||||
invalid_iterator invalid_iterator::create(int id_, const Twine& what_arg)
|
||||
invalid_iterator invalid_iterator::create(int id_, std::string_view what_arg)
|
||||
{
|
||||
return invalid_iterator(id_, "[json.exception.invalid_iterator." + Twine(id_) + "] " + what_arg);
|
||||
return invalid_iterator(id_, fmt::format("[json.exception.invalid_iterator.{}] {}", id_, what_arg));
|
||||
}
|
||||
|
||||
type_error type_error::create(int id_, const Twine& what_arg)
|
||||
invalid_iterator invalid_iterator::create(int id_, std::string_view what_arg, std::string_view type_info)
|
||||
{
|
||||
return type_error(id_, "[json.exception.type_error." + Twine(id_) + "] " + what_arg);
|
||||
return invalid_iterator(id_, fmt::format("[json.exception.invalid_iterator.{}] {} {}", id_, what_arg, type_info));
|
||||
}
|
||||
|
||||
out_of_range out_of_range::create(int id_, const Twine& what_arg)
|
||||
type_error type_error::create(int id_, std::string_view what_arg)
|
||||
{
|
||||
return out_of_range(id_, "[json.exception.out_of_range." + Twine(id_) + "] " + what_arg);
|
||||
return type_error(id_, fmt::format("[json.exception.type_error.{}] {}", id_, what_arg));
|
||||
}
|
||||
|
||||
other_error other_error::create(int id_, const Twine& what_arg)
|
||||
type_error type_error::create(int id_, std::string_view what_arg, std::string_view type_info)
|
||||
{
|
||||
return other_error(id_, "[json.exception.other_error." + Twine(id_) + "] " + what_arg);
|
||||
return type_error(id_, fmt::format("[json.exception.type_error.{}] {} {}", id_, what_arg, type_info));
|
||||
}
|
||||
|
||||
out_of_range out_of_range::create(int id_, std::string_view what_arg)
|
||||
{
|
||||
return out_of_range(id_, fmt::format("[json.exception.out_of_range.{}] {}", id_, what_arg));
|
||||
}
|
||||
|
||||
other_error other_error::create(int id_, std::string_view what_arg)
|
||||
{
|
||||
return other_error(id_, fmt::format("[json.exception.other_error.{}] {}", id_, what_arg));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@@ -353,12 +365,12 @@ json::reference json::at(size_type idx)
|
||||
JSON_CATCH (std::out_of_range&)
|
||||
{
|
||||
// create better exception explanation
|
||||
JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
|
||||
JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,16 +386,16 @@ json::const_reference json::at(size_type idx) const
|
||||
JSON_CATCH (std::out_of_range&)
|
||||
{
|
||||
// create better exception explanation
|
||||
JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
|
||||
JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
json::reference json::at(StringRef key)
|
||||
json::reference json::at(std::string_view key)
|
||||
{
|
||||
// at only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
@@ -392,17 +404,17 @@ json::reference json::at(StringRef key)
|
||||
if (it == m_value.object->end())
|
||||
{
|
||||
// create better exception explanation
|
||||
JSON_THROW(out_of_range::create(403, "key '" + Twine(key) + "' not found"));
|
||||
JSON_THROW(out_of_range::create(403, fmt::format("key '{}' not found", key)));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
json::const_reference json::at(StringRef key) const
|
||||
json::const_reference json::at(std::string_view key) const
|
||||
{
|
||||
// at only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
@@ -411,13 +423,13 @@ json::const_reference json::at(StringRef key) const
|
||||
if (it == m_value.object->end())
|
||||
{
|
||||
// create better exception explanation
|
||||
JSON_THROW(out_of_range::create(403, "key '" + Twine(key) + "' not found"));
|
||||
JSON_THROW(out_of_range::create(403, fmt::format("key '{}' not found", key)));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +457,7 @@ json::reference json::operator[](size_type idx)
|
||||
return m_value.array->operator[](idx);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
|
||||
}
|
||||
|
||||
json::const_reference json::operator[](size_type idx) const
|
||||
@@ -456,10 +468,10 @@ json::const_reference json::operator[](size_type idx) const
|
||||
return m_value.array->operator[](idx);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
|
||||
}
|
||||
|
||||
json::reference json::operator[](StringRef key)
|
||||
json::reference json::operator[](std::string_view key)
|
||||
{
|
||||
// implicitly convert null value to an empty object
|
||||
if (is_null())
|
||||
@@ -475,10 +487,10 @@ json::reference json::operator[](StringRef key)
|
||||
return m_value.object->operator[](key);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
|
||||
}
|
||||
|
||||
json::const_reference json::operator[](StringRef key) const
|
||||
json::const_reference json::operator[](std::string_view key) const
|
||||
{
|
||||
// const operator[] only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
@@ -487,10 +499,10 @@ json::const_reference json::operator[](StringRef key) const
|
||||
return m_value.object->find(key)->second;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
|
||||
}
|
||||
|
||||
json::size_type json::erase(StringRef key)
|
||||
json::size_type json::erase(std::string_view key)
|
||||
{
|
||||
// this erase only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
@@ -498,7 +510,7 @@ json::size_type json::erase(StringRef key)
|
||||
return m_value.object->erase(key);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
|
||||
}
|
||||
|
||||
void json::erase(const size_type idx)
|
||||
@@ -508,18 +520,18 @@ void json::erase(const size_type idx)
|
||||
{
|
||||
if (JSON_UNLIKELY(idx >= size()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
|
||||
JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
|
||||
}
|
||||
|
||||
m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
json::iterator json::find(StringRef key)
|
||||
json::iterator json::find(std::string_view key)
|
||||
{
|
||||
auto result = end();
|
||||
|
||||
@@ -531,7 +543,7 @@ json::iterator json::find(StringRef key)
|
||||
return result;
|
||||
}
|
||||
|
||||
json::const_iterator json::find(StringRef key) const
|
||||
json::const_iterator json::find(std::string_view key) const
|
||||
{
|
||||
auto result = cend();
|
||||
|
||||
@@ -543,7 +555,7 @@ json::const_iterator json::find(StringRef key) const
|
||||
return result;
|
||||
}
|
||||
|
||||
json::size_type json::count(StringRef key) const
|
||||
json::size_type json::count(std::string_view key) const
|
||||
{
|
||||
// return 0 for all nonobject types
|
||||
return is_object() ? m_value.object->count(key) : 0;
|
||||
@@ -689,7 +701,7 @@ void json::push_back(json&& val)
|
||||
// push_back only works for null objects or arrays
|
||||
if (JSON_UNLIKELY(not(is_null() or is_array())))
|
||||
{
|
||||
JSON_THROW(type_error::create(308, "cannot use push_back() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(308, "cannot use push_back() with", type_name()));
|
||||
}
|
||||
|
||||
// transform null object into an array
|
||||
@@ -711,7 +723,7 @@ void json::push_back(const json& val)
|
||||
// push_back only works for null objects or arrays
|
||||
if (JSON_UNLIKELY(not(is_null() or is_array())))
|
||||
{
|
||||
JSON_THROW(type_error::create(308, "cannot use push_back() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(308, "cannot use push_back() with", type_name()));
|
||||
}
|
||||
|
||||
// transform null object into an array
|
||||
@@ -731,7 +743,7 @@ void json::push_back(initializer_list_t init)
|
||||
if (is_object() and init.size() == 2 and (*init.begin())->is_string())
|
||||
{
|
||||
std::string key = init.begin()->moved_or_copied();
|
||||
push_back(std::pair<StringRef, json>(key, (init.begin() + 1)->moved_or_copied()));
|
||||
push_back(std::pair<std::string_view, json>(key, (init.begin() + 1)->moved_or_copied()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -756,7 +768,7 @@ json::iterator json::insert(const_iterator pos, const json& val)
|
||||
return result;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
|
||||
}
|
||||
|
||||
json::iterator json::insert(const_iterator pos, size_type cnt, const json& val)
|
||||
@@ -776,7 +788,7 @@ json::iterator json::insert(const_iterator pos, size_type cnt, const json& val)
|
||||
return result;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
|
||||
}
|
||||
|
||||
json::iterator json::insert(const_iterator pos, const_iterator first, const_iterator last)
|
||||
@@ -784,7 +796,7 @@ json::iterator json::insert(const_iterator pos, const_iterator first, const_iter
|
||||
// insert only works for arrays
|
||||
if (JSON_UNLIKELY(not is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
|
||||
}
|
||||
|
||||
// check if iterator pos fits to this JSON value
|
||||
@@ -818,7 +830,7 @@ json::iterator json::insert(const_iterator pos, initializer_list_t ilist)
|
||||
// insert only works for arrays
|
||||
if (JSON_UNLIKELY(not is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
|
||||
}
|
||||
|
||||
// check if iterator pos fits to this JSON value
|
||||
@@ -838,7 +850,7 @@ void json::insert(const_iterator first, const_iterator last)
|
||||
// insert only works for objects
|
||||
if (JSON_UNLIKELY(not is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
|
||||
}
|
||||
|
||||
// check if range iterators belong to the same JSON object
|
||||
@@ -871,11 +883,11 @@ void json::update(const_reference j)
|
||||
|
||||
if (JSON_UNLIKELY(not is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with", type_name()));
|
||||
}
|
||||
if (JSON_UNLIKELY(not j.is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with", j.type_name()));
|
||||
}
|
||||
|
||||
for (auto it = j.cbegin(); it != j.cend(); ++it)
|
||||
@@ -896,7 +908,7 @@ void json::update(const_iterator first, const_iterator last)
|
||||
|
||||
if (JSON_UNLIKELY(not is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(312, "cannot use update() with", type_name()));
|
||||
}
|
||||
|
||||
// check if range iterators belong to the same JSON object
|
||||
@@ -1156,7 +1168,7 @@ json json::patch(const json& json_patch) const
|
||||
if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
|
||||
{
|
||||
// avoid undefined behavior
|
||||
JSON_THROW(out_of_range::create(401, "array index " + Twine(idx) + " is out of range"));
|
||||
JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1194,7 +1206,7 @@ json json::patch(const json& json_patch) const
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(out_of_range::create(403, "key '" + Twine(last_path) + "' not found"));
|
||||
JSON_THROW(out_of_range::create(403, fmt::format("key '{}' not found", last_path)));
|
||||
}
|
||||
}
|
||||
else if (parent.is_array())
|
||||
@@ -1227,13 +1239,13 @@ json json::patch(const json& json_patch) const
|
||||
// check if desired value is present
|
||||
if (JSON_UNLIKELY(it == val.m_value.object->end()))
|
||||
{
|
||||
JSON_THROW(parse_error::create(105, 0, Twine(error_msg) + " must have member '" + Twine(member) + "'"));
|
||||
JSON_THROW(parse_error::create(105, 0, fmt::format("{} must have member '{}'", error_msg, member)));
|
||||
}
|
||||
|
||||
// check if result is of type string
|
||||
if (JSON_UNLIKELY(string_type and not it->second.is_string()))
|
||||
{
|
||||
JSON_THROW(parse_error::create(105, 0, Twine(error_msg) + " must have string member '" + Twine(member) + "'"));
|
||||
JSON_THROW(parse_error::create(105, 0, fmt::format("{} must have string member '{}'", error_msg, member)));
|
||||
}
|
||||
|
||||
// no error: return value
|
||||
@@ -1321,7 +1333,7 @@ json json::patch(const json& json_patch) const
|
||||
// throw an exception if test fails
|
||||
if (JSON_UNLIKELY(not success))
|
||||
{
|
||||
JSON_THROW(other_error::create(501, "unsuccessful: " + Twine(val.dump())));
|
||||
JSON_THROW(other_error::create(501, fmt::format("unsuccessful: {}", val.dump())));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1331,7 +1343,7 @@ json json::patch(const json& json_patch) const
|
||||
{
|
||||
// op must be "add", "remove", "replace", "move", "copy", or
|
||||
// "test"
|
||||
JSON_THROW(parse_error::create(105, 0, "operation value '" + Twine(op) + "' is invalid"));
|
||||
JSON_THROW(parse_error::create(105, 0, fmt::format("operation value '{}' is invalid", op)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1413,7 +1425,7 @@ json json::diff(const json& source, const json& target,
|
||||
for (auto it = source.cbegin(); it != source.cend(); ++it)
|
||||
{
|
||||
// escape the key name to be used in a JSON patch
|
||||
const auto key = json_pointer::escape(it.key());
|
||||
const auto key = json_pointer::escape(std::string{it.key()});
|
||||
|
||||
if (target.find(it.key()) != target.end())
|
||||
{
|
||||
@@ -1437,7 +1449,7 @@ json json::diff(const json& source, const json& target,
|
||||
if (source.find(it.key()) == source.end())
|
||||
{
|
||||
// found a key that is not in this -> add it
|
||||
const auto key = json_pointer::escape(it.key());
|
||||
const auto key = json_pointer::escape(std::string{it.key()});
|
||||
result.push_back(
|
||||
{
|
||||
{"op", "add"}, {"path", path + "/" + key},
|
||||
|
||||
@@ -36,6 +36,7 @@ SOFTWARE.
|
||||
|
||||
#include <cmath> // ldexp
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/raw_istream.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -711,7 +712,7 @@ json json::binary_reader::parse_cbor_internal(const bool get_char)
|
||||
|
||||
default: // anything else (0xFF is handled inside the other types)
|
||||
{
|
||||
JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + Twine::utohexstr(current)));
|
||||
JSON_THROW(parse_error::create(112, chars_read, fmt::format("error reading CBOR; last byte: {:#02x}", current)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1034,7 +1035,7 @@ json json::binary_reader::parse_msgpack_internal()
|
||||
default: // anything else
|
||||
{
|
||||
JSON_THROW(parse_error::create(112, chars_read,
|
||||
"error reading MessagePack; last byte: 0x" + Twine::utohexstr(current)));
|
||||
fmt::format("error reading MessagePack; last byte: {:#02x}", current)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1106,7 +1107,8 @@ std::string json::binary_reader::get_cbor_string()
|
||||
|
||||
default:
|
||||
{
|
||||
JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + Twine::utohexstr(current)));
|
||||
JSON_THROW(parse_error::create(113, chars_read,
|
||||
fmt::format("expected a CBOR string; last byte: {:#02x}", current)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1172,7 +1174,7 @@ std::string json::binary_reader::get_msgpack_string()
|
||||
default:
|
||||
{
|
||||
JSON_THROW(parse_error::create(113, chars_read,
|
||||
"expected a MessagePack string; last byte: 0x" + Twine::utohexstr(current)));
|
||||
fmt::format("expected a MessagePack string; last byte: {:#02x}", current)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1200,7 +1202,7 @@ std::string json::binary_reader::get_ubjson_string(const bool get_char)
|
||||
return get_string(get_number<int64_t>());
|
||||
default:
|
||||
JSON_THROW(parse_error::create(113, chars_read,
|
||||
"expected a UBJSON string; last byte: 0x" + Twine::utohexstr(current)));
|
||||
fmt::format("expected a UBJSON string; last byte: {:#02x}", current)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,7 +1222,7 @@ std::pair<std::size_t, int> json::binary_reader::get_ubjson_size_type()
|
||||
if (current != '#')
|
||||
{
|
||||
JSON_THROW(parse_error::create(112, chars_read,
|
||||
"expected '#' after UBJSON type information; last byte: 0x" + Twine::utohexstr(current)));
|
||||
fmt::format("expected '#' after UBJSON type information; last byte: {:#02x}", current)));
|
||||
}
|
||||
sz = parse_ubjson_internal();
|
||||
}
|
||||
@@ -1269,7 +1271,7 @@ json json::binary_reader::get_ubjson_value(const int prefix)
|
||||
if (JSON_UNLIKELY(current > 127))
|
||||
{
|
||||
JSON_THROW(parse_error::create(113, chars_read,
|
||||
"byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + Twine::utohexstr(current)));
|
||||
fmt::format("byte after 'C' must be in range 0x00..0x7F; last byte: {:#02x}", current)));
|
||||
}
|
||||
return std::string(1, static_cast<char>(current));
|
||||
}
|
||||
@@ -1285,7 +1287,7 @@ json json::binary_reader::get_ubjson_value(const int prefix)
|
||||
|
||||
default: // anything else
|
||||
JSON_THROW(parse_error::create(112, chars_read,
|
||||
"error reading UBJSON; last byte: 0x" + Twine::utohexstr(current)));
|
||||
fmt::format("error reading UBJSON; last byte: {:#02x}", current)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1299,7 +1301,7 @@ json json::binary_reader::get_ubjson_array()
|
||||
if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(408,
|
||||
"excessive array size: " + Twine(size_and_type.first)));
|
||||
fmt::format("excessive array size: {}", size_and_type.first)));
|
||||
}
|
||||
|
||||
if (size_and_type.second != 0)
|
||||
@@ -1344,7 +1346,7 @@ json json::binary_reader::get_ubjson_object()
|
||||
if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(408,
|
||||
"excessive object size: " + Twine(size_and_type.first)));
|
||||
fmt::format("excessive object size: {}", size_and_type.first)));
|
||||
}
|
||||
|
||||
if (size_and_type.second != 0)
|
||||
|
||||
@@ -34,6 +34,7 @@ SOFTWARE.
|
||||
#define WPI_JSON_IMPLEMENTATION
|
||||
#include "wpi/json.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -75,9 +76,9 @@ class json::binary_writer
|
||||
const bool use_type, const bool add_prefix = true);
|
||||
|
||||
private:
|
||||
void write_cbor_string(StringRef str);
|
||||
void write_cbor_string(std::string_view str);
|
||||
|
||||
void write_msgpack_string(StringRef str);
|
||||
void write_msgpack_string(std::string_view str);
|
||||
|
||||
/*
|
||||
@brief write a number to output input
|
||||
@@ -630,7 +631,7 @@ void json::binary_writer::write_ubjson(const json& j, const bool use_count,
|
||||
o << static_cast<CharType>('S');
|
||||
}
|
||||
write_number_with_ubjson_prefix(j.m_value.string->size(), true);
|
||||
o << j.m_value.string;
|
||||
o << *j.m_value.string;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -731,7 +732,7 @@ void json::binary_writer::write_ubjson(const json& j, const bool use_count,
|
||||
}
|
||||
}
|
||||
|
||||
void json::binary_writer::write_cbor_string(StringRef str)
|
||||
void json::binary_writer::write_cbor_string(std::string_view str)
|
||||
{
|
||||
// step 1: write control byte and the string length
|
||||
const auto N = str.size();
|
||||
@@ -766,7 +767,7 @@ void json::binary_writer::write_cbor_string(StringRef str)
|
||||
o << str;
|
||||
}
|
||||
|
||||
void json::binary_writer::write_msgpack_string(StringRef str)
|
||||
void json::binary_writer::write_msgpack_string(std::string_view str)
|
||||
{
|
||||
// step 1: write control byte and the string length
|
||||
const auto N = str.size();
|
||||
@@ -862,7 +863,7 @@ void json::binary_writer::write_number_with_ubjson_prefix(const NumberType n,
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(out_of_range::create(407, "number overflow serializing " + Twine(n)));
|
||||
JSON_THROW(out_of_range::create(407, fmt::format("number overflow serializing {}", n)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,7 +916,7 @@ void json::binary_writer::write_number_with_ubjson_prefix(const NumberType n,
|
||||
// LCOV_EXCL_START
|
||||
else
|
||||
{
|
||||
JSON_THROW(out_of_range::create(407, "number overflow serializing " + Twine(n)));
|
||||
JSON_THROW(out_of_range::create(407, fmt::format("number overflow serializing {}", n)));
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ SOFTWARE.
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "wpi/Format.h"
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/raw_istream.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
@@ -336,7 +336,7 @@ class json::lexer
|
||||
}
|
||||
|
||||
/// return current string value
|
||||
StringRef get_string()
|
||||
std::string_view get_string()
|
||||
{
|
||||
return token_buffer;
|
||||
}
|
||||
@@ -1407,7 +1407,7 @@ std::string json::lexer::get_token_string() const
|
||||
if (c <= '\x1F')
|
||||
{
|
||||
// escape control characters
|
||||
ss << "<U+" << format_hex_no_prefix(c, 4, true) << '>';
|
||||
ss << fmt::format("<U+{:04X}>", c);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1605,7 +1605,7 @@ void json::parser::parse_internal(bool keep, json& result)
|
||||
|
||||
if (keep and keep_tag and not value.is_discarded())
|
||||
{
|
||||
result.m_value.object->try_emplace(StringRef(key.data(), key.size()), std::move(value));
|
||||
result.m_value.object->try_emplace(std::string_view(key.data(), key.size()), std::move(value));
|
||||
}
|
||||
|
||||
// comma -> next value
|
||||
@@ -1757,8 +1757,8 @@ void json::parser::parse_internal(bool keep, json& result)
|
||||
{
|
||||
if (allow_exceptions)
|
||||
{
|
||||
JSON_THROW(out_of_range::create(406, "number overflow parsing '" +
|
||||
Twine(m_lexer.get_token_string()) + "'"));
|
||||
JSON_THROW(out_of_range::create(406,
|
||||
fmt::format("number overflow parsing '{}'", m_lexer.get_token_string())));
|
||||
}
|
||||
expect(token_type::uninitialized);
|
||||
}
|
||||
@@ -1917,7 +1917,7 @@ void json::parser::throw_exception() const
|
||||
JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg));
|
||||
}
|
||||
|
||||
json json::parse(StringRef s,
|
||||
json json::parse(std::string_view s,
|
||||
const parser_callback_t cb,
|
||||
const bool allow_exceptions)
|
||||
{
|
||||
@@ -1942,7 +1942,7 @@ json json::parse(raw_istream& i,
|
||||
return result;
|
||||
}
|
||||
|
||||
bool json::accept(StringRef s)
|
||||
bool json::accept(std::string_view s)
|
||||
{
|
||||
raw_mem_istream is(makeArrayRef(s.data(), s.size()));
|
||||
return parser(is).accept(true);
|
||||
|
||||
@@ -36,7 +36,9 @@ SOFTWARE.
|
||||
|
||||
#include <numeric> // accumulate
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -50,17 +52,16 @@ std::string json_pointer::to_string() const noexcept
|
||||
});
|
||||
}
|
||||
|
||||
int json_pointer::array_index(const Twine& s)
|
||||
int json_pointer::array_index(std::string_view s)
|
||||
{
|
||||
SmallString<128> buf;
|
||||
StringRef str = s.toNullTerminatedStringRef(buf);
|
||||
SmallString<128> str{s};
|
||||
std::size_t processed_chars = 0;
|
||||
const int res = std::stoi(str, &processed_chars);
|
||||
const int res = std::stoi(str.c_str(), &processed_chars);
|
||||
|
||||
// check if the string was completely read
|
||||
if (JSON_UNLIKELY(processed_chars != str.size()))
|
||||
{
|
||||
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + Twine(s) + "'"));
|
||||
JSON_THROW(detail::out_of_range::create(404, fmt::format("unresolved reference token '{}'", s)));
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -108,7 +109,7 @@ json& json_pointer::get_and_create(json& j) const
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + Twine(reference_token) + "' is not a number"));
|
||||
JSON_THROW(detail::parse_error::create(109, 0, fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -164,8 +165,7 @@ json& json_pointer::get_unchecked(json* ptr) const
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
"array index '" + Twine(reference_token) +
|
||||
"' must not begin with '0'"));
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
if (reference_token == "-")
|
||||
@@ -183,14 +183,16 @@ json& json_pointer::get_unchecked(json* ptr) const
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + Twine(reference_token) + "' is not a number"));
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + Twine(reference_token) + "'"));
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,16 +219,14 @@ json& json_pointer::get_checked(json* ptr) const
|
||||
{
|
||||
// "-" always fails the range check
|
||||
JSON_THROW(detail::out_of_range::create(402,
|
||||
"array index '-' (" + Twine(ptr->m_value.array->size()) +
|
||||
") is out of range"));
|
||||
fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
|
||||
}
|
||||
|
||||
// error condition (cf. RFC 6901, Sect. 4)
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
"array index '" + Twine(reference_token) +
|
||||
"' must not begin with '0'"));
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
// note: at performs range check
|
||||
@@ -236,13 +236,15 @@ json& json_pointer::get_checked(json* ptr) const
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + Twine(reference_token) + "' is not a number"));
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + Twine(reference_token) + "'"));
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,16 +271,14 @@ const json& json_pointer::get_unchecked(const json* ptr) const
|
||||
{
|
||||
// "-" cannot be used for const access
|
||||
JSON_THROW(detail::out_of_range::create(402,
|
||||
"array index '-' (" + Twine(ptr->m_value.array->size()) +
|
||||
") is out of range"));
|
||||
fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
|
||||
}
|
||||
|
||||
// error condition (cf. RFC 6901, Sect. 4)
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
"array index '" + Twine(reference_token) +
|
||||
"' must not begin with '0'"));
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
// use unchecked array access
|
||||
@@ -289,13 +289,15 @@ const json& json_pointer::get_unchecked(const json* ptr) const
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + Twine(reference_token) + "' is not a number"));
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + Twine(reference_token) + "'"));
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,16 +324,14 @@ const json& json_pointer::get_checked(const json* ptr) const
|
||||
{
|
||||
// "-" always fails the range check
|
||||
JSON_THROW(detail::out_of_range::create(402,
|
||||
"array index '-' (" + Twine(ptr->m_value.array->size()) +
|
||||
") is out of range"));
|
||||
fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
|
||||
}
|
||||
|
||||
// error condition (cf. RFC 6901, Sect. 4)
|
||||
if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(106, 0,
|
||||
"array index '" + Twine(reference_token) +
|
||||
"' must not begin with '0'"));
|
||||
fmt::format("array index '{}' must not begin with '0'", reference_token)));
|
||||
}
|
||||
|
||||
// note: at performs range check
|
||||
@@ -341,23 +341,23 @@ const json& json_pointer::get_checked(const json* ptr) const
|
||||
}
|
||||
JSON_CATCH(std::invalid_argument&)
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + Twine(reference_token) + "' is not a number"));
|
||||
JSON_THROW(detail::parse_error::create(109, 0,
|
||||
fmt::format("array index '{}' is not a number", reference_token)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + Twine(reference_token) + "'"));
|
||||
JSON_THROW(detail::out_of_range::create(404,
|
||||
fmt::format("unresolved reference token '{}'", reference_token)));
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> json_pointer::split(const Twine& reference_string)
|
||||
std::vector<std::string> json_pointer::split(std::string_view ref_str)
|
||||
{
|
||||
SmallString<128> ref_str_buf;
|
||||
StringRef ref_str = reference_string.toStringRef(ref_str_buf);
|
||||
std::vector<std::string> result;
|
||||
|
||||
// special case: empty reference string -> no reference tokens
|
||||
@@ -370,8 +370,7 @@ std::vector<std::string> json_pointer::split(const Twine& reference_string)
|
||||
if (JSON_UNLIKELY(ref_str[0] != '/'))
|
||||
{
|
||||
JSON_THROW(detail::parse_error::create(107, 1,
|
||||
"JSON pointer must be empty or begin with '/' - was: '" +
|
||||
Twine(ref_str) + "'"));
|
||||
fmt::format("JSON pointer must be empty or begin with '/' - was: '{}'", ref_str)));
|
||||
}
|
||||
|
||||
// extract the reference tokens:
|
||||
@@ -392,11 +391,11 @@ std::vector<std::string> json_pointer::split(const Twine& reference_string)
|
||||
{
|
||||
// use the text between the beginning of the reference token
|
||||
// (start) and the last slash (slash).
|
||||
auto reference_token = ref_str.slice(start, slash);
|
||||
auto reference_token = slice(ref_str, start, slash);
|
||||
|
||||
// check reference tokens are properly escaped
|
||||
for (std::size_t pos = reference_token.find_first_of('~');
|
||||
pos != StringRef::npos;
|
||||
pos != std::string_view::npos;
|
||||
pos = reference_token.find_first_of('~', pos + 1))
|
||||
{
|
||||
assert(reference_token[pos] == '~');
|
||||
@@ -411,7 +410,7 @@ std::vector<std::string> json_pointer::split(const Twine& reference_string)
|
||||
}
|
||||
|
||||
// finally, store the reference token
|
||||
std::string ref_tok = reference_token;
|
||||
std::string ref_tok{reference_token};
|
||||
unescape(ref_tok);
|
||||
result.emplace_back(std::move(ref_tok));
|
||||
}
|
||||
@@ -444,7 +443,7 @@ void json_pointer::unescape(std::string& s)
|
||||
replace_substring(s, "~0", "~");
|
||||
}
|
||||
|
||||
void json_pointer::flatten(const Twine& reference_string,
|
||||
void json_pointer::flatten(std::string_view reference_string,
|
||||
const json& value,
|
||||
json& result)
|
||||
{
|
||||
@@ -455,15 +454,14 @@ void json_pointer::flatten(const Twine& reference_string,
|
||||
if (value.m_value.array->empty())
|
||||
{
|
||||
// flatten empty array as null
|
||||
SmallString<64> buf;
|
||||
result[reference_string.toStringRef(buf)] = nullptr;
|
||||
result[reference_string] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate array and use index as reference string
|
||||
for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
|
||||
{
|
||||
flatten(reference_string + "/" + Twine(i),
|
||||
flatten(fmt::format("{}/{}", reference_string, i),
|
||||
value.m_value.array->operator[](i), result);
|
||||
}
|
||||
}
|
||||
@@ -475,15 +473,14 @@ void json_pointer::flatten(const Twine& reference_string,
|
||||
if (value.m_value.object->empty())
|
||||
{
|
||||
// flatten empty object as null
|
||||
SmallString<64> buf;
|
||||
result[reference_string.toStringRef(buf)] = nullptr;
|
||||
result[reference_string] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate object and use keys as reference string
|
||||
for (const auto& element : *value.m_value.object)
|
||||
{
|
||||
flatten(reference_string + "/" + Twine(escape(element.first())), element.second, result);
|
||||
flatten(fmt::format("{}/{}", reference_string, escape(std::string{element.first()})), element.second, result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -492,8 +489,7 @@ void json_pointer::flatten(const Twine& reference_string,
|
||||
default:
|
||||
{
|
||||
// add primitive value with its reference string
|
||||
SmallString<64> buf;
|
||||
result[reference_string.toStringRef(buf)] = value;
|
||||
result[reference_string] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,8 @@ SOFTWARE.
|
||||
#define WPI_JSON_IMPLEMENTATION
|
||||
#include "wpi/json.h"
|
||||
|
||||
#include "wpi/Format.h"
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/raw_os_ostream.h"
|
||||
|
||||
#include "json_serializer.h"
|
||||
@@ -1332,7 +1331,7 @@ void json::serializer::dump(const json& val, const bool pretty_print,
|
||||
}
|
||||
}
|
||||
|
||||
void json::serializer::dump_escaped(StringRef s, const bool ensure_ascii)
|
||||
void json::serializer::dump_escaped(std::string_view s, const bool ensure_ascii)
|
||||
{
|
||||
uint32_t codepoint;
|
||||
uint8_t state = UTF8_ACCEPT;
|
||||
@@ -1397,12 +1396,12 @@ void json::serializer::dump_escaped(StringRef s, const bool ensure_ascii)
|
||||
{
|
||||
if (codepoint <= 0xFFFF)
|
||||
{
|
||||
o << '\\' << 'u' << format_hex_no_prefix(codepoint, 4);
|
||||
o << fmt::format("\\u{:04x}", codepoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
o << '\\' << 'u' << format_hex_no_prefix(0xD7C0 + (codepoint >> 10), 4);
|
||||
o << '\\' << 'u' << format_hex_no_prefix(0xDC00 + (codepoint & 0x3FF), 4);
|
||||
o << fmt::format("\\u{:04x}", 0xD7C0 + (codepoint >> 10));
|
||||
o << fmt::format("\\u{:04x}", 0xDC00 + (codepoint & 0x3FF));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1419,7 +1418,7 @@ void json::serializer::dump_escaped(StringRef s, const bool ensure_ascii)
|
||||
|
||||
case UTF8_REJECT: // decode found invalid UTF-8 byte
|
||||
{
|
||||
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + Twine(i) + ": 0x" + Twine::utohexstr(byte)));
|
||||
JSON_THROW(type_error::create(316, fmt::format("invalid UTF-8 byte at index {}: {:#02x}", i, byte)));
|
||||
}
|
||||
|
||||
default: // decode found yet incomplete multi-byte code point
|
||||
@@ -1437,7 +1436,7 @@ void json::serializer::dump_escaped(StringRef s, const bool ensure_ascii)
|
||||
if (JSON_UNLIKELY(state != UTF8_ACCEPT))
|
||||
{
|
||||
// we finish reading, but do not accept: string was incomplete
|
||||
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + Twine::utohexstr(static_cast<uint8_t>(s.back()))));
|
||||
JSON_THROW(type_error::create(316, fmt::format("incomplete UTF-8 string; last byte: {:#02x}", s.back())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ class json::serializer
|
||||
|
||||
@complexity Linear in the length of string @a s.
|
||||
*/
|
||||
void dump_escaped(StringRef s, const bool ensure_ascii);
|
||||
void dump_escaped(std::string_view s, const bool ensure_ascii);
|
||||
|
||||
template <typename NumberType,
|
||||
detail::enable_if_t<std::is_same_v<NumberType, uint64_t>, int> = 0>
|
||||
|
||||
@@ -744,10 +744,10 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
|
||||
namespace sys {
|
||||
namespace windows {
|
||||
std::error_code CodePageToUTF16(unsigned codepage,
|
||||
wpi::StringRef original,
|
||||
std::string_view original,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
if (!original.empty()) {
|
||||
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
|
||||
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), 0);
|
||||
|
||||
if (len == 0) {
|
||||
@@ -757,7 +757,7 @@ std::error_code CodePageToUTF16(unsigned codepage,
|
||||
utf16.reserve(len + 1);
|
||||
utf16.set_size(len);
|
||||
|
||||
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
|
||||
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), utf16.size());
|
||||
|
||||
if (len == 0) {
|
||||
@@ -772,12 +772,12 @@ std::error_code CodePageToUTF16(unsigned codepage,
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code UTF8ToUTF16(wpi::StringRef utf8,
|
||||
std::error_code UTF8ToUTF16(std::string_view utf8,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_UTF8, utf8, utf16);
|
||||
}
|
||||
|
||||
std::error_code CurCPToUTF16(wpi::StringRef curcp,
|
||||
std::error_code CurCPToUTF16(std::string_view curcp,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_ACP, curcp, utf16);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ bool convertUTF16ToUTF8String(ArrayRef<UTF16> SrcUTF16,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertUTF8ToUTF16String(StringRef SrcUTF8,
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16) {
|
||||
assert(DstUTF16.empty());
|
||||
|
||||
@@ -91,8 +91,8 @@ bool convertUTF8ToUTF16String(StringRef SrcUTF8,
|
||||
return true;
|
||||
}
|
||||
|
||||
const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.begin());
|
||||
const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.end());
|
||||
const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.data());
|
||||
const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.data() + SrcUTF8.size());
|
||||
|
||||
// Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding
|
||||
// as UTF-16 should always require the same amount or less code units than the
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
//===----- lib/Support/Error.cpp - Error and associated utilities ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/Error.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/ManagedStatic.h"
|
||||
#include <system_error>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
namespace {
|
||||
|
||||
enum class ErrorErrorCode : int {
|
||||
MultipleErrors = 1,
|
||||
FileError,
|
||||
InconvertibleError
|
||||
};
|
||||
|
||||
// FIXME: This class is only here to support the transition to wpi::Error. It
|
||||
// will be removed once this transition is complete. Clients should prefer to
|
||||
// deal with the Error value directly, rather than converting to error_code.
|
||||
class ErrorErrorCategory : public std::error_category {
|
||||
public:
|
||||
const char *name() const noexcept override { return "Error"; }
|
||||
|
||||
std::string message(int condition) const override {
|
||||
switch (static_cast<ErrorErrorCode>(condition)) {
|
||||
case ErrorErrorCode::MultipleErrors:
|
||||
return "Multiple errors";
|
||||
case ErrorErrorCode::InconvertibleError:
|
||||
return "Inconvertible error value. An error has occurred that could "
|
||||
"not be converted to a known std::error_code. Please file a "
|
||||
"bug.";
|
||||
case ErrorErrorCode::FileError:
|
||||
return "A file error occurred.";
|
||||
}
|
||||
wpi_unreachable("Unhandled error code");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
|
||||
|
||||
namespace wpi {
|
||||
|
||||
void ErrorInfoBase::anchor() {}
|
||||
char ErrorInfoBase::ID = 0;
|
||||
char ErrorList::ID = 0;
|
||||
void ECError::anchor() {}
|
||||
char ECError::ID = 0;
|
||||
char StringError::ID = 0;
|
||||
char FileError::ID = 0;
|
||||
|
||||
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {
|
||||
if (!E)
|
||||
return;
|
||||
OS << ErrorBanner;
|
||||
handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
|
||||
EI.log(OS);
|
||||
OS << "\n";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
std::error_code ErrorList::convertToErrorCode() const {
|
||||
return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
|
||||
*ErrorErrorCat);
|
||||
}
|
||||
|
||||
std::error_code inconvertibleErrorCode() {
|
||||
return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError),
|
||||
*ErrorErrorCat);
|
||||
}
|
||||
|
||||
std::error_code FileError::convertToErrorCode() const {
|
||||
return std::error_code(static_cast<int>(ErrorErrorCode::FileError),
|
||||
*ErrorErrorCat);
|
||||
}
|
||||
|
||||
Error errorCodeToError(std::error_code EC) {
|
||||
if (!EC)
|
||||
return Error::success();
|
||||
return Error(std::make_unique<ECError>(ECError(EC)));
|
||||
}
|
||||
|
||||
std::error_code errorToErrorCode(Error Err) {
|
||||
std::error_code EC;
|
||||
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
|
||||
EC = EI.convertToErrorCode();
|
||||
});
|
||||
if (EC == inconvertibleErrorCode())
|
||||
report_fatal_error(EC.message());
|
||||
return EC;
|
||||
}
|
||||
|
||||
StringError::StringError(std::error_code EC, const Twine &S)
|
||||
: Msg(S.str()), EC(EC) {}
|
||||
|
||||
StringError::StringError(const Twine &S, std::error_code EC)
|
||||
: Msg(S.str()), EC(EC), PrintMsgOnly(true) {}
|
||||
|
||||
void StringError::log(raw_ostream &OS) const {
|
||||
if (PrintMsgOnly) {
|
||||
OS << Msg;
|
||||
} else {
|
||||
OS << EC.message();
|
||||
if (!Msg.empty())
|
||||
OS << (" " + Msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code StringError::convertToErrorCode() const {
|
||||
return EC;
|
||||
}
|
||||
|
||||
Error createStringError(std::error_code EC, char const *Msg) {
|
||||
return make_error<StringError>(Msg, EC);
|
||||
}
|
||||
|
||||
void report_fatal_error(Error Err, bool GenCrashDiag) {
|
||||
assert(Err && "report_fatal_error called with success value");
|
||||
std::string ErrMsg;
|
||||
{
|
||||
raw_string_ostream ErrStream(ErrMsg);
|
||||
logAllUnhandledErrors(std::move(Err), ErrStream);
|
||||
}
|
||||
report_fatal_error(ErrMsg);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
@@ -14,11 +14,10 @@
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/Error.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "fmt/format.h"
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
@@ -68,18 +67,14 @@ void wpi::remove_fatal_error_handler() {
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const char *Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
|
||||
void wpi::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
|
||||
wpi::fatal_error_handler_t handler = nullptr;
|
||||
void* handlerData = nullptr;
|
||||
{
|
||||
@@ -91,21 +86,9 @@ void wpi::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(handlerData, Reason.str(), GenCrashDiag);
|
||||
handler(handlerData, std::string{Reason}, GenCrashDiag);
|
||||
} else {
|
||||
// Blast the result out to stderr. We don't try hard to make sure this
|
||||
// succeeds (e.g. handling EINTR) and we can't use errs() here because
|
||||
// raw ostreams can call report_fatal_error.
|
||||
SmallVector<char, 64> Buffer;
|
||||
raw_svector_ostream OS(Buffer);
|
||||
OS << "LLVM ERROR: " << Reason << "\n";
|
||||
StringRef MessageStr = OS.str();
|
||||
#ifdef _WIN32
|
||||
int written = ::_write(2, MessageStr.data(), MessageStr.size());
|
||||
#else
|
||||
ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
|
||||
#endif
|
||||
(void)written; // If something went wrong, we deliberately just give up.
|
||||
fmt::print(stderr, "LLVM ERROR: {}\n");
|
||||
}
|
||||
|
||||
exit(1);
|
||||
@@ -185,11 +168,11 @@ void wpi::wpi_unreachable_internal(const char *msg, const char *file,
|
||||
// wpi_unreachable is intended to be used to indicate "impossible"
|
||||
// situations, and not legitimate runtime errors.
|
||||
if (msg)
|
||||
errs() << msg << "\n";
|
||||
errs() << "UNREACHABLE executed";
|
||||
fmt::print(stderr, "{}\n", msg);
|
||||
std::fputs("UNREACHABLE executed", stderr);
|
||||
if (file)
|
||||
errs() << " at " << file << ":" << line;
|
||||
errs() << "!\n";
|
||||
fmt::print(stderr, " at {}:{}", file, line);
|
||||
fmt::print(stderr, "{}", "!\n");
|
||||
abort();
|
||||
#ifdef LLVM_BUILTIN_UNREACHABLE
|
||||
// Windows systems and possibly others don't declare abort() to be noreturn,
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/NativeFormatting.h"
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Format.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
static int format_to_buffer(T Value, char (&Buffer)[N]) {
|
||||
char *EndPtr = std::end(Buffer);
|
||||
char *CurPtr = EndPtr;
|
||||
|
||||
do {
|
||||
*--CurPtr = '0' + char(Value % 10);
|
||||
Value /= 10;
|
||||
} while (Value);
|
||||
return EndPtr - CurPtr;
|
||||
}
|
||||
|
||||
static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
|
||||
assert(!Buffer.empty());
|
||||
|
||||
ArrayRef<char> ThisGroup;
|
||||
int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
|
||||
ThisGroup = Buffer.take_front(InitialDigits);
|
||||
S.write(ThisGroup.data(), ThisGroup.size());
|
||||
|
||||
Buffer = Buffer.drop_front(InitialDigits);
|
||||
assert(Buffer.size() % 3 == 0);
|
||||
while (!Buffer.empty()) {
|
||||
S << ',';
|
||||
ThisGroup = Buffer.take_front(3);
|
||||
S.write(ThisGroup.data(), 3);
|
||||
Buffer = Buffer.drop_front(3);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style, bool IsNegative) {
|
||||
static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
|
||||
|
||||
char NumberBuffer[128];
|
||||
std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
|
||||
|
||||
size_t Len = 0;
|
||||
Len = format_to_buffer(N, NumberBuffer);
|
||||
|
||||
if (IsNegative)
|
||||
S << '-';
|
||||
|
||||
if (Len < MinDigits && Style != IntegerStyle::Number) {
|
||||
for (size_t I = Len; I < MinDigits; ++I)
|
||||
S << '0';
|
||||
}
|
||||
|
||||
if (Style == IntegerStyle::Number) {
|
||||
writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
|
||||
} else {
|
||||
S.write(std::end(NumberBuffer) - Len, Len);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style, bool IsNegative = false) {
|
||||
// Output using 32-bit div/mod if possible.
|
||||
if (N == static_cast<uint32_t>(N))
|
||||
write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
|
||||
IsNegative);
|
||||
else
|
||||
write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_signed(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
static_assert(std::is_signed<T>::value, "Value is not signed!");
|
||||
|
||||
using UnsignedT = typename std::make_unsigned<T>::type;
|
||||
|
||||
if (N >= 0) {
|
||||
write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
|
||||
return;
|
||||
}
|
||||
|
||||
UnsignedT UN = -(UnsignedT)N;
|
||||
write_unsigned(S, UN, MinDigits, Style, true);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, int N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, long long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
|
||||
std::optional<size_t> Width) {
|
||||
const size_t kMaxWidth = 128u;
|
||||
|
||||
size_t W = std::min(kMaxWidth, Width.value_or(0u));
|
||||
|
||||
unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
|
||||
bool Prefix = (Style == HexPrintStyle::PrefixLower ||
|
||||
Style == HexPrintStyle::PrefixUpper);
|
||||
bool Upper =
|
||||
(Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
|
||||
unsigned PrefixChars = Prefix ? 2 : 0;
|
||||
unsigned NumChars =
|
||||
std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
|
||||
|
||||
char NumberBuffer[kMaxWidth];
|
||||
::memset(NumberBuffer, '0', wpi::array_lengthof(NumberBuffer));
|
||||
if (Prefix)
|
||||
NumberBuffer[1] = 'x';
|
||||
char *EndPtr = NumberBuffer + NumChars;
|
||||
char *CurPtr = EndPtr;
|
||||
while (N) {
|
||||
unsigned char x = static_cast<unsigned char>(N) % 16;
|
||||
*--CurPtr = hexdigit(x, !Upper);
|
||||
N /= 16;
|
||||
}
|
||||
|
||||
S.write(NumberBuffer, NumChars);
|
||||
}
|
||||
|
||||
void wpi::write_double(raw_ostream &S, double N, FloatStyle Style,
|
||||
std::optional<size_t> Precision) {
|
||||
size_t Prec = Precision.value_or(getDefaultPrecision(Style));
|
||||
|
||||
if (std::isnan(N)) {
|
||||
S << "nan";
|
||||
return;
|
||||
} else if (std::isinf(N)) {
|
||||
S << "INF";
|
||||
return;
|
||||
}
|
||||
|
||||
char Letter;
|
||||
if (Style == FloatStyle::Exponent)
|
||||
Letter = 'e';
|
||||
else if (Style == FloatStyle::ExponentUpper)
|
||||
Letter = 'E';
|
||||
else
|
||||
Letter = 'f';
|
||||
|
||||
SmallString<8> Spec;
|
||||
wpi::raw_svector_ostream Out(Spec);
|
||||
Out << "%." << Prec << Letter;
|
||||
|
||||
if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
|
||||
#ifdef _WIN32
|
||||
// On MSVCRT and compatible, output of %e is incompatible to Posix
|
||||
// by default. Number of exponent digits should be at least 2. "%+03d"
|
||||
// FIXME: Implement our formatter to here or Support/Format.h!
|
||||
#if defined(__MINGW32__)
|
||||
// FIXME: It should be generic to C++11.
|
||||
if (N == 0.0 && std::signbit(N)) {
|
||||
char NegativeZero[] = "-0.000000e+00";
|
||||
if (Style == FloatStyle::ExponentUpper)
|
||||
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
||||
S << NegativeZero;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
int fpcl = _fpclass(N);
|
||||
|
||||
// negative zero
|
||||
if (fpcl == _FPCLASS_NZ) {
|
||||
char NegativeZero[] = "-0.000000e+00";
|
||||
if (Style == FloatStyle::ExponentUpper)
|
||||
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
||||
S << NegativeZero;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
char buf[32];
|
||||
unsigned len;
|
||||
len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
|
||||
if (len <= sizeof(buf) - 2) {
|
||||
if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
|
||||
buf[len - 3] == '0') {
|
||||
int cs = buf[len - 4];
|
||||
if (cs == '+' || cs == '-') {
|
||||
int c1 = buf[len - 2];
|
||||
int c0 = buf[len - 1];
|
||||
if (isdigit(static_cast<unsigned char>(c1)) &&
|
||||
isdigit(static_cast<unsigned char>(c0))) {
|
||||
// Trim leading '0': "...e+012" -> "...e+12\0"
|
||||
buf[len - 3] = c1;
|
||||
buf[len - 2] = c0;
|
||||
buf[--len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
S << buf;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Style == FloatStyle::Percent)
|
||||
N *= 100.0;
|
||||
|
||||
char Buf[32];
|
||||
format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
|
||||
S << Buf;
|
||||
if (Style == FloatStyle::Percent)
|
||||
S << '%';
|
||||
}
|
||||
|
||||
bool wpi::isPrefixedHexStyle(HexPrintStyle S) {
|
||||
return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
|
||||
}
|
||||
|
||||
size_t wpi::getDefaultPrecision(FloatStyle Style) {
|
||||
switch (Style) {
|
||||
case FloatStyle::Exponent:
|
||||
case FloatStyle::ExponentUpper:
|
||||
return 6; // Number of decimal places.
|
||||
case FloatStyle::Fixed:
|
||||
case FloatStyle::Percent:
|
||||
return 2; // Number of decimal places.
|
||||
}
|
||||
LLVM_BUILTIN_UNREACHABLE;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ void StringMapImpl::init(unsigned InitSize) {
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) { // Hash table unallocated so far?
|
||||
init(16);
|
||||
@@ -128,7 +128,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
// Do the comparison like this because Name isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char*)BucketItem+ItemSize;
|
||||
if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) {
|
||||
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int StringMapImpl::FindKey(StringRef Key) const {
|
||||
int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) return -1; // Really empty table?
|
||||
unsigned FullHashValue = HashString(Key);
|
||||
@@ -171,7 +171,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
|
||||
// Do the comparison like this because NameStart isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char*)BucketItem+ItemSize;
|
||||
if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) {
|
||||
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
@@ -190,14 +190,14 @@ int StringMapImpl::FindKey(StringRef Key) const {
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
const char *VStr = (char*)V + ItemSize;
|
||||
StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength()));
|
||||
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
|
||||
(void)V2;
|
||||
assert(V == V2 && "Didn't find key?");
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return nullptr;
|
||||
|
||||
|
||||
@@ -1,507 +0,0 @@
|
||||
//===-- StringRef.cpp - Lightweight String References ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <bitset>
|
||||
#include <climits>
|
||||
#include <ostream>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
// MSVC emits references to this into the translation units which reference it.
|
||||
#ifndef _MSC_VER
|
||||
const size_t StringRef::npos;
|
||||
#endif
|
||||
|
||||
// strncasecmp() is not available on non-POSIX systems, so define an
|
||||
// alternative function here.
|
||||
static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) noexcept {
|
||||
for (size_t I = 0; I < Length; ++I) {
|
||||
unsigned char LHC = toLower(LHS[I]);
|
||||
unsigned char RHC = toLower(RHS[I]);
|
||||
if (LHC != RHC)
|
||||
return LHC < RHC ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// compare_lower - Compare strings, ignoring case.
|
||||
int StringRef::compare_lower(StringRef RHS) const noexcept {
|
||||
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(Length, RHS.Length)))
|
||||
return Res;
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
/// Check if this string starts with the given \p Prefix, ignoring case.
|
||||
bool StringRef::startswith_lower(StringRef Prefix) const noexcept {
|
||||
return Length >= Prefix.Length &&
|
||||
ascii_strncasecmp(Data, Prefix.Data, Prefix.Length) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string ends with the given \p Suffix, ignoring case.
|
||||
bool StringRef::endswith_lower(StringRef Suffix) const noexcept {
|
||||
return Length >= Suffix.Length &&
|
||||
ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
|
||||
}
|
||||
|
||||
size_t StringRef::find_lower(char C, size_t From) const noexcept {
|
||||
char L = toLower(C);
|
||||
return find_if([L](char D) { return toLower(D) == L; }, From);
|
||||
}
|
||||
|
||||
/// compare_numeric - Compare strings, handle embedded numbers.
|
||||
int StringRef::compare_numeric(StringRef RHS) const noexcept {
|
||||
for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) {
|
||||
// Check for sequences of digits.
|
||||
if (isDigit(Data[I]) && isDigit(RHS.Data[I])) {
|
||||
// The longer sequence of numbers is considered larger.
|
||||
// This doesn't really handle prefixed zeros well.
|
||||
size_t J;
|
||||
for (J = I + 1; J != E + 1; ++J) {
|
||||
bool ld = J < Length && isDigit(Data[J]);
|
||||
bool rd = J < RHS.Length && isDigit(RHS.Data[J]);
|
||||
if (ld != rd)
|
||||
return rd ? -1 : 1;
|
||||
if (!rd)
|
||||
break;
|
||||
}
|
||||
// The two number sequences have the same length (J-I), just memcmp them.
|
||||
if (int Res = compareMemory(Data + I, RHS.Data + I, J - I))
|
||||
return Res < 0 ? -1 : 1;
|
||||
// Identical number sequences, continue search after the numbers.
|
||||
I = J - 1;
|
||||
continue;
|
||||
}
|
||||
if (Data[I] != RHS.Data[I])
|
||||
return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1;
|
||||
}
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// String Operations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
std::string StringRef::lower() const {
|
||||
std::string Result(size(), char());
|
||||
for (size_type i = 0, e = size(); i != e; ++i) {
|
||||
Result[i] = toLower(Data[i]);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string StringRef::upper() const {
|
||||
std::string Result(size(), char());
|
||||
for (size_type i = 0, e = size(); i != e; ++i) {
|
||||
Result[i] = toUpper(Data[i]);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// String Searching
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/// find - Search for the first string \arg Str in the string.
|
||||
///
|
||||
/// \return - The index of the first occurrence of \arg Str, or npos if not
|
||||
/// found.
|
||||
size_t StringRef::find(StringRef Str, size_t From) const noexcept {
|
||||
if (From > Length)
|
||||
return npos;
|
||||
|
||||
const char *Start = Data + From;
|
||||
size_t Size = Length - From;
|
||||
|
||||
const char *Needle = Str.data();
|
||||
size_t N = Str.size();
|
||||
if (N == 0)
|
||||
return From;
|
||||
if (Size < N)
|
||||
return npos;
|
||||
if (N == 1) {
|
||||
const char *Ptr = (const char *)::memchr(Start, Needle[0], Size);
|
||||
return Ptr == nullptr ? npos : Ptr - Data;
|
||||
}
|
||||
|
||||
const char *Stop = Start + (Size - N + 1);
|
||||
|
||||
// For short haystacks or unsupported needles fall back to the naive algorithm
|
||||
if (Size < 16 || N > 255) {
|
||||
do {
|
||||
if (std::memcmp(Start, Needle, N) == 0)
|
||||
return Start - Data;
|
||||
++Start;
|
||||
} while (Start < Stop);
|
||||
return npos;
|
||||
}
|
||||
|
||||
// Build the bad char heuristic table, with uint8_t to reduce cache thrashing.
|
||||
uint8_t BadCharSkip[256];
|
||||
std::memset(BadCharSkip, N, 256);
|
||||
for (unsigned i = 0; i != N-1; ++i)
|
||||
BadCharSkip[(uint8_t)Str[i]] = N-1-i;
|
||||
|
||||
do {
|
||||
uint8_t Last = Start[N - 1];
|
||||
if (LLVM_UNLIKELY(Last == (uint8_t)Needle[N - 1]))
|
||||
if (std::memcmp(Start, Needle, N - 1) == 0)
|
||||
return Start - Data;
|
||||
|
||||
// Otherwise skip the appropriate number of bytes.
|
||||
Start += BadCharSkip[Last];
|
||||
} while (Start < Stop);
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::find_lower(StringRef Str, size_t From) const noexcept {
|
||||
StringRef This = substr(From);
|
||||
while (This.size() >= Str.size()) {
|
||||
if (This.startswith_lower(Str))
|
||||
return From;
|
||||
This = This.drop_front();
|
||||
++From;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::rfind_lower(char C, size_t From) const noexcept {
|
||||
From = std::min(From, Length);
|
||||
size_t i = From;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
if (toLower(Data[i]) == toLower(C))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// rfind - Search for the last string \arg Str in the string.
|
||||
///
|
||||
/// \return - The index of the last occurrence of \arg Str, or npos if not
|
||||
/// found.
|
||||
size_t StringRef::rfind(StringRef Str) const noexcept {
|
||||
size_t N = Str.size();
|
||||
if (N > Length)
|
||||
return npos;
|
||||
for (size_t i = Length - N + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (substr(i, N).equals(Str))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::rfind_lower(StringRef Str) const noexcept {
|
||||
size_t N = Str.size();
|
||||
if (N > Length)
|
||||
return npos;
|
||||
for (size_t i = Length - N + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (substr(i, N).equals_lower(Str))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_first_of - Find the first character in the string that is in \arg
|
||||
/// Chars, or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_first_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_first_not_of - Find the first character in the string that is not
|
||||
/// \arg C or npos if not found.
|
||||
StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const noexcept {
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (Data[i] != C)
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_first_not_of - Find the first character in the string that is not
|
||||
/// in the string \arg Chars, or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_first_not_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (!CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_last_of - Find the last character in the string that is in \arg C,
|
||||
/// or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_last_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_last_not_of - Find the last character in the string that is not
|
||||
/// \arg C, or npos if not found.
|
||||
StringRef::size_type StringRef::find_last_not_of(char C, size_t From) const noexcept {
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (Data[i] != C)
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_last_not_of - Find the last character in the string that is not in
|
||||
/// \arg Chars, or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_last_not_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0, e = Chars.size(); i != e; ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (!CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
void StringRef::split(SmallVectorImpl<StringRef> &A,
|
||||
StringRef Separator, int MaxSplit,
|
||||
bool KeepEmpty) const {
|
||||
StringRef S = *this;
|
||||
|
||||
// Count down from MaxSplit. When MaxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make MaxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (MaxSplit-- != 0) {
|
||||
size_t Idx = S.find(Separator);
|
||||
if (Idx == npos)
|
||||
break;
|
||||
|
||||
// Push this split.
|
||||
if (KeepEmpty || Idx > 0)
|
||||
A.push_back(S.slice(0, Idx));
|
||||
|
||||
// Jump forward.
|
||||
S = S.slice(Idx + Separator.size(), npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (KeepEmpty || !S.empty())
|
||||
A.push_back(S);
|
||||
}
|
||||
|
||||
void StringRef::split(SmallVectorImpl<StringRef> &A, char Separator,
|
||||
int MaxSplit, bool KeepEmpty) const {
|
||||
StringRef S = *this;
|
||||
|
||||
// Count down from MaxSplit. When MaxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make MaxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (MaxSplit-- != 0) {
|
||||
size_t Idx = S.find(Separator);
|
||||
if (Idx == npos)
|
||||
break;
|
||||
|
||||
// Push this split.
|
||||
if (KeepEmpty || Idx > 0)
|
||||
A.push_back(S.slice(0, Idx));
|
||||
|
||||
// Jump forward.
|
||||
S = S.slice(Idx + 1, npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (KeepEmpty || !S.empty())
|
||||
A.push_back(S);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Helpful Algorithms
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// count - Return the number of non-overlapped occurrences of \arg Str in
|
||||
/// the string.
|
||||
size_t StringRef::count(StringRef Str) const noexcept {
|
||||
size_t Count = 0;
|
||||
size_t N = Str.size();
|
||||
if (N > Length)
|
||||
return 0;
|
||||
for (size_t i = 0, e = Length - N + 1; i != e; ++i)
|
||||
if (substr(i, N).equals(Str))
|
||||
++Count;
|
||||
return Count;
|
||||
}
|
||||
|
||||
static unsigned GetAutoSenseRadix(StringRef &Str) noexcept {
|
||||
if (Str.empty())
|
||||
return 10;
|
||||
|
||||
if (Str.startswith("0x") || Str.startswith("0X")) {
|
||||
Str = Str.substr(2);
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (Str.startswith("0b") || Str.startswith("0B")) {
|
||||
Str = Str.substr(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (Str.startswith("0o")) {
|
||||
Str = Str.substr(2);
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (Str[0] == '0' && Str.size() > 1 && isDigit(Str[1])) {
|
||||
Str = Str.substr(1);
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
|
||||
bool wpi::consumeUnsignedInteger(StringRef &Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept {
|
||||
// Autosense radix if not specified.
|
||||
if (Radix == 0)
|
||||
Radix = GetAutoSenseRadix(Str);
|
||||
|
||||
// Empty strings (after the radix autosense) are invalid.
|
||||
if (Str.empty()) return true;
|
||||
|
||||
// Parse all the bytes of the string given this radix. Watch for overflow.
|
||||
StringRef Str2 = Str;
|
||||
Result = 0;
|
||||
while (!Str2.empty()) {
|
||||
unsigned CharVal;
|
||||
if (Str2[0] >= '0' && Str2[0] <= '9')
|
||||
CharVal = Str2[0] - '0';
|
||||
else if (Str2[0] >= 'a' && Str2[0] <= 'z')
|
||||
CharVal = Str2[0] - 'a' + 10;
|
||||
else if (Str2[0] >= 'A' && Str2[0] <= 'Z')
|
||||
CharVal = Str2[0] - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
// If the parsed value is larger than the integer radix, we cannot
|
||||
// consume any more characters.
|
||||
if (CharVal >= Radix)
|
||||
break;
|
||||
|
||||
// Add in this character.
|
||||
unsigned long long PrevResult = Result;
|
||||
Result = Result * Radix + CharVal;
|
||||
|
||||
// Check for overflow by shifting back and seeing if bits were lost.
|
||||
if (Result / Radix < PrevResult)
|
||||
return true;
|
||||
|
||||
Str2 = Str2.substr(1);
|
||||
}
|
||||
|
||||
// We consider the operation a failure if no characters were consumed
|
||||
// successfully.
|
||||
if (Str.size() == Str2.size())
|
||||
return true;
|
||||
|
||||
Str = Str2;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::consumeSignedInteger(StringRef &Str, unsigned Radix,
|
||||
long long &Result) noexcept {
|
||||
unsigned long long ULLVal;
|
||||
|
||||
// Handle positive strings first.
|
||||
if (Str.empty() || Str.front() != '-') {
|
||||
if (consumeUnsignedInteger(Str, Radix, ULLVal) ||
|
||||
// Check for value so large it overflows a signed value.
|
||||
(long long)ULLVal < 0)
|
||||
return true;
|
||||
Result = ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the positive part of the value.
|
||||
StringRef Str2 = Str.drop_front(1);
|
||||
if (consumeUnsignedInteger(Str2, Radix, ULLVal) ||
|
||||
// Reject values so large they'd overflow as negative signed, but allow
|
||||
// "-0". This negates the unsigned so that the negative isn't undefined
|
||||
// on signed overflow.
|
||||
(long long)-ULLVal > 0)
|
||||
return true;
|
||||
|
||||
Str = Str2;
|
||||
Result = -ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
|
||||
/// sequence of radix up to 36 to an unsigned long long value.
|
||||
bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept {
|
||||
if (consumeUnsignedInteger(Str, Radix, Result))
|
||||
return true;
|
||||
|
||||
// For getAsUnsignedInteger, we require the whole string to be consumed or
|
||||
// else we consider it a failure.
|
||||
return !Str.empty();
|
||||
}
|
||||
|
||||
bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
|
||||
long long &Result) noexcept {
|
||||
if (consumeSignedInteger(Str, Radix, Result))
|
||||
return true;
|
||||
|
||||
// For getAsSignedInteger, we require the whole string to be consumed or else
|
||||
// we consider it a failure.
|
||||
return !Str.empty();
|
||||
}
|
||||
|
||||
std::ostream &wpi::operator<<(std::ostream &os, StringRef string) {
|
||||
os.write(string.data(), string.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
// Implementation of StringRef hashing.
|
||||
hash_code wpi::hash_value(StringRef S) {
|
||||
return hash_combine_range(S.begin(), S.end());
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
//===-- Twine.cpp - Fast Temporary String Concatenation -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
using namespace wpi;
|
||||
|
||||
std::string Twine::str() const {
|
||||
// If we're storing only a std::string, just return it.
|
||||
if (LHSKind == StdStringKind && RHSKind == EmptyKind)
|
||||
return *LHS.stdString;
|
||||
|
||||
// Otherwise, flatten and copy the contents first.
|
||||
SmallString<256> Vec;
|
||||
return toStringRef(Vec).str();
|
||||
}
|
||||
|
||||
void Twine::toVector(SmallVectorImpl<char> &Out) const {
|
||||
raw_svector_ostream OS(Out);
|
||||
print(OS);
|
||||
}
|
||||
|
||||
StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
|
||||
if (isUnary()) {
|
||||
switch (getLHSKind()) {
|
||||
case CStringKind:
|
||||
// Already null terminated, yay!
|
||||
return StringRef(LHS.cString);
|
||||
case StdStringKind: {
|
||||
const std::string *str = LHS.stdString;
|
||||
return StringRef(str->c_str(), str->size());
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
toVector(Out);
|
||||
Out.push_back(0);
|
||||
Out.pop_back();
|
||||
return StringRef(Out.data(), Out.size());
|
||||
}
|
||||
|
||||
void Twine::printOneChild(raw_ostream &OS, Child Ptr,
|
||||
NodeKind Kind) const {
|
||||
switch (Kind) {
|
||||
case Twine::NullKind: break;
|
||||
case Twine::EmptyKind: break;
|
||||
case Twine::TwineKind:
|
||||
Ptr.twine->print(OS);
|
||||
break;
|
||||
case Twine::CStringKind:
|
||||
OS << Ptr.cString;
|
||||
break;
|
||||
case Twine::StdStringKind:
|
||||
OS << *Ptr.stdString;
|
||||
break;
|
||||
case Twine::StringRefKind:
|
||||
OS << *Ptr.stringRef;
|
||||
break;
|
||||
case Twine::StringViewKind:
|
||||
OS << *Ptr.stringView;
|
||||
break;
|
||||
case Twine::SmallStringKind:
|
||||
OS << *Ptr.smallString;
|
||||
break;
|
||||
case Twine::CharKind:
|
||||
OS << Ptr.character;
|
||||
break;
|
||||
case Twine::DecUIKind:
|
||||
OS << Ptr.decUI;
|
||||
break;
|
||||
case Twine::DecIKind:
|
||||
OS << Ptr.decI;
|
||||
break;
|
||||
case Twine::DecULKind:
|
||||
OS << *Ptr.decUL;
|
||||
break;
|
||||
case Twine::DecLKind:
|
||||
OS << *Ptr.decL;
|
||||
break;
|
||||
case Twine::DecULLKind:
|
||||
OS << *Ptr.decULL;
|
||||
break;
|
||||
case Twine::DecLLKind:
|
||||
OS << *Ptr.decLL;
|
||||
break;
|
||||
case Twine::UHexKind:
|
||||
OS.write_hex(*Ptr.uHex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr,
|
||||
NodeKind Kind) const {
|
||||
switch (Kind) {
|
||||
case Twine::NullKind:
|
||||
OS << "null"; break;
|
||||
case Twine::EmptyKind:
|
||||
OS << "empty"; break;
|
||||
case Twine::TwineKind:
|
||||
OS << "rope:";
|
||||
Ptr.twine->printRepr(OS);
|
||||
break;
|
||||
case Twine::CStringKind:
|
||||
OS << "cstring:\""
|
||||
<< Ptr.cString << "\"";
|
||||
break;
|
||||
case Twine::StdStringKind:
|
||||
OS << "std::string:\""
|
||||
<< Ptr.stdString << "\"";
|
||||
break;
|
||||
case Twine::StringRefKind:
|
||||
OS << "stringref:\""
|
||||
<< Ptr.stringRef << "\"";
|
||||
break;
|
||||
case Twine::StringViewKind:
|
||||
OS << "std::string_view:\""
|
||||
<< Ptr.stringView << "\"";
|
||||
break;
|
||||
case Twine::SmallStringKind:
|
||||
OS << "smallstring:\"" << *Ptr.smallString << "\"";
|
||||
break;
|
||||
case Twine::CharKind:
|
||||
OS << "char:\"" << Ptr.character << "\"";
|
||||
break;
|
||||
case Twine::DecUIKind:
|
||||
OS << "decUI:\"" << Ptr.decUI << "\"";
|
||||
break;
|
||||
case Twine::DecIKind:
|
||||
OS << "decI:\"" << Ptr.decI << "\"";
|
||||
break;
|
||||
case Twine::DecULKind:
|
||||
OS << "decUL:\"" << *Ptr.decUL << "\"";
|
||||
break;
|
||||
case Twine::DecLKind:
|
||||
OS << "decL:\"" << *Ptr.decL << "\"";
|
||||
break;
|
||||
case Twine::DecULLKind:
|
||||
OS << "decULL:\"" << *Ptr.decULL << "\"";
|
||||
break;
|
||||
case Twine::DecLLKind:
|
||||
OS << "decLL:\"" << *Ptr.decLL << "\"";
|
||||
break;
|
||||
case Twine::UHexKind:
|
||||
OS << "uhex:\"" << Ptr.uHex << "\"";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Twine::print(raw_ostream &OS) const {
|
||||
printOneChild(OS, LHS, getLHSKind());
|
||||
printOneChild(OS, RHS, getRHSKind());
|
||||
}
|
||||
|
||||
void Twine::printRepr(raw_ostream &OS) const {
|
||||
OS << "(Twine ";
|
||||
printOneChildRepr(OS, LHS, getLHSKind());
|
||||
OS << " ";
|
||||
printOneChildRepr(OS, RHS, getRHSKind());
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void Twine::dump() const {
|
||||
print(errs());
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void Twine::dumpRepr() const {
|
||||
printRepr(errs());
|
||||
}
|
||||
@@ -36,13 +36,12 @@
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/Chrono.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/VersionTuple.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/Format.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/NativeFormatting.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "wpi/fs.h"
|
||||
#include <algorithm>
|
||||
@@ -113,32 +111,7 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
||||
assert(OutBufStart <= OutBufEnd && "Invalid size!");
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long N) {
|
||||
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long N) {
|
||||
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long long N) {
|
||||
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long long N) {
|
||||
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_hex(unsigned long long N) {
|
||||
wpi::write_hex(*this, N, HexPrintStyle::Lower);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_escaped(StringRef Str,
|
||||
raw_ostream &raw_ostream::write_escaped(std::string_view Str,
|
||||
bool UseHexEscapes) {
|
||||
for (unsigned char c : Str) {
|
||||
switch (c) {
|
||||
@@ -178,16 +151,6 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str,
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const void *P) {
|
||||
wpi::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(double N) {
|
||||
wpi::write_double(*this, N, FloatStyle::Exponent);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void raw_ostream::flush_nonempty() {
|
||||
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
|
||||
size_t Length = OutBufCur - OutBufStart;
|
||||
@@ -277,170 +240,6 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
|
||||
OutBufCur += Size;
|
||||
}
|
||||
|
||||
// Formatted output.
|
||||
raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
|
||||
// If we have more than a few bytes left in our output buffer, try
|
||||
// formatting directly onto its end.
|
||||
size_t NextBufferSize = 127;
|
||||
size_t BufferBytesLeft = OutBufEnd - OutBufCur;
|
||||
if (BufferBytesLeft > 3) {
|
||||
size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
|
||||
|
||||
// Common case is that we have plenty of space.
|
||||
if (BytesUsed <= BufferBytesLeft) {
|
||||
OutBufCur += BytesUsed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Otherwise, we overflowed and the return value tells us the size to try
|
||||
// again with.
|
||||
NextBufferSize = BytesUsed;
|
||||
}
|
||||
|
||||
// If we got here, we didn't have enough space in the output buffer for the
|
||||
// string. Try printing into a SmallVector that is resized to have enough
|
||||
// space. Iterate until we win.
|
||||
SmallVector<char, 128> V;
|
||||
|
||||
while (true) {
|
||||
V.resize(NextBufferSize);
|
||||
|
||||
// Try formatting into the SmallVector.
|
||||
size_t BytesUsed = Fmt.print(V.data(), NextBufferSize);
|
||||
|
||||
// If BytesUsed fit into the vector, we win.
|
||||
if (BytesUsed <= NextBufferSize)
|
||||
return write(V.data(), BytesUsed);
|
||||
|
||||
// Otherwise, try again with a new size.
|
||||
assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
|
||||
NextBufferSize = BytesUsed;
|
||||
}
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
|
||||
if (FS.Str.size() >= FS.Width || FS.Justify == FormattedString::JustifyNone) {
|
||||
this->operator<<(FS.Str);
|
||||
return *this;
|
||||
}
|
||||
const size_t Difference = FS.Width - FS.Str.size();
|
||||
switch (FS.Justify) {
|
||||
case FormattedString::JustifyLeft:
|
||||
this->operator<<(FS.Str);
|
||||
this->indent(Difference);
|
||||
break;
|
||||
case FormattedString::JustifyRight:
|
||||
this->indent(Difference);
|
||||
this->operator<<(FS.Str);
|
||||
break;
|
||||
case FormattedString::JustifyCenter: {
|
||||
int PadAmount = Difference / 2;
|
||||
this->indent(PadAmount);
|
||||
this->operator<<(FS.Str);
|
||||
this->indent(Difference - PadAmount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
wpi_unreachable("Bad Justification");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
|
||||
if (FN.Hex) {
|
||||
HexPrintStyle Style;
|
||||
if (FN.Upper && FN.HexPrefix)
|
||||
Style = HexPrintStyle::PrefixUpper;
|
||||
else if (FN.Upper && !FN.HexPrefix)
|
||||
Style = HexPrintStyle::Upper;
|
||||
else if (!FN.Upper && FN.HexPrefix)
|
||||
Style = HexPrintStyle::PrefixLower;
|
||||
else
|
||||
Style = HexPrintStyle::Lower;
|
||||
wpi::write_hex(*this, FN.HexValue, Style, FN.Width);
|
||||
} else {
|
||||
wpi::SmallString<16> Buffer;
|
||||
wpi::raw_svector_ostream Stream(Buffer);
|
||||
wpi::write_integer(Stream, FN.DecValue, 0, IntegerStyle::Integer);
|
||||
if (Buffer.size() < FN.Width)
|
||||
indent(FN.Width - Buffer.size());
|
||||
(*this) << Buffer;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
|
||||
if (FB.Bytes.empty())
|
||||
return *this;
|
||||
|
||||
size_t LineIndex = 0;
|
||||
auto Bytes = FB.Bytes;
|
||||
const size_t Size = Bytes.size();
|
||||
HexPrintStyle HPS = FB.Upper ? HexPrintStyle::Upper : HexPrintStyle::Lower;
|
||||
uint64_t OffsetWidth = 0;
|
||||
if (FB.FirstByteOffset.has_value()) {
|
||||
// Figure out how many nibbles are needed to print the largest offset
|
||||
// represented by this data set, so that we can align the offset field
|
||||
// to the right width.
|
||||
size_t Lines = Size / FB.NumPerLine;
|
||||
uint64_t MaxOffset = *FB.FirstByteOffset + Lines * FB.NumPerLine;
|
||||
unsigned Power = 0;
|
||||
if (MaxOffset > 0)
|
||||
Power = wpi::Log2_64_Ceil(MaxOffset);
|
||||
OffsetWidth = std::max<uint64_t>(4, wpi::alignTo(Power, 4) / 4);
|
||||
}
|
||||
|
||||
// The width of a block of data including all spaces for group separators.
|
||||
unsigned NumByteGroups =
|
||||
alignTo(FB.NumPerLine, FB.ByteGroupSize) / FB.ByteGroupSize;
|
||||
unsigned BlockCharWidth = FB.NumPerLine * 2 + NumByteGroups - 1;
|
||||
|
||||
while (!Bytes.empty()) {
|
||||
indent(FB.IndentLevel);
|
||||
|
||||
if (FB.FirstByteOffset.has_value()) {
|
||||
uint64_t Offset = FB.FirstByteOffset.value();
|
||||
wpi::write_hex(*this, Offset + LineIndex, HPS, OffsetWidth);
|
||||
*this << ": ";
|
||||
}
|
||||
|
||||
auto Line = Bytes.take_front(FB.NumPerLine);
|
||||
|
||||
size_t CharsPrinted = 0;
|
||||
// Print the hex bytes for this line in groups
|
||||
for (size_t I = 0; I < Line.size(); ++I, CharsPrinted += 2) {
|
||||
if (I && (I % FB.ByteGroupSize) == 0) {
|
||||
++CharsPrinted;
|
||||
*this << " ";
|
||||
}
|
||||
wpi::write_hex(*this, Line[I], HPS, 2);
|
||||
}
|
||||
|
||||
if (FB.ASCII) {
|
||||
// Print any spaces needed for any bytes that we didn't print on this
|
||||
// line so that the ASCII bytes are correctly aligned.
|
||||
assert(BlockCharWidth >= CharsPrinted);
|
||||
indent(BlockCharWidth - CharsPrinted + 2);
|
||||
*this << "|";
|
||||
|
||||
// Print the ASCII char values for each byte on this line
|
||||
for (uint8_t Byte : Line) {
|
||||
if (isPrint(Byte))
|
||||
*this << static_cast<char>(Byte);
|
||||
else
|
||||
*this << '.';
|
||||
}
|
||||
*this << '|';
|
||||
}
|
||||
|
||||
Bytes = Bytes.drop_front(Line.size());
|
||||
LineIndex += Line.size();
|
||||
if (LineIndex < Size)
|
||||
*this << '\n';
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <char C>
|
||||
static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
|
||||
static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
@@ -474,19 +273,11 @@ raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
|
||||
|
||||
void raw_ostream::anchor() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Formatted Output
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Out of line virtual method.
|
||||
void format_object_base::home() {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_fd_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static int getFD(StringRef Filename, std::error_code &EC,
|
||||
static int getFD(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp, fs::FileAccess Access,
|
||||
fs::OpenFlags Flags) {
|
||||
assert((Access & fs::FA_Write) &&
|
||||
@@ -521,25 +312,25 @@ static int getFD(StringRef Filename, std::error_code &EC,
|
||||
return FD;
|
||||
}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC)
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp)
|
||||
: raw_fd_ostream(Filename, EC, Disp, fs::FA_Write, fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::FileAccess Access)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, Access,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::OpenFlags Flags)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
Flags) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp,
|
||||
fs::FileAccess Access,
|
||||
fs::OpenFlags Flags)
|
||||
@@ -622,7 +413,7 @@ raw_fd_ostream::~raw_fd_ostream() {
|
||||
// the input is UTF-8 or transcode from the local codepage to UTF-8 before
|
||||
// quoting it. If they don't, this may mess up the encoding, but this is still
|
||||
// probably the best compromise we can make.
|
||||
static bool write_console_impl(int FD, StringRef Data) {
|
||||
static bool write_console_impl(int FD, std::string_view Data) {
|
||||
SmallVector<wchar_t, 256> WideText;
|
||||
|
||||
// Fall back to ::write if it wasn't valid UTF-8.
|
||||
@@ -665,7 +456,7 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
// If this is a Windows console device, try re-encoding from UTF-8 to UTF-16
|
||||
// and using WriteConsoleW. If that fails, fall back to plain write().
|
||||
if (IsWindowsConsole)
|
||||
if (write_console_impl(FD, StringRef(Ptr, Size)))
|
||||
if (write_console_impl(FD, std::string_view(Ptr, Size)))
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/fs.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
@@ -33,13 +33,13 @@
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
StringRef raw_istream::getline(SmallVectorImpl<char>& buf, int maxLen) {
|
||||
std::string_view raw_istream::getline(SmallVectorImpl<char>& buf, int maxLen) {
|
||||
buf.clear();
|
||||
for (int i = 0; i < maxLen; ++i) {
|
||||
char c;
|
||||
read(c);
|
||||
if (has_error()) {
|
||||
return StringRef{buf.data(), buf.size()};
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
if (c == '\r') {
|
||||
continue;
|
||||
@@ -49,7 +49,7 @@ StringRef raw_istream::getline(SmallVectorImpl<char>& buf, int maxLen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return StringRef{buf.data(), buf.size()};
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
void raw_mem_istream::close() {}
|
||||
@@ -69,16 +69,16 @@ void raw_mem_istream::read_impl(void* data, size_t len) {
|
||||
set_read_count(len);
|
||||
}
|
||||
|
||||
static int getFD(const Twine& Filename, std::error_code& EC) {
|
||||
static int getFD(std::string_view Filename, std::error_code& EC) {
|
||||
// Handle "-" as stdin. Note that when we do this, we consider ourself
|
||||
// the owner of stdin. This means that we can do things like close the
|
||||
// file descriptor when we're done and set the "binary" flag globally.
|
||||
if (Filename.isSingleStringRef() && Filename.getSingleStringRef() == "-") {
|
||||
if (Filename == "-") {
|
||||
EC = std::error_code();
|
||||
return STDIN_FILENO;
|
||||
}
|
||||
|
||||
fs::file_t F = fs::OpenFileForRead(Filename.str(), EC);
|
||||
fs::file_t F = fs::OpenFileForRead(Filename, EC);
|
||||
if (EC) {
|
||||
return -1;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ static int getFD(const Twine& Filename, std::error_code& EC) {
|
||||
return FD;
|
||||
}
|
||||
|
||||
raw_fd_istream::raw_fd_istream(const Twine& filename, std::error_code& ec,
|
||||
raw_fd_istream::raw_fd_istream(std::string_view filename, std::error_code& ec,
|
||||
size_t bufSize)
|
||||
: raw_fd_istream(getFD(filename, ec), true, bufSize) {}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ SHA1::SHA1() {
|
||||
reset(digest, buf_size, transforms);
|
||||
}
|
||||
|
||||
void SHA1::Update(StringRef s) {
|
||||
void SHA1::Update(std::string_view s) {
|
||||
raw_mem_istream is(makeArrayRef(s.data(), s.size()));
|
||||
Update(is);
|
||||
}
|
||||
@@ -293,7 +293,7 @@ std::string SHA1::Final() {
|
||||
return os.str();
|
||||
}
|
||||
|
||||
StringRef SHA1::Final(SmallVectorImpl<char>& buf) {
|
||||
std::string_view SHA1::Final(SmallVectorImpl<char>& buf) {
|
||||
raw_svector_ostream os(buf);
|
||||
|
||||
finalize(digest, buffer, buf_size, transforms, os, true);
|
||||
@@ -301,7 +301,7 @@ StringRef SHA1::Final(SmallVectorImpl<char>& buf) {
|
||||
return os.str();
|
||||
}
|
||||
|
||||
StringRef SHA1::RawFinal(SmallVectorImpl<char>& buf) {
|
||||
std::string_view SHA1::RawFinal(SmallVectorImpl<char>& buf) {
|
||||
raw_svector_ostream os(buf);
|
||||
|
||||
finalize(digest, buffer, buf_size, transforms, os, false);
|
||||
@@ -309,7 +309,7 @@ StringRef SHA1::RawFinal(SmallVectorImpl<char>& buf) {
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string SHA1::FromFile(StringRef filename) {
|
||||
std::string SHA1::FromFile(std::string_view filename) {
|
||||
std::error_code ec;
|
||||
raw_fd_istream stream(filename, ec);
|
||||
SHA1 checksum;
|
||||
|
||||
@@ -22,8 +22,8 @@ std::shared_ptr<FsEvent> FsEvent::Create(Loop& loop) {
|
||||
return h;
|
||||
}
|
||||
|
||||
void FsEvent::Start(const Twine& path, unsigned int flags) {
|
||||
SmallString<128> pathBuf;
|
||||
void FsEvent::Start(std::string_view path, unsigned int flags) {
|
||||
SmallString<128> pathBuf{path};
|
||||
Invoke(
|
||||
&uv_fs_event_start, GetRaw(),
|
||||
[](uv_fs_event_t* handle, const char* filename, int events, int status) {
|
||||
@@ -34,7 +34,7 @@ void FsEvent::Start(const Twine& path, unsigned int flags) {
|
||||
h.fsEvent(filename, events);
|
||||
}
|
||||
},
|
||||
path.toNullTerminatedStringRef(pathBuf).data(), flags);
|
||||
pathBuf.c_str(), flags);
|
||||
}
|
||||
|
||||
std::string FsEvent::GetPath() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "wpi/uv/GetAddrInfo.h"
|
||||
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/uv/Loop.h"
|
||||
#include "wpi/uv/util.h"
|
||||
|
||||
@@ -14,10 +15,10 @@ GetAddrInfoReq::GetAddrInfoReq() {
|
||||
}
|
||||
|
||||
void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
const Twine& node, const Twine& service,
|
||||
std::string_view node, std::string_view service,
|
||||
const addrinfo* hints) {
|
||||
SmallVector<char, 128> nodeStr;
|
||||
SmallVector<char, 128> serviceStr;
|
||||
SmallString<128> nodeStr{node};
|
||||
SmallString<128> serviceStr{service};
|
||||
int err = uv_getaddrinfo(
|
||||
loop.GetRaw(), req->GetRaw(),
|
||||
[](uv_getaddrinfo_t* req, int status, addrinfo* res) {
|
||||
@@ -30,10 +31,8 @@ void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
uv_freeaddrinfo(res);
|
||||
h.Release(); // this is always a one-shot
|
||||
},
|
||||
node.isNull() ? nullptr : node.toNullTerminatedStringRef(nodeStr).data(),
|
||||
service.isNull() ? nullptr
|
||||
: service.toNullTerminatedStringRef(serviceStr).data(),
|
||||
hints);
|
||||
node.empty() ? nullptr : nodeStr.c_str(),
|
||||
service.empty() ? nullptr : serviceStr.c_str(), hints);
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
} else {
|
||||
@@ -42,7 +41,7 @@ void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
}
|
||||
|
||||
void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
|
||||
const Twine& node, const Twine& service,
|
||||
std::string_view node, std::string_view service,
|
||||
const addrinfo* hints) {
|
||||
auto req = std::make_shared<GetAddrInfoReq>();
|
||||
req->resolved.connect(callback);
|
||||
|
||||
@@ -44,7 +44,7 @@ void GetNameInfo(Loop& loop,
|
||||
}
|
||||
|
||||
void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags) {
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -56,7 +56,7 @@ void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
|
||||
void GetNameInfo4(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags) {
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -67,7 +67,7 @@ void GetNameInfo4(Loop& loop,
|
||||
}
|
||||
|
||||
void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags) {
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -79,7 +79,7 @@ void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
|
||||
void GetNameInfo6(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags) {
|
||||
std::string_view ip, unsigned int port, int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
|
||||
@@ -10,53 +10,49 @@
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in* addr) {
|
||||
SmallString<128> tmp;
|
||||
StringRef ipStr = ip.toNullTerminatedStringRef(tmp);
|
||||
if (ipStr.empty()) {
|
||||
int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in* addr) {
|
||||
if (ip.empty()) {
|
||||
std::memset(addr, 0, sizeof(sockaddr_in));
|
||||
addr->sin_family = PF_INET;
|
||||
addr->sin_addr.s_addr = INADDR_ANY;
|
||||
addr->sin_port = htons(port);
|
||||
return 0;
|
||||
} else {
|
||||
return uv_ip4_addr(ipStr.data(), port, addr);
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_ip4_addr(ipBuf.c_str(), port, addr);
|
||||
}
|
||||
}
|
||||
|
||||
int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in6* addr) {
|
||||
SmallString<128> tmp;
|
||||
StringRef ipStr = ip.toNullTerminatedStringRef(tmp);
|
||||
if (ipStr.empty()) {
|
||||
int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in6* addr) {
|
||||
if (ip.empty()) {
|
||||
std::memset(addr, 0, sizeof(sockaddr_in6));
|
||||
addr->sin6_family = PF_INET6;
|
||||
addr->sin6_addr = in6addr_any;
|
||||
addr->sin6_port = htons(port);
|
||||
return 0;
|
||||
} else {
|
||||
return uv_ip6_addr(ipStr.data(), port, addr);
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_ip6_addr(ipBuf.c_str(), port, addr);
|
||||
}
|
||||
}
|
||||
|
||||
int NameToAddr(const Twine& ip, in_addr* addr) {
|
||||
SmallString<128> tmp;
|
||||
StringRef ipStr = ip.toNullTerminatedStringRef(tmp);
|
||||
if (ipStr.empty()) {
|
||||
int NameToAddr(std::string_view ip, in_addr* addr) {
|
||||
if (ip.empty()) {
|
||||
addr->s_addr = INADDR_ANY;
|
||||
return 0;
|
||||
} else {
|
||||
return uv_inet_pton(AF_INET, ipStr.data(), addr);
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_inet_pton(AF_INET, ipBuf.c_str(), addr);
|
||||
}
|
||||
}
|
||||
|
||||
int NameToAddr(const Twine& ip, in6_addr* addr) {
|
||||
SmallString<128> tmp;
|
||||
StringRef ipStr = ip.toNullTerminatedStringRef(tmp);
|
||||
if (ipStr.empty()) {
|
||||
int NameToAddr(std::string_view ip, in6_addr* addr) {
|
||||
if (ip.empty()) {
|
||||
*addr = in6addr_any;
|
||||
return 0;
|
||||
} else {
|
||||
return uv_inet_pton(AF_INET6, ipStr.data(), addr);
|
||||
SmallString<128> ipBuf{ip};
|
||||
return uv_inet_pton(AF_INET6, ipBuf.c_str(), addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,17 +62,15 @@ Pipe* Pipe::DoAccept() {
|
||||
return Accept().get();
|
||||
}
|
||||
|
||||
void Pipe::Bind(const Twine& name) {
|
||||
SmallString<128> nameBuf;
|
||||
Invoke(&uv_pipe_bind, GetRaw(),
|
||||
name.toNullTerminatedStringRef(nameBuf).data());
|
||||
void Pipe::Bind(std::string_view name) {
|
||||
SmallString<128> nameBuf{name};
|
||||
Invoke(&uv_pipe_bind, GetRaw(), nameBuf.c_str());
|
||||
}
|
||||
|
||||
void Pipe::Connect(const Twine& name,
|
||||
void Pipe::Connect(std::string_view name,
|
||||
const std::shared_ptr<PipeConnectReq>& req) {
|
||||
SmallString<128> nameBuf;
|
||||
uv_pipe_connect(req->GetRaw(), GetRaw(),
|
||||
name.toNullTerminatedStringRef(nameBuf).data(),
|
||||
SmallString<128> nameBuf{name};
|
||||
uv_pipe_connect(req->GetRaw(), GetRaw(), nameBuf.c_str(),
|
||||
[](uv_connect_t* req, int status) {
|
||||
auto& h = *static_cast<PipeConnectReq*>(req->data);
|
||||
if (status < 0) {
|
||||
@@ -85,7 +83,7 @@ void Pipe::Connect(const Twine& name,
|
||||
req->Keep();
|
||||
}
|
||||
|
||||
void Pipe::Connect(const Twine& name, std::function<void()> callback) {
|
||||
void Pipe::Connect(std::string_view name, std::function<void()> callback) {
|
||||
auto req = std::make_shared<PipeConnectReq>();
|
||||
req->connected.connect(callback);
|
||||
Connect(name, req);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
std::shared_ptr<Process> Process::SpawnArray(Loop& loop, const Twine& file,
|
||||
std::shared_ptr<Process> Process::SpawnArray(Loop& loop, std::string_view file,
|
||||
ArrayRef<Option> options) {
|
||||
// convert Option array to libuv structure
|
||||
uv_process_options_t coptions;
|
||||
@@ -20,8 +20,8 @@ std::shared_ptr<Process> Process::SpawnArray(Loop& loop, const Twine& file,
|
||||
h.exited(status, signal);
|
||||
};
|
||||
|
||||
SmallString<128> fileBuf;
|
||||
coptions.file = file.toNullTerminatedStringRef(fileBuf).data();
|
||||
SmallString<128> fileBuf{file};
|
||||
coptions.file = fileBuf.c_str();
|
||||
coptions.cwd = nullptr;
|
||||
coptions.flags = 0;
|
||||
coptions.uid = 0;
|
||||
|
||||
@@ -61,7 +61,7 @@ Tcp* Tcp::DoAccept() {
|
||||
return Accept().get();
|
||||
}
|
||||
|
||||
void Tcp::Bind(const Twine& ip, unsigned int port, unsigned int flags) {
|
||||
void Tcp::Bind(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -71,7 +71,7 @@ void Tcp::Bind(const Twine& ip, unsigned int port, unsigned int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Bind6(const Twine& ip, unsigned int port, unsigned int flags) {
|
||||
void Tcp::Bind6(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -123,7 +123,7 @@ void Tcp::Connect(const sockaddr& addr, std::function<void()> callback) {
|
||||
Connect(addr, req);
|
||||
}
|
||||
|
||||
void Tcp::Connect(const Twine& ip, unsigned int port,
|
||||
void Tcp::Connect(std::string_view ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
@@ -134,7 +134,7 @@ void Tcp::Connect(const Twine& ip, unsigned int port,
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Connect(const Twine& ip, unsigned int port,
|
||||
void Tcp::Connect(std::string_view ip, unsigned int port,
|
||||
std::function<void()> callback) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
@@ -145,7 +145,7 @@ void Tcp::Connect(const Twine& ip, unsigned int port,
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Connect6(const Twine& ip, unsigned int port,
|
||||
void Tcp::Connect6(std::string_view ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
@@ -156,7 +156,7 @@ void Tcp::Connect6(const Twine& ip, unsigned int port,
|
||||
}
|
||||
}
|
||||
|
||||
void Tcp::Connect6(const Twine& ip, unsigned int port,
|
||||
void Tcp::Connect6(std::string_view ip, unsigned int port,
|
||||
std::function<void()> callback) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
|
||||
@@ -47,7 +47,7 @@ std::shared_ptr<Udp> Udp::Create(Loop& loop, unsigned int flags) {
|
||||
return h;
|
||||
}
|
||||
|
||||
void Udp::Bind(const Twine& ip, unsigned int port, unsigned int flags) {
|
||||
void Udp::Bind(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -57,7 +57,7 @@ void Udp::Bind(const Twine& ip, unsigned int port, unsigned int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
void Udp::Bind6(const Twine& ip, unsigned int port, unsigned int flags) {
|
||||
void Udp::Bind6(std::string_view ip, unsigned int port, unsigned int flags) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -67,7 +67,7 @@ void Udp::Bind6(const Twine& ip, unsigned int port, unsigned int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
void Udp::Connect(const Twine& ip, unsigned int port) {
|
||||
void Udp::Connect(std::string_view ip, unsigned int port) {
|
||||
sockaddr_in addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -77,7 +77,7 @@ void Udp::Connect(const Twine& ip, unsigned int port) {
|
||||
}
|
||||
}
|
||||
|
||||
void Udp::Connect6(const Twine& ip, unsigned int port) {
|
||||
void Udp::Connect6(std::string_view ip, unsigned int port) {
|
||||
sockaddr_in6 addr;
|
||||
int err = NameToAddr(ip, port, &addr);
|
||||
if (err < 0) {
|
||||
@@ -107,20 +107,18 @@ sockaddr_storage Udp::GetSock() {
|
||||
return name;
|
||||
}
|
||||
|
||||
void Udp::SetMembership(const Twine& multicastAddr, const Twine& interfaceAddr,
|
||||
void Udp::SetMembership(std::string_view multicastAddr,
|
||||
std::string_view interfaceAddr,
|
||||
uv_membership membership) {
|
||||
SmallString<128> multicastAddrBuf;
|
||||
SmallString<128> interfaceAddrBuf;
|
||||
Invoke(&uv_udp_set_membership, GetRaw(),
|
||||
multicastAddr.toNullTerminatedStringRef(multicastAddrBuf).data(),
|
||||
interfaceAddr.toNullTerminatedStringRef(interfaceAddrBuf).data(),
|
||||
membership);
|
||||
SmallString<128> multicastAddrBuf{multicastAddr};
|
||||
SmallString<128> interfaceAddrBuf{interfaceAddr};
|
||||
Invoke(&uv_udp_set_membership, GetRaw(), multicastAddrBuf.c_str(),
|
||||
interfaceAddrBuf.c_str(), membership);
|
||||
}
|
||||
|
||||
void Udp::SetMulticastInterface(const Twine& interfaceAddr) {
|
||||
SmallString<128> interfaceAddrBuf;
|
||||
Invoke(&uv_udp_set_multicast_interface, GetRaw(),
|
||||
interfaceAddr.toNullTerminatedStringRef(interfaceAddrBuf).data());
|
||||
void Udp::SetMulticastInterface(std::string_view interfaceAddr) {
|
||||
SmallString<128> interfaceAddrBuf{interfaceAddr};
|
||||
Invoke(&uv_udp_set_multicast_interface, GetRaw(), interfaceAddrBuf.c_str());
|
||||
}
|
||||
|
||||
void Udp::Send(const sockaddr& addr, ArrayRef<Buffer> bufs,
|
||||
|
||||
@@ -7,26 +7,26 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
class raw_ostream;
|
||||
|
||||
size_t Base64Decode(raw_ostream& os, StringRef encoded);
|
||||
size_t Base64Decode(raw_ostream& os, std::string_view encoded);
|
||||
|
||||
size_t Base64Decode(StringRef encoded, std::string* plain);
|
||||
size_t Base64Decode(std::string_view encoded, std::string* plain);
|
||||
|
||||
StringRef Base64Decode(StringRef encoded, size_t* num_read,
|
||||
SmallVectorImpl<char>& buf);
|
||||
std::string_view Base64Decode(std::string_view encoded, size_t* num_read,
|
||||
SmallVectorImpl<char>& buf);
|
||||
|
||||
void Base64Encode(raw_ostream& os, StringRef plain);
|
||||
void Base64Encode(raw_ostream& os, std::string_view plain);
|
||||
|
||||
void Base64Encode(StringRef plain, std::string* encoded);
|
||||
void Base64Encode(std::string_view plain, std::string* encoded);
|
||||
|
||||
StringRef Base64Encode(StringRef plain, SmallVectorImpl<char>& buf);
|
||||
std::string_view Base64Encode(std::string_view plain,
|
||||
SmallVectorImpl<char>& buf);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
|
||||
@@ -91,10 +91,10 @@
|
||||
#define LLVM_SUPPORT_CONVERTUTF_H
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/StringRef.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
// Wrap everything in namespace wpi so that programs can link with wpiutil and
|
||||
@@ -243,15 +243,15 @@ bool convertUTF16ToUTF8String(ArrayRef<UTF16> SrcUTF16,
|
||||
*
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF8ToUTF16String(StringRef SrcUTF8,
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16);
|
||||
|
||||
#if defined(_WIN32)
|
||||
namespace sys {
|
||||
namespace windows {
|
||||
std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
std::error_code UTF8ToUTF16(std::string_view utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
/// Convert to UTF16 from the current code page used in the system
|
||||
std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
std::error_code CurCPToUTF16(std::string_view utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
|
||||
SmallVectorImpl<char> &utf8);
|
||||
/// Convert from UTF16 to the current code page used in the system
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#define WPIUTIL_WPI_DEMANGLE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -17,7 +16,7 @@ namespace wpi {
|
||||
* @param mangledSymbol the mangled symbol.
|
||||
* @return The demangled symbol, or mangledSymbol if demangling fails.
|
||||
*/
|
||||
std::string Demangle(const Twine& mangledSymbol);
|
||||
std::string Demangle(std::string_view mangledSymbol);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
@@ -206,26 +206,26 @@ struct DenseMapInfo<std::pair<T, U>> {
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for StringRefs.
|
||||
template <> struct DenseMapInfo<StringRef> {
|
||||
static inline StringRef getEmptyKey() {
|
||||
return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
|
||||
// Provide DenseMapInfo for std::string_view.
|
||||
template <> struct DenseMapInfo<std::string_view> {
|
||||
static inline std::string_view getEmptyKey() {
|
||||
return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
|
||||
0);
|
||||
}
|
||||
|
||||
static inline StringRef getTombstoneKey() {
|
||||
return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
|
||||
static inline std::string_view getTombstoneKey() {
|
||||
return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
|
||||
0);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(StringRef Val) {
|
||||
static unsigned getHashValue(std::string_view Val) {
|
||||
assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
|
||||
assert(Val.data() != getTombstoneKey().data() &&
|
||||
"Cannot hash the tombstone key!");
|
||||
return (unsigned)(hash_value(Val));
|
||||
}
|
||||
|
||||
static bool isEqual(StringRef LHS, StringRef RHS) {
|
||||
static bool isEqual(std::string_view LHS, std::string_view RHS) {
|
||||
if (RHS.data() == getEmptyKey().data())
|
||||
return LHS.data() == getEmptyKey().data();
|
||||
if (RHS.data() == getTombstoneKey().data())
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,11 +17,9 @@
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
class StringRef;
|
||||
class Twine;
|
||||
|
||||
/// An error handler callback.
|
||||
typedef void (*fatal_error_handler_t)(void *user_data,
|
||||
const std::string& reason,
|
||||
@@ -73,9 +71,7 @@ LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason,
|
||||
bool gen_crash_diag = true);
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const std::string &reason,
|
||||
bool gen_crash_diag = true);
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(StringRef reason,
|
||||
bool gen_crash_diag = true);
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const Twine &reason,
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(std::string_view reason,
|
||||
bool gen_crash_diag = true);
|
||||
|
||||
/// Installs a new bad alloc error handler that should be used whenever a
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Provides ErrorOr<T> smart pointer.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERROROR_H
|
||||
#define WPIUTIL_WPI_ERROROR_H
|
||||
|
||||
#include "wpi/AlignOf.h"
|
||||
#include <cassert>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// Represents either an error or a value T.
|
||||
///
|
||||
/// ErrorOr<T> is a pointer-like class that represents the result of an
|
||||
/// operation. The result is either an error, or a value of type T. This is
|
||||
/// designed to emulate the usage of returning a pointer where nullptr indicates
|
||||
/// failure. However instead of just knowing that the operation failed, we also
|
||||
/// have an error_code and optional user data that describes why it failed.
|
||||
///
|
||||
/// It is used like the following.
|
||||
/// \code
|
||||
/// ErrorOr<Buffer> getBuffer();
|
||||
///
|
||||
/// auto buffer = getBuffer();
|
||||
/// if (error_code ec = buffer.getError())
|
||||
/// return ec;
|
||||
/// buffer->write("adena");
|
||||
/// \endcode
|
||||
///
|
||||
///
|
||||
/// Implicit conversion to bool returns true if there is a usable value. The
|
||||
/// unary * and -> operators provide pointer like access to the value. Accessing
|
||||
/// the value when there is an error has undefined behavior.
|
||||
///
|
||||
/// When T is a reference type the behavior is slightly different. The reference
|
||||
/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
|
||||
/// there is special handling to make operator -> work as if T was not a
|
||||
/// reference.
|
||||
///
|
||||
/// T cannot be a rvalue reference.
|
||||
template<class T>
|
||||
class ErrorOr {
|
||||
template <class OtherT> friend class ErrorOr;
|
||||
|
||||
static const bool isRef = std::is_reference<T>::value;
|
||||
|
||||
using wrap = std::reference_wrapper<typename std::remove_reference<T>::type>;
|
||||
|
||||
public:
|
||||
using storage_type = typename std::conditional<isRef, wrap, T>::type;
|
||||
|
||||
private:
|
||||
using reference = typename std::remove_reference<T>::type &;
|
||||
using const_reference = const typename std::remove_reference<T>::type &;
|
||||
using pointer = typename std::remove_reference<T>::type *;
|
||||
using const_pointer = const typename std::remove_reference<T>::type *;
|
||||
|
||||
public:
|
||||
template <class E>
|
||||
ErrorOr(E ErrorCode,
|
||||
typename std::enable_if<std::is_error_code_enum<E>::value ||
|
||||
std::is_error_condition_enum<E>::value,
|
||||
void *>::type = nullptr)
|
||||
: HasError(true) {
|
||||
new (getErrorStorage()) std::error_code(make_error_code(ErrorCode));
|
||||
}
|
||||
|
||||
ErrorOr(std::error_code EC) : HasError(true) {
|
||||
new (getErrorStorage()) std::error_code(EC);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
ErrorOr(OtherT &&Val,
|
||||
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
|
||||
* = nullptr)
|
||||
: HasError(false) {
|
||||
new (getStorage()) storage_type(std::forward<OtherT>(Val));
|
||||
}
|
||||
|
||||
ErrorOr(const ErrorOr &Other) {
|
||||
copyConstruct(Other);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
ErrorOr(
|
||||
const ErrorOr<OtherT> &Other,
|
||||
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
|
||||
nullptr) {
|
||||
copyConstruct(Other);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
explicit ErrorOr(
|
||||
const ErrorOr<OtherT> &Other,
|
||||
typename std::enable_if<
|
||||
!std::is_convertible<OtherT, const T &>::value>::type * = nullptr) {
|
||||
copyConstruct(Other);
|
||||
}
|
||||
|
||||
ErrorOr(ErrorOr &&Other) {
|
||||
moveConstruct(std::move(Other));
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
ErrorOr(
|
||||
ErrorOr<OtherT> &&Other,
|
||||
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
|
||||
nullptr) {
|
||||
moveConstruct(std::move(Other));
|
||||
}
|
||||
|
||||
// This might eventually need SFINAE but it's more complex than is_convertible
|
||||
// & I'm too lazy to write it right now.
|
||||
template <class OtherT>
|
||||
explicit ErrorOr(
|
||||
ErrorOr<OtherT> &&Other,
|
||||
typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
|
||||
nullptr) {
|
||||
moveConstruct(std::move(Other));
|
||||
}
|
||||
|
||||
ErrorOr &operator=(const ErrorOr &Other) {
|
||||
copyAssign(Other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr &operator=(ErrorOr &&Other) {
|
||||
moveAssign(std::move(Other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ErrorOr() {
|
||||
if (!HasError)
|
||||
getStorage()->~storage_type();
|
||||
}
|
||||
|
||||
/// Return false if there is an error.
|
||||
explicit operator bool() const {
|
||||
return !HasError;
|
||||
}
|
||||
|
||||
reference get() { return *getStorage(); }
|
||||
const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
|
||||
|
||||
std::error_code getError() const {
|
||||
return HasError ? *getErrorStorage() : std::error_code();
|
||||
}
|
||||
|
||||
pointer operator ->() {
|
||||
return toPointer(getStorage());
|
||||
}
|
||||
|
||||
const_pointer operator->() const { return toPointer(getStorage()); }
|
||||
|
||||
reference operator *() {
|
||||
return *getStorage();
|
||||
}
|
||||
|
||||
const_reference operator*() const { return *getStorage(); }
|
||||
|
||||
private:
|
||||
template <class OtherT>
|
||||
void copyConstruct(const ErrorOr<OtherT> &Other) {
|
||||
if (!Other.HasError) {
|
||||
// Get the other value.
|
||||
HasError = false;
|
||||
new (getStorage()) storage_type(*Other.getStorage());
|
||||
} else {
|
||||
// Get other's error.
|
||||
HasError = true;
|
||||
new (getErrorStorage()) std::error_code(Other.getError());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T1>
|
||||
static bool compareThisIfSameType(const T1 &a, const T1 &b) {
|
||||
return &a == &b;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
static bool compareThisIfSameType(const T1 &a, const T2 &b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
void copyAssign(const ErrorOr<OtherT> &Other) {
|
||||
if (compareThisIfSameType(*this, Other))
|
||||
return;
|
||||
|
||||
this->~ErrorOr();
|
||||
new (this) ErrorOr(Other);
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
void moveConstruct(ErrorOr<OtherT> &&Other) {
|
||||
if (!Other.HasError) {
|
||||
// Get the other value.
|
||||
HasError = false;
|
||||
new (getStorage()) storage_type(std::move(*Other.getStorage()));
|
||||
} else {
|
||||
// Get other's error.
|
||||
HasError = true;
|
||||
new (getErrorStorage()) std::error_code(Other.getError());
|
||||
}
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
void moveAssign(ErrorOr<OtherT> &&Other) {
|
||||
if (compareThisIfSameType(*this, Other))
|
||||
return;
|
||||
|
||||
this->~ErrorOr();
|
||||
new (this) ErrorOr(std::move(Other));
|
||||
}
|
||||
|
||||
pointer toPointer(pointer Val) {
|
||||
return Val;
|
||||
}
|
||||
|
||||
const_pointer toPointer(const_pointer Val) const { return Val; }
|
||||
|
||||
pointer toPointer(wrap *Val) {
|
||||
return &Val->get();
|
||||
}
|
||||
|
||||
const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
|
||||
|
||||
storage_type *getStorage() {
|
||||
assert(!HasError && "Cannot get value when an error exists!");
|
||||
return reinterpret_cast<storage_type*>(TStorage.buffer);
|
||||
}
|
||||
|
||||
const storage_type *getStorage() const {
|
||||
assert(!HasError && "Cannot get value when an error exists!");
|
||||
return reinterpret_cast<const storage_type*>(TStorage.buffer);
|
||||
}
|
||||
|
||||
std::error_code *getErrorStorage() {
|
||||
assert(HasError && "Cannot get error when a value exists!");
|
||||
return reinterpret_cast<std::error_code *>(ErrorStorage.buffer);
|
||||
}
|
||||
|
||||
const std::error_code *getErrorStorage() const {
|
||||
return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
|
||||
}
|
||||
|
||||
union {
|
||||
AlignedCharArrayUnion<storage_type> TStorage;
|
||||
AlignedCharArrayUnion<std::error_code> ErrorStorage;
|
||||
};
|
||||
bool HasError : 1;
|
||||
};
|
||||
|
||||
template <class T, class E>
|
||||
typename std::enable_if<std::is_error_code_enum<E>::value ||
|
||||
std::is_error_condition_enum<E>::value,
|
||||
bool>::type
|
||||
operator==(const ErrorOr<T> &Err, E Code) {
|
||||
return Err.getError() == Code;
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_SUPPORT_ERROROR_H
|
||||
@@ -1,265 +0,0 @@
|
||||
//===- Format.h - Efficient printf-style formatting for streams -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the format() function, which can be used with other
|
||||
// LLVM subsystems to provide printf-style formatting. This gives all the power
|
||||
// and risk of printf. This can be used like this (with raw_ostreams as an
|
||||
// example):
|
||||
//
|
||||
// OS << "mynumber: " << format("%4.5f", 1234.412) << '\n';
|
||||
//
|
||||
// Or if you prefer:
|
||||
//
|
||||
// OS << format("mynumber: %4.5f\n", 1234.412);
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_FORMAT_H
|
||||
#define WPIUTIL_WPI_FORMAT_H
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// This is a helper class used for handling formatted output. It is the
|
||||
/// abstract base class of a templated derived class.
|
||||
class format_object_base {
|
||||
protected:
|
||||
const char *Fmt;
|
||||
~format_object_base() = default; // Disallow polymorphic deletion.
|
||||
format_object_base(const format_object_base &) = default;
|
||||
virtual void home(); // Out of line virtual method.
|
||||
|
||||
/// Call snprintf() for this object, on the given buffer and size.
|
||||
virtual int snprint(char *Buffer, unsigned BufferSize) const = 0;
|
||||
|
||||
public:
|
||||
format_object_base(const char *fmt) : Fmt(fmt) {}
|
||||
|
||||
/// Format the object into the specified buffer. On success, this returns
|
||||
/// the length of the formatted string. If the buffer is too small, this
|
||||
/// returns a length to retry with, which will be larger than BufferSize.
|
||||
unsigned print(char *Buffer, unsigned BufferSize) const {
|
||||
assert(BufferSize && "Invalid buffer size!");
|
||||
|
||||
// Print the string, leaving room for the terminating null.
|
||||
int N = snprint(Buffer, BufferSize);
|
||||
|
||||
// VC++ and old GlibC return negative on overflow, just double the size.
|
||||
if (N < 0)
|
||||
return BufferSize * 2;
|
||||
|
||||
// Other implementations yield number of bytes needed, not including the
|
||||
// final '\0'.
|
||||
if (unsigned(N) >= BufferSize)
|
||||
return N + 1;
|
||||
|
||||
// Otherwise N is the length of output (not including the final '\0').
|
||||
return N;
|
||||
}
|
||||
};
|
||||
|
||||
/// These are templated helper classes used by the format function that
|
||||
/// capture the object to be formatted and the format string. When actually
|
||||
/// printed, this synthesizes the string into a temporary buffer provided and
|
||||
/// returns whether or not it is big enough.
|
||||
|
||||
// Helper to validate that format() parameters are scalars or pointers.
|
||||
template <typename... Args> struct validate_format_parameters;
|
||||
template <typename Arg, typename... Args>
|
||||
struct validate_format_parameters<Arg, Args...> {
|
||||
static_assert(std::is_scalar<Arg>::value,
|
||||
"format can't be used with non fundamental / non pointer type");
|
||||
validate_format_parameters() { validate_format_parameters<Args...>(); }
|
||||
};
|
||||
template <> struct validate_format_parameters<> {};
|
||||
|
||||
template <typename... Ts>
|
||||
class format_object final : public format_object_base {
|
||||
std::tuple<Ts...> Vals;
|
||||
|
||||
template <std::size_t... Is>
|
||||
int snprint_tuple(char *Buffer, unsigned BufferSize,
|
||||
std::index_sequence<Is...>) const {
|
||||
#ifdef _MSC_VER
|
||||
return _snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
return snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
format_object(const char *fmt, const Ts &... vals)
|
||||
: format_object_base(fmt), Vals(vals...) {
|
||||
validate_format_parameters<Ts...>();
|
||||
}
|
||||
|
||||
int snprint(char *Buffer, unsigned BufferSize) const override {
|
||||
return snprint_tuple(Buffer, BufferSize, std::index_sequence_for<Ts...>());
|
||||
}
|
||||
};
|
||||
|
||||
/// These are helper functions used to produce formatted output. They use
|
||||
/// template type deduction to construct the appropriate instance of the
|
||||
/// format_object class to simplify their construction.
|
||||
///
|
||||
/// This is typically used like:
|
||||
/// \code
|
||||
/// OS << format("%0.4f", myfloat) << '\n';
|
||||
/// \endcode
|
||||
|
||||
template <typename... Ts>
|
||||
inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) {
|
||||
return format_object<Ts...>(Fmt, Vals...);
|
||||
}
|
||||
|
||||
/// This is a helper class for left_justify, right_justify, and center_justify.
|
||||
class FormattedString {
|
||||
public:
|
||||
enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter };
|
||||
FormattedString(StringRef S, unsigned W, Justification J)
|
||||
: Str(S), Width(W), Justify(J) {}
|
||||
|
||||
private:
|
||||
StringRef Str;
|
||||
unsigned Width;
|
||||
Justification Justify;
|
||||
friend class raw_ostream;
|
||||
};
|
||||
|
||||
/// left_justify - append spaces after string so total output is
|
||||
/// \p Width characters. If \p Str is larger that \p Width, full string
|
||||
/// is written with no padding.
|
||||
inline FormattedString left_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, FormattedString::JustifyLeft);
|
||||
}
|
||||
|
||||
/// right_justify - add spaces before string so total output is
|
||||
/// \p Width characters. If \p Str is larger that \p Width, full string
|
||||
/// is written with no padding.
|
||||
inline FormattedString right_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, FormattedString::JustifyRight);
|
||||
}
|
||||
|
||||
/// center_justify - add spaces before and after string so total output is
|
||||
/// \p Width characters. If \p Str is larger that \p Width, full string
|
||||
/// is written with no padding.
|
||||
inline FormattedString center_justify(StringRef Str, unsigned Width) {
|
||||
return FormattedString(Str, Width, FormattedString::JustifyCenter);
|
||||
}
|
||||
|
||||
/// This is a helper class used for format_hex() and format_decimal().
|
||||
class FormattedNumber {
|
||||
uint64_t HexValue;
|
||||
int64_t DecValue;
|
||||
unsigned Width;
|
||||
bool Hex;
|
||||
bool Upper;
|
||||
bool HexPrefix;
|
||||
friend class raw_ostream;
|
||||
|
||||
public:
|
||||
FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U,
|
||||
bool Prefix)
|
||||
: HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U),
|
||||
HexPrefix(Prefix) {}
|
||||
};
|
||||
|
||||
/// format_hex - Output \p N as a fixed width hexadecimal. If number will not
|
||||
/// fit in width, full number is still printed. Examples:
|
||||
/// OS << format_hex(255, 4) => 0xff
|
||||
/// OS << format_hex(255, 4, true) => 0xFF
|
||||
/// OS << format_hex(255, 6) => 0x00ff
|
||||
/// OS << format_hex(255, 2) => 0xff
|
||||
inline FormattedNumber format_hex(uint64_t N, unsigned Width,
|
||||
bool Upper = false) {
|
||||
assert(Width <= 18 && "hex width must be <= 18");
|
||||
return FormattedNumber(N, 0, Width, true, Upper, true);
|
||||
}
|
||||
|
||||
/// format_hex_no_prefix - Output \p N as a fixed width hexadecimal. Does not
|
||||
/// prepend '0x' to the outputted string. If number will not fit in width,
|
||||
/// full number is still printed. Examples:
|
||||
/// OS << format_hex_no_prefix(255, 2) => ff
|
||||
/// OS << format_hex_no_prefix(255, 2, true) => FF
|
||||
/// OS << format_hex_no_prefix(255, 4) => 00ff
|
||||
/// OS << format_hex_no_prefix(255, 1) => ff
|
||||
inline FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width,
|
||||
bool Upper = false) {
|
||||
assert(Width <= 16 && "hex width must be <= 16");
|
||||
return FormattedNumber(N, 0, Width, true, Upper, false);
|
||||
}
|
||||
|
||||
/// format_decimal - Output \p N as a right justified, fixed-width decimal. If
|
||||
/// number will not fit in width, full number is still printed. Examples:
|
||||
/// OS << format_decimal(0, 5) => " 0"
|
||||
/// OS << format_decimal(255, 5) => " 255"
|
||||
/// OS << format_decimal(-1, 3) => " -1"
|
||||
/// OS << format_decimal(12345, 3) => "12345"
|
||||
inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
|
||||
return FormattedNumber(0, N, Width, false, false, false);
|
||||
}
|
||||
|
||||
class FormattedBytes {
|
||||
ArrayRef<uint8_t> Bytes;
|
||||
|
||||
// If not nullopt, display offsets for each line relative to starting value.
|
||||
std::optional<uint64_t> FirstByteOffset;
|
||||
uint32_t IndentLevel; // Number of characters to indent each line.
|
||||
uint32_t NumPerLine; // Number of bytes to show per line.
|
||||
uint8_t ByteGroupSize; // How many hex bytes are grouped without spaces
|
||||
bool Upper; // Show offset and hex bytes as upper case.
|
||||
bool ASCII; // Show the ASCII bytes for the hex bytes to the right.
|
||||
friend class raw_ostream;
|
||||
|
||||
public:
|
||||
FormattedBytes(ArrayRef<uint8_t> B, uint32_t IL, std::optional<uint64_t> O,
|
||||
uint32_t NPL, uint8_t BGS, bool U, bool A)
|
||||
: Bytes(B), FirstByteOffset(O), IndentLevel(IL), NumPerLine(NPL),
|
||||
ByteGroupSize(BGS), Upper(U), ASCII(A) {
|
||||
|
||||
if (ByteGroupSize > NumPerLine)
|
||||
ByteGroupSize = NumPerLine;
|
||||
}
|
||||
};
|
||||
|
||||
inline FormattedBytes
|
||||
format_bytes(ArrayRef<uint8_t> Bytes, std::optional<uint64_t> FirstByteOffset = std::nullopt,
|
||||
uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
|
||||
uint32_t IndentLevel = 0, bool Upper = false) {
|
||||
return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
|
||||
ByteGroupSize, Upper, false);
|
||||
}
|
||||
|
||||
inline FormattedBytes
|
||||
format_bytes_with_ascii(ArrayRef<uint8_t> Bytes,
|
||||
std::optional<uint64_t> FirstByteOffset = std::nullopt,
|
||||
uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
|
||||
uint32_t IndentLevel = 0, bool Upper = false) {
|
||||
return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
|
||||
ByteGroupSize, Upper, true);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -660,6 +661,11 @@ hash_code hash_value(const std::basic_string<T> &arg) {
|
||||
return hash_combine_range(arg.begin(), arg.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string_view<T> &arg) {
|
||||
return hash_combine_range(arg.begin(), arg.end());
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/http_parser.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -58,9 +59,10 @@ class HttpParser {
|
||||
* @param in input data
|
||||
* @return Trailing input data after the parse.
|
||||
*/
|
||||
StringRef Execute(StringRef in) {
|
||||
return in.drop_front(
|
||||
std::string_view Execute(std::string_view in) {
|
||||
in.remove_prefix(
|
||||
http_parser_execute(&m_parser, &m_settings, in.data(), in.size()));
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +138,7 @@ class HttpParser {
|
||||
/**
|
||||
* Get URL. Valid in and after the url callback has been called.
|
||||
*/
|
||||
StringRef GetUrl() const { return m_urlBuf; }
|
||||
std::string_view GetUrl() const { return m_urlBuf.str(); }
|
||||
|
||||
/**
|
||||
* Message begin callback.
|
||||
@@ -148,7 +150,7 @@ class HttpParser {
|
||||
*
|
||||
* The parameter to the callback is the complete URL string.
|
||||
*/
|
||||
sig::Signal<StringRef> url;
|
||||
sig::Signal<std::string_view> url;
|
||||
|
||||
/**
|
||||
* Status callback.
|
||||
@@ -156,14 +158,14 @@ class HttpParser {
|
||||
* The parameter to the callback is the complete status string.
|
||||
* GetStatusCode() can be used to get the numeric status code.
|
||||
*/
|
||||
sig::Signal<StringRef> status;
|
||||
sig::Signal<std::string_view> status;
|
||||
|
||||
/**
|
||||
* Header field callback.
|
||||
*
|
||||
* The parameters to the callback are the field name and field value.
|
||||
*/
|
||||
sig::Signal<StringRef, StringRef> header;
|
||||
sig::Signal<std::string_view, std::string_view> header;
|
||||
|
||||
/**
|
||||
* Headers complete callback.
|
||||
@@ -183,7 +185,7 @@ class HttpParser {
|
||||
* multiple times arbitrarily (e.g. it's possible that it may be called with
|
||||
* just a few characters at a time).
|
||||
*/
|
||||
sig::Signal<StringRef, bool> body;
|
||||
sig::Signal<std::string_view, bool> body;
|
||||
|
||||
/**
|
||||
* Headers complete callback.
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
#define WPIUTIL_WPI_HTTPSERVERCONNECTION_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/HttpParser.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Stream.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -64,9 +63,9 @@ class HttpServerConnection {
|
||||
* be set to false.
|
||||
* @param extra Extra HTTP headers to send, including final "\r\n"
|
||||
*/
|
||||
virtual void BuildHeader(raw_ostream& os, int code, const Twine& codeText,
|
||||
const Twine& contentType, uint64_t contentLength,
|
||||
const Twine& extra = Twine{});
|
||||
virtual void BuildHeader(raw_ostream& os, int code, std::string_view codeText,
|
||||
std::string_view contentType, uint64_t contentLength,
|
||||
std::string_view extra = {});
|
||||
|
||||
/**
|
||||
* Send data to client.
|
||||
@@ -91,9 +90,10 @@ class HttpServerConnection {
|
||||
* @param content Response message content
|
||||
* @param extraHeader Extra HTTP headers to send, including final "\r\n"
|
||||
*/
|
||||
virtual void SendResponse(int code, const Twine& codeText,
|
||||
const Twine& contentType, StringRef content,
|
||||
const Twine& extraHeader = Twine{});
|
||||
virtual void SendResponse(int code, std::string_view codeText,
|
||||
std::string_view contentType,
|
||||
std::string_view content,
|
||||
std::string_view extraHeader = {});
|
||||
|
||||
/**
|
||||
* Send HTTP response from static data, along with other header information
|
||||
@@ -109,10 +109,10 @@ class HttpServerConnection {
|
||||
* @param gzipped True if content is gzip compressed
|
||||
* @param extraHeader Extra HTTP headers to send, including final "\r\n"
|
||||
*/
|
||||
virtual void SendStaticResponse(int code, const Twine& codeText,
|
||||
const Twine& contentType, StringRef content,
|
||||
bool gzipped,
|
||||
const Twine& extraHeader = Twine{});
|
||||
virtual void SendStaticResponse(int code, std::string_view codeText,
|
||||
std::string_view contentType,
|
||||
std::string_view content, bool gzipped,
|
||||
std::string_view extraHeader = {});
|
||||
|
||||
/**
|
||||
* Send error header and message.
|
||||
@@ -123,7 +123,7 @@ class HttpServerConnection {
|
||||
* @param code HTTP error code (e.g. 404)
|
||||
* @param message Additional message text
|
||||
*/
|
||||
virtual void SendError(int code, const Twine& message = Twine{});
|
||||
virtual void SendError(int code, std::string_view message = {});
|
||||
|
||||
/** The HTTP request. */
|
||||
HttpParser m_request{HttpParser::kRequest};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -17,8 +18,6 @@
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringMap.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/raw_istream.h"
|
||||
#include "wpi/raw_socket_istream.h"
|
||||
#include "wpi/raw_socket_ostream.h"
|
||||
@@ -29,15 +28,15 @@ namespace wpi {
|
||||
// @param buf Buffer for output
|
||||
// @param error Set to true if an error occurred
|
||||
// @return Escaped string
|
||||
StringRef UnescapeURI(const Twine& str, SmallVectorImpl<char>& buf,
|
||||
bool* error);
|
||||
std::string_view UnescapeURI(std::string_view str, SmallVectorImpl<char>& buf,
|
||||
bool* error);
|
||||
|
||||
// Escape a string with %xx-encoding.
|
||||
// @param buf Buffer for output
|
||||
// @param spacePlus If true, encodes spaces to '+' rather than "%20"
|
||||
// @return Escaped string
|
||||
StringRef EscapeURI(const Twine& str, SmallVectorImpl<char>& buf,
|
||||
bool spacePlus = true);
|
||||
std::string_view EscapeURI(std::string_view str, SmallVectorImpl<char>& buf,
|
||||
bool spacePlus = true);
|
||||
|
||||
// Parse a set of HTTP headers. Saves just the Content-Type and Content-Length
|
||||
// fields.
|
||||
@@ -55,7 +54,7 @@ bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
|
||||
// @param saveBuf If not null, all scanned characters up to but not including
|
||||
// the boundary are saved to this string
|
||||
// @return False if error occurred on input stream, true if boundary found.
|
||||
bool FindMultipartBoundary(wpi::raw_istream& is, StringRef boundary,
|
||||
bool FindMultipartBoundary(wpi::raw_istream& is, std::string_view boundary,
|
||||
std::string* saveBuf);
|
||||
|
||||
/**
|
||||
@@ -77,7 +76,7 @@ class HttpQueryMap {
|
||||
*
|
||||
* @param query query string
|
||||
*/
|
||||
explicit HttpQueryMap(StringRef query);
|
||||
explicit HttpQueryMap(std::string_view query);
|
||||
|
||||
/**
|
||||
* Gets an element of the query string. Both the name and the returned
|
||||
@@ -88,11 +87,11 @@ class HttpQueryMap {
|
||||
* @return Optional unescaped value. Returns an empty optional if the
|
||||
* name is not present in the query map.
|
||||
*/
|
||||
std::optional<StringRef> Get(StringRef name,
|
||||
SmallVectorImpl<char>& buf) const;
|
||||
std::optional<std::string_view> Get(std::string_view name,
|
||||
SmallVectorImpl<char>& buf) const;
|
||||
|
||||
private:
|
||||
StringMap<StringRef> m_elems;
|
||||
StringMap<std::string_view> m_elems;
|
||||
};
|
||||
|
||||
class HttpPathRef;
|
||||
@@ -120,7 +119,7 @@ class HttpPath {
|
||||
* Constructs a HTTP path from an escaped path string. Makes a copy of the
|
||||
* path, so it's safe to be a temporary.
|
||||
*/
|
||||
explicit HttpPath(StringRef path);
|
||||
explicit HttpPath(std::string_view path);
|
||||
|
||||
/**
|
||||
* Evaluates to true if the path is not empty.
|
||||
@@ -143,11 +142,15 @@ class HttpPath {
|
||||
* @param match match list
|
||||
* @return True if path equals match list
|
||||
*/
|
||||
bool equals(std::initializer_list<StringRef> match) const {
|
||||
bool equals(std::initializer_list<std::string_view> match) const {
|
||||
return equals(0, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
bool equals(ArrayRef<StringRef> match) const { return equals(0, match); }
|
||||
bool equals(StringRef match) const { return equals(0, makeArrayRef(match)); }
|
||||
bool equals(ArrayRef<std::string_view> match) const {
|
||||
return equals(0, match);
|
||||
}
|
||||
bool equals(std::string_view match) const {
|
||||
return equals(0, makeArrayRef(match));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the elements of the path starting at the "start" element
|
||||
@@ -157,16 +160,17 @@ class HttpPath {
|
||||
* @param match match list
|
||||
* @return True if match
|
||||
*/
|
||||
bool equals(size_t start, std::initializer_list<StringRef> match) const {
|
||||
bool equals(size_t start,
|
||||
std::initializer_list<std::string_view> match) const {
|
||||
return equals(start, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
bool equals(size_t start, ArrayRef<StringRef> match) const {
|
||||
bool equals(size_t start, ArrayRef<std::string_view> match) const {
|
||||
if (m_pathEnds.size() != (start + match.size())) {
|
||||
return false;
|
||||
}
|
||||
return startswith(start, match);
|
||||
}
|
||||
bool equals(size_t start, StringRef match) const {
|
||||
bool equals(size_t start, std::string_view match) const {
|
||||
return equals(start, makeArrayRef(match));
|
||||
}
|
||||
|
||||
@@ -177,13 +181,13 @@ class HttpPath {
|
||||
* @param match match list
|
||||
* @return True if path starts with match list
|
||||
*/
|
||||
bool startswith(std::initializer_list<StringRef> match) const {
|
||||
bool startswith(std::initializer_list<std::string_view> match) const {
|
||||
return startswith(0, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
bool startswith(ArrayRef<StringRef> match) const {
|
||||
bool startswith(ArrayRef<std::string_view> match) const {
|
||||
return startswith(0, match);
|
||||
}
|
||||
bool startswith(StringRef match) const {
|
||||
bool startswith(std::string_view match) const {
|
||||
return startswith(0, makeArrayRef(match));
|
||||
}
|
||||
|
||||
@@ -195,22 +199,21 @@ class HttpPath {
|
||||
* @param match match list
|
||||
* @return True if path starting at the start element matches the match list
|
||||
*/
|
||||
bool startswith(size_t start, std::initializer_list<StringRef> match) const {
|
||||
bool startswith(size_t start,
|
||||
std::initializer_list<std::string_view> match) const {
|
||||
return startswith(start, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
|
||||
bool startswith(size_t start, ArrayRef<StringRef> match) const;
|
||||
bool startswith(size_t start, ArrayRef<std::string_view> match) const;
|
||||
|
||||
bool startswith(size_t start, StringRef match) const {
|
||||
bool startswith(size_t start, std::string_view match) const {
|
||||
return startswith(start, makeArrayRef(match));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single element of the path.
|
||||
*/
|
||||
StringRef operator[](size_t n) const {
|
||||
return m_pathBuf.slice(n == 0 ? 0 : m_pathEnds[n - 1], m_pathEnds[n]);
|
||||
}
|
||||
std::string_view operator[](size_t n) const;
|
||||
|
||||
/**
|
||||
* Returns a path reference with the first N elements of the path removed.
|
||||
@@ -236,44 +239,50 @@ class HttpPathRef {
|
||||
bool empty() const { return m_path && m_path->size() == m_start; }
|
||||
size_t size() const { return m_path ? m_path->size() - m_start : 0; }
|
||||
|
||||
bool equals(std::initializer_list<StringRef> match) const {
|
||||
bool equals(std::initializer_list<std::string_view> match) const {
|
||||
return equals(0, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
bool equals(ArrayRef<StringRef> match) const { return equals(0, match); }
|
||||
bool equals(StringRef match) const { return equals(0, makeArrayRef(match)); }
|
||||
bool equals(ArrayRef<std::string_view> match) const {
|
||||
return equals(0, match);
|
||||
}
|
||||
bool equals(std::string_view match) const {
|
||||
return equals(0, makeArrayRef(match));
|
||||
}
|
||||
|
||||
bool equals(size_t start, std::initializer_list<StringRef> match) const {
|
||||
bool equals(size_t start,
|
||||
std::initializer_list<std::string_view> match) const {
|
||||
return equals(start, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
bool equals(size_t start, ArrayRef<StringRef> match) const {
|
||||
bool equals(size_t start, ArrayRef<std::string_view> match) const {
|
||||
return m_path ? m_path->equals(m_start + start, match) : false;
|
||||
}
|
||||
bool equals(size_t start, StringRef match) const {
|
||||
bool equals(size_t start, std::string_view match) const {
|
||||
return equals(start, makeArrayRef(match));
|
||||
}
|
||||
|
||||
bool startswith(std::initializer_list<StringRef> match) const {
|
||||
bool startswith(std::initializer_list<std::string_view> match) const {
|
||||
return startswith(0, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
bool startswith(ArrayRef<StringRef> match) const {
|
||||
bool startswith(ArrayRef<std::string_view> match) const {
|
||||
return startswith(0, match);
|
||||
}
|
||||
bool startswith(StringRef match) const {
|
||||
bool startswith(std::string_view match) const {
|
||||
return startswith(0, makeArrayRef(match));
|
||||
}
|
||||
|
||||
bool startswith(size_t start, std::initializer_list<StringRef> match) const {
|
||||
bool startswith(size_t start,
|
||||
std::initializer_list<std::string_view> match) const {
|
||||
return startswith(start, makeArrayRef(match.begin(), match.end()));
|
||||
}
|
||||
bool startswith(size_t start, ArrayRef<StringRef> match) const {
|
||||
bool startswith(size_t start, ArrayRef<std::string_view> match) const {
|
||||
return m_path ? m_path->startswith(m_start + start, match) : false;
|
||||
}
|
||||
bool startswith(size_t start, StringRef match) const {
|
||||
bool startswith(size_t start, std::string_view match) const {
|
||||
return startswith(start, makeArrayRef(match));
|
||||
}
|
||||
|
||||
StringRef operator[](size_t n) const {
|
||||
return m_path ? m_path->operator[](m_start + n) : StringRef{};
|
||||
std::string_view operator[](size_t n) const {
|
||||
return m_path ? m_path->operator[](m_start + n) : std::string_view{};
|
||||
}
|
||||
HttpPathRef drop_front(size_t n) const {
|
||||
return m_path ? m_path->drop_front(m_start + n) : HttpPathRef{};
|
||||
@@ -287,7 +296,7 @@ class HttpPathRef {
|
||||
class HttpLocation {
|
||||
public:
|
||||
HttpLocation() = default;
|
||||
HttpLocation(const Twine& url_, bool* error, std::string* errorMsg);
|
||||
HttpLocation(std::string_view url_, bool* error, std::string* errorMsg);
|
||||
|
||||
std::string url; // retain copy
|
||||
std::string user; // unescaped
|
||||
@@ -312,13 +321,13 @@ class HttpRequest {
|
||||
template <typename T>
|
||||
HttpRequest(const HttpLocation& loc, const T& extraParams);
|
||||
|
||||
HttpRequest(const HttpLocation& loc, StringRef path_)
|
||||
HttpRequest(const HttpLocation& loc, std::string_view path_)
|
||||
: host{loc.host}, port{loc.port}, path{path_} {
|
||||
SetAuth(loc);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HttpRequest(const HttpLocation& loc, StringRef path_, const T& params)
|
||||
HttpRequest(const HttpLocation& loc, std::string_view path_, const T& params)
|
||||
: host{loc.host}, port{loc.port} {
|
||||
SetPath(path_, params);
|
||||
SetAuth(loc);
|
||||
@@ -332,18 +341,18 @@ class HttpRequest {
|
||||
private:
|
||||
void SetAuth(const HttpLocation& loc);
|
||||
template <typename T>
|
||||
void SetPath(StringRef path_, const T& params);
|
||||
void SetPath(std::string_view path_, const T& params);
|
||||
|
||||
template <typename T>
|
||||
static StringRef GetFirst(const T& elem) {
|
||||
static std::string_view GetFirst(const T& elem) {
|
||||
return elem.first;
|
||||
}
|
||||
template <typename T>
|
||||
static StringRef GetFirst(const StringMapEntry<T>& elem) {
|
||||
static std::string_view GetFirst(const StringMapEntry<T>& elem) {
|
||||
return elem.getKey();
|
||||
}
|
||||
template <typename T>
|
||||
static StringRef GetSecond(const T& elem) {
|
||||
static std::string_view GetSecond(const T& elem) {
|
||||
return elem.second;
|
||||
}
|
||||
};
|
||||
@@ -368,14 +377,15 @@ class HttpConnection {
|
||||
|
||||
class HttpMultipartScanner {
|
||||
public:
|
||||
explicit HttpMultipartScanner(StringRef boundary, bool saveSkipped = false) {
|
||||
explicit HttpMultipartScanner(std::string_view boundary,
|
||||
bool saveSkipped = false) {
|
||||
Reset(saveSkipped);
|
||||
SetBoundary(boundary);
|
||||
}
|
||||
|
||||
// Change the boundary. This is only safe to do when IsDone() is true (or
|
||||
// immediately after construction).
|
||||
void SetBoundary(StringRef boundary);
|
||||
void SetBoundary(std::string_view boundary);
|
||||
|
||||
// Reset the scanner. This allows reuse of internal buffers.
|
||||
void Reset(bool saveSkipped = false);
|
||||
@@ -384,14 +394,14 @@ class HttpMultipartScanner {
|
||||
// is true.
|
||||
// @param in input data
|
||||
// @return the input not consumed; empty if all input consumed
|
||||
StringRef Execute(StringRef in);
|
||||
std::string_view Execute(std::string_view in);
|
||||
|
||||
// Returns true when the boundary has been found.
|
||||
bool IsDone() const { return m_state == kDone; }
|
||||
|
||||
// Get the skipped data. Will be empty if saveSkipped was false.
|
||||
StringRef GetSkipped() const {
|
||||
return m_saveSkipped ? StringRef{m_buf} : StringRef{};
|
||||
std::string_view GetSkipped() const {
|
||||
return m_saveSkipped ? std::string_view{m_buf} : std::string_view{};
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,7 +18,7 @@ inline HttpPathRef HttpPath::drop_front(size_t n) const {
|
||||
template <typename T>
|
||||
HttpRequest::HttpRequest(const HttpLocation& loc, const T& extraParams)
|
||||
: host{loc.host}, port{loc.port} {
|
||||
StringMap<StringRef> params;
|
||||
StringMap<std::string_view> params;
|
||||
for (const auto& p : loc.params) {
|
||||
params.insert(std::make_pair(GetFirst(p), GetSecond(p)));
|
||||
}
|
||||
@@ -30,7 +30,7 @@ HttpRequest::HttpRequest(const HttpLocation& loc, const T& extraParams)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void HttpRequest::SetPath(StringRef path_, const T& params) {
|
||||
void HttpRequest::SetPath(std::string_view path_, const T& params) {
|
||||
// Build location including query string
|
||||
raw_svector_ostream pathOs{path};
|
||||
pathOs << path_;
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/HttpServerConnection.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/WebSocket.h"
|
||||
#include "wpi/WebSocketServer.h"
|
||||
#include "wpi/uv/Stream.h"
|
||||
@@ -36,7 +36,7 @@ class HttpWebSocketServerConnection
|
||||
* @param protocols Acceptable subprotocols
|
||||
*/
|
||||
HttpWebSocketServerConnection(std::shared_ptr<uv::Stream> stream,
|
||||
ArrayRef<StringRef> protocols);
|
||||
ArrayRef<std::string_view> protocols);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -44,8 +44,9 @@ class HttpWebSocketServerConnection
|
||||
* @param stream network stream
|
||||
* @param protocols Acceptable subprotocols
|
||||
*/
|
||||
HttpWebSocketServerConnection(std::shared_ptr<uv::Stream> stream,
|
||||
std::initializer_list<StringRef> protocols)
|
||||
HttpWebSocketServerConnection(
|
||||
std::shared_ptr<uv::Stream> stream,
|
||||
std::initializer_list<std::string_view> protocols)
|
||||
: HttpWebSocketServerConnection(
|
||||
stream, makeArrayRef(protocols.begin(), protocols.end())) {}
|
||||
|
||||
@@ -59,7 +60,7 @@ class HttpWebSocketServerConnection
|
||||
*
|
||||
* @param protocol negotiated subprotocol
|
||||
*/
|
||||
virtual bool IsValidWsUpgrade(StringRef protocol) { return true; }
|
||||
virtual bool IsValidWsUpgrade(std::string_view protocol) { return true; }
|
||||
|
||||
/**
|
||||
* Process an incoming WebSocket upgrade. This is called after the header
|
||||
|
||||
@@ -13,15 +13,16 @@ namespace wpi {
|
||||
|
||||
template <typename Derived>
|
||||
HttpWebSocketServerConnection<Derived>::HttpWebSocketServerConnection(
|
||||
std::shared_ptr<uv::Stream> stream, ArrayRef<StringRef> protocols)
|
||||
std::shared_ptr<uv::Stream> stream, ArrayRef<std::string_view> protocols)
|
||||
: HttpServerConnection{stream},
|
||||
m_helper{m_request},
|
||||
m_protocols{protocols.begin(), protocols.end()} {
|
||||
// Handle upgrade event
|
||||
m_helper.upgrade.connect([this] {
|
||||
// Negotiate sub-protocol
|
||||
SmallVector<StringRef, 2> protocols{m_protocols.begin(), m_protocols.end()};
|
||||
StringRef protocol = m_helper.MatchProtocol(protocols).second;
|
||||
SmallVector<std::string_view, 2> protocols{m_protocols.begin(),
|
||||
m_protocols.end()};
|
||||
std::string_view protocol = m_helper.MatchProtocol(protocols).second;
|
||||
|
||||
// Check that the upgrade is valid
|
||||
if (!IsValidWsUpgrade(protocol)) {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -40,12 +39,19 @@ class Logger {
|
||||
void set_min_level(unsigned int level) { m_min_level = level; }
|
||||
unsigned int min_level() const { return m_min_level; }
|
||||
|
||||
void DoLog(unsigned int level, const char* file, unsigned int line,
|
||||
const char* msg);
|
||||
|
||||
void LogV(unsigned int level, const char* file, unsigned int line,
|
||||
fmt::string_view format, fmt::format_args args);
|
||||
|
||||
template <typename S, typename... Args>
|
||||
void Log(unsigned int level, const char* file, unsigned int line,
|
||||
const char* msg) {
|
||||
if (!m_func || level < m_min_level) {
|
||||
return;
|
||||
const S& format, Args&&... args) {
|
||||
if (m_func && level >= m_min_level) {
|
||||
LogV(level, file, line, format,
|
||||
fmt::make_args_checked<Args...>(format, args...));
|
||||
}
|
||||
m_func(level, file, line, msg);
|
||||
}
|
||||
|
||||
bool HasLogger() const { return m_func != nullptr; }
|
||||
@@ -55,44 +61,43 @@ class Logger {
|
||||
unsigned int m_min_level = 20;
|
||||
};
|
||||
|
||||
#define WPI_LOG(logger_inst, level, x) \
|
||||
do { \
|
||||
::wpi::Logger& WPI_logger_ = logger_inst; \
|
||||
if (WPI_logger_.min_level() <= static_cast<unsigned int>(level) && \
|
||||
WPI_logger_.HasLogger()) { \
|
||||
::wpi::SmallString<128> log_buf_; \
|
||||
::wpi::raw_svector_ostream log_os_{log_buf_}; \
|
||||
log_os_ << x; \
|
||||
WPI_logger_.Log(level, __FILE__, __LINE__, log_buf_.c_str()); \
|
||||
} \
|
||||
} while (0)
|
||||
#define WPI_LOG(logger_inst, level, format, ...) \
|
||||
logger_inst.Log(level, __FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
|
||||
|
||||
#define WPI_ERROR(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_ERROR, x)
|
||||
#define WPI_WARNING(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_WARNING, x)
|
||||
#define WPI_INFO(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_INFO, x)
|
||||
#define WPI_ERROR(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_ERROR, format, __VA_ARGS__)
|
||||
#define WPI_WARNING(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_WARNING, format, __VA_ARGS__)
|
||||
#define WPI_INFO(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_INFO, format, __VA_ARGS__)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define WPI_DEBUG(inst, x) \
|
||||
do { \
|
||||
#define WPI_DEBUG(inst, format, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG1(inst, x) \
|
||||
do { \
|
||||
#define WPI_DEBUG1(inst, format, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG2(inst, x) \
|
||||
do { \
|
||||
#define WPI_DEBUG2(inst, format, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG3(inst, x) \
|
||||
do { \
|
||||
#define WPI_DEBUG3(inst, format, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG4(inst, x) \
|
||||
do { \
|
||||
#define WPI_DEBUG4(inst, format, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#else
|
||||
#define WPI_DEBUG(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, x)
|
||||
#define WPI_DEBUG1(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG1, x)
|
||||
#define WPI_DEBUG2(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG2, x)
|
||||
#define WPI_DEBUG3(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG3, x)
|
||||
#define WPI_DEBUG4(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG4, x)
|
||||
#define WPI_DEBUG(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, format, __VA_ARGS__)
|
||||
#define WPI_DEBUG1(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG1, format, __VA_ARGS__)
|
||||
#define WPI_DEBUG2(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG2, format, __VA_ARGS__)
|
||||
#define WPI_DEBUG3(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG3, format, __VA_ARGS__)
|
||||
#define WPI_DEBUG4(inst, format, ...) \
|
||||
WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG4, format, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#ifndef WPIUTIL_WPI_MIMETYPES_H_
|
||||
#define WPIUTIL_WPI_MIMETYPES_H_
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
StringRef MimeTypeFromPath(StringRef path);
|
||||
std::string_view MimeTypeFromPath(std::string_view path);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
//===- NativeFormatting.h - Low level formatting helpers ---------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_NATIVE_FORMATTING_H
|
||||
#define WPIUTIL_WPI_NATIVE_FORMATTING_H
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace wpi {
|
||||
enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent };
|
||||
enum class IntegerStyle {
|
||||
Integer,
|
||||
Number,
|
||||
};
|
||||
enum class HexPrintStyle { Upper, Lower, PrefixUpper, PrefixLower };
|
||||
|
||||
size_t getDefaultPrecision(FloatStyle Style);
|
||||
|
||||
bool isPrefixedHexStyle(HexPrintStyle S);
|
||||
|
||||
void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, int N, size_t MinDigits, IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
void write_integer(raw_ostream &S, long long N, size_t MinDigits,
|
||||
IntegerStyle Style);
|
||||
|
||||
void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
|
||||
std::optional<size_t> Width = std::nullopt);
|
||||
void write_double(raw_ostream &S, double D, FloatStyle Style,
|
||||
std::optional<size_t> Precision = std::nullopt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#define WPIUTIL_WPI_NETWORKSTREAM_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -28,7 +27,7 @@ class NetworkStream {
|
||||
int timeout = 0) = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual StringRef getPeerIP() const = 0;
|
||||
virtual std::string_view getPeerIP() const = 0;
|
||||
virtual int getPeerPort() const = 0;
|
||||
virtual void setNoDelay() = 0;
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -38,7 +37,8 @@ class PortForwarder {
|
||||
* @param remoteHost remote IP address / DNS name
|
||||
* @param remotePort remote port number
|
||||
*/
|
||||
void Add(unsigned int port, const Twine& remoteHost, unsigned int remotePort);
|
||||
void Add(unsigned int port, std::string_view remoteHost,
|
||||
unsigned int remotePort);
|
||||
|
||||
/**
|
||||
* Stop TCP forwarding on a port.
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
#define WPIUTIL_WPI_SMALLSTRING_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -28,8 +28,9 @@ public:
|
||||
/// Default ctor - Initialize to empty.
|
||||
SmallString() = default;
|
||||
|
||||
/// Initialize from a StringRef.
|
||||
SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
|
||||
/// Initialize from a std::string_view.
|
||||
SmallString(std::string_view S)
|
||||
: SmallVector<char, InternalLen>(S.begin(), S.end()) {}
|
||||
|
||||
/// Initialize with a range.
|
||||
template<typename ItTy>
|
||||
@@ -54,8 +55,8 @@ public:
|
||||
SmallVectorImpl<char>::append(S, E);
|
||||
}
|
||||
|
||||
/// Assign from a StringRef.
|
||||
void assign(StringRef RHS) {
|
||||
/// Assign from a std::string_view.
|
||||
void assign(std::string_view RHS) {
|
||||
this->clear();
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
@@ -80,8 +81,8 @@ public:
|
||||
SmallVectorImpl<char>::append(NumInputs, Elt);
|
||||
}
|
||||
|
||||
/// Append from a StringRef.
|
||||
void append(StringRef RHS) {
|
||||
/// Append from a std::string_view.
|
||||
void append(std::string_view RHS) {
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
@@ -94,48 +95,12 @@ public:
|
||||
/// @name String Comparison
|
||||
/// @{
|
||||
|
||||
/// Check for string equality. This is more efficient than compare() when
|
||||
/// the relative ordering of inequal strings isn't needed.
|
||||
bool equals(StringRef RHS) const {
|
||||
return str().equals(RHS);
|
||||
}
|
||||
|
||||
/// Check for string equality, ignoring case.
|
||||
bool equals_lower(StringRef RHS) const {
|
||||
return str().equals_lower(RHS);
|
||||
}
|
||||
|
||||
/// Compare two strings; the result is -1, 0, or 1 if this string is
|
||||
/// lexicographically less than, equal to, or greater than the \p RHS.
|
||||
int compare(StringRef RHS) const {
|
||||
int compare(std::string_view RHS) const {
|
||||
return str().compare(RHS);
|
||||
}
|
||||
|
||||
/// compare_lower - Compare two strings, ignoring case.
|
||||
int compare_lower(StringRef RHS) const {
|
||||
return str().compare_lower(RHS);
|
||||
}
|
||||
|
||||
/// compare_numeric - Compare two strings, treating sequences of digits as
|
||||
/// numbers.
|
||||
int compare_numeric(StringRef RHS) const {
|
||||
return str().compare_numeric(RHS);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Predicates
|
||||
/// @{
|
||||
|
||||
/// startswith - Check if this string starts with the given \p Prefix.
|
||||
bool startswith(StringRef Prefix) const {
|
||||
return str().startswith(Prefix);
|
||||
}
|
||||
|
||||
/// endswith - Check if this string ends with the given \p Suffix.
|
||||
bool endswith(StringRef Suffix) const {
|
||||
return str().endswith(Suffix);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Searching
|
||||
/// @{
|
||||
@@ -152,7 +117,7 @@ public:
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t find(StringRef Str, size_t From = 0) const {
|
||||
size_t find(std::string_view Str, size_t From = 0) const {
|
||||
return str().find(Str, From);
|
||||
}
|
||||
|
||||
@@ -160,7 +125,7 @@ public:
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t rfind(char C, size_t From = StringRef::npos) const {
|
||||
size_t rfind(char C, size_t From = std::string_view::npos) const {
|
||||
return str().rfind(C, From);
|
||||
}
|
||||
|
||||
@@ -168,7 +133,7 @@ public:
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t rfind(StringRef Str) const {
|
||||
size_t rfind(std::string_view Str) const {
|
||||
return str().rfind(Str);
|
||||
}
|
||||
|
||||
@@ -182,7 +147,7 @@ public:
|
||||
/// not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_of(StringRef Chars, size_t From = 0) const {
|
||||
size_t find_first_of(std::string_view Chars, size_t From = 0) const {
|
||||
return str().find_first_of(Chars, From);
|
||||
}
|
||||
|
||||
@@ -196,13 +161,13 @@ public:
|
||||
/// \p Chars, or npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_not_of(StringRef Chars, size_t From = 0) const {
|
||||
size_t find_first_not_of(std::string_view Chars, size_t From = 0) const {
|
||||
return str().find_first_not_of(Chars, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is \p C, or npos if not
|
||||
/// found.
|
||||
size_t find_last_of(char C, size_t From = StringRef::npos) const {
|
||||
size_t find_last_of(char C, size_t From = std::string_view::npos) const {
|
||||
return str().find_last_of(C, From);
|
||||
}
|
||||
|
||||
@@ -211,25 +176,10 @@ public:
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_last_of(
|
||||
StringRef Chars, size_t From = StringRef::npos) const {
|
||||
std::string_view Chars, size_t From = std::string_view::npos) const {
|
||||
return str().find_last_of(Chars, From);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Helpful Algorithms
|
||||
/// @{
|
||||
|
||||
/// Return the number of occurrences of \p C in the string.
|
||||
size_t count(char C) const {
|
||||
return str().count(C);
|
||||
}
|
||||
|
||||
/// Return the number of non-overlapped occurrences of \p Str in the
|
||||
/// string.
|
||||
size_t count(StringRef Str) const {
|
||||
return str().count(Str);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Substring Operations
|
||||
/// @{
|
||||
@@ -243,28 +193,17 @@ public:
|
||||
/// \param N The number of characters to included in the substring. If \p N
|
||||
/// exceeds the number of characters remaining in the string, the string
|
||||
/// suffix (starting with \p Start) will be returned.
|
||||
StringRef substr(size_t Start, size_t N = StringRef::npos) const {
|
||||
std::string_view substr(size_t Start, size_t N = std::string_view::npos) const {
|
||||
return str().substr(Start, N);
|
||||
}
|
||||
|
||||
/// Return a reference to the substring from [Start, End).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
/// the index is npos or greater than the length of the string then the
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param End The index following the last character to include in the
|
||||
/// substring. If this is npos, or less than \p Start, or exceeds the
|
||||
/// number of characters remaining in the string, the string suffix
|
||||
/// (starting with \p Start) will be returned.
|
||||
StringRef slice(size_t Start, size_t End) const {
|
||||
return str().slice(Start, End);
|
||||
}
|
||||
|
||||
// Extra methods.
|
||||
|
||||
/// Explicit conversion to StringRef.
|
||||
StringRef str() const { return StringRef(this->begin(), this->size()); }
|
||||
/// Explicit conversion to std::string_view.
|
||||
std::string_view str() const { return {this->begin(), this->size()}; }
|
||||
|
||||
/// Explicit conversion to std::string.
|
||||
std::string string() const { return {this->begin(), this->size()}; }
|
||||
|
||||
// TODO: Make this const, if it's safe...
|
||||
const char* c_str() {
|
||||
@@ -273,16 +212,19 @@ public:
|
||||
return this->data();
|
||||
}
|
||||
|
||||
/// Implicit conversion to StringRef.
|
||||
operator StringRef() const { return str(); }
|
||||
/// Implicit conversion to std::string_view.
|
||||
operator std::string_view() const { return str(); }
|
||||
|
||||
/// Implicit conversion to std::string.
|
||||
operator std::string() const { return string(); }
|
||||
|
||||
// Extra operators.
|
||||
const SmallString &operator=(StringRef RHS) {
|
||||
const SmallString &operator=(std::string_view RHS) {
|
||||
this->clear();
|
||||
return *this += RHS;
|
||||
}
|
||||
|
||||
SmallString &operator+=(StringRef RHS) {
|
||||
SmallString &operator+=(std::string_view RHS) {
|
||||
this->append(RHS.begin(), RHS.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#define WPIUTIL_WPI_STRINGMAP_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/iterator_range.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
@@ -29,6 +28,7 @@
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
@@ -82,12 +82,12 @@ protected:
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned LookupBucketFor(StringRef Key);
|
||||
unsigned LookupBucketFor(std::string_view Key);
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int FindKey(StringRef Key) const;
|
||||
int FindKey(std::string_view Key) const;
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
@@ -95,7 +95,7 @@ protected:
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *RemoveKey(StringRef Key);
|
||||
StringMapEntryBase *RemoveKey(std::string_view Key);
|
||||
|
||||
/// Allocate the table with the specified number of buckets and otherwise
|
||||
/// setup the map as empty.
|
||||
@@ -137,8 +137,8 @@ public:
|
||||
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
|
||||
StringMapEntry(StringMapEntry &E) = delete;
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), getKeyLength());
|
||||
std::string_view getKey() const {
|
||||
return {getKeyData(), getKeyLength()};
|
||||
}
|
||||
|
||||
const ValueTy &getValue() const { return second; }
|
||||
@@ -151,12 +151,12 @@ public:
|
||||
/// StringMapEntry object.
|
||||
const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);}
|
||||
|
||||
StringRef first() const { return StringRef(getKeyData(), getKeyLength()); }
|
||||
std::string_view first() const { return {getKeyData(), getKeyLength()}; }
|
||||
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename... InitTy>
|
||||
static StringMapEntry *Create(StringRef Key, InitTy &&... InitVals) {
|
||||
static StringMapEntry *Create(std::string_view Key, InitTy &&... InitVals) {
|
||||
size_t KeyLength = Key.size();
|
||||
|
||||
// Allocate a new item with space for the string at the end and a null
|
||||
@@ -177,7 +177,7 @@ public:
|
||||
return NewItem;
|
||||
}
|
||||
|
||||
static StringMapEntry *Create(StringRef Key) {
|
||||
static StringMapEntry *Create(std::string_view Key) {
|
||||
return Create(Key, ValueTy());
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ public:
|
||||
explicit StringMap(unsigned InitialSize)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
StringMap(std::initializer_list<std::pair<StringRef, ValueTy>> List)
|
||||
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
for (const auto &P : List) {
|
||||
insert(P);
|
||||
@@ -302,13 +302,13 @@ public:
|
||||
StringMapKeyIterator<ValueTy>(end()));
|
||||
}
|
||||
|
||||
iterator find(StringRef Key) {
|
||||
iterator find(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return end();
|
||||
return iterator(TheTable+Bucket, true);
|
||||
}
|
||||
|
||||
const_iterator find(StringRef Key) const {
|
||||
const_iterator find(std::string_view Key) const {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return end();
|
||||
return const_iterator(TheTable+Bucket, true);
|
||||
@@ -316,7 +316,7 @@ public:
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
ValueTy lookup(StringRef Key) const {
|
||||
ValueTy lookup(std::string_view Key) const {
|
||||
const_iterator it = find(Key);
|
||||
if (it != end())
|
||||
return it->second;
|
||||
@@ -325,10 +325,10 @@ public:
|
||||
|
||||
/// Lookup the ValueTy for the \p Key, or create a default constructed value
|
||||
/// if the key is not in the map.
|
||||
ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; }
|
||||
ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
size_type count(StringRef Key) const {
|
||||
size_type count(std::string_view Key) const {
|
||||
return find(Key) == end() ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ public:
|
||||
/// isn't already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {
|
||||
std::pair<iterator, bool> insert(std::pair<std::string_view, ValueTy> KV) {
|
||||
return try_emplace(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ public:
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
template <typename... ArgsTy>
|
||||
std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&... Args) {
|
||||
std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&... Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
@@ -411,7 +411,7 @@ public:
|
||||
V.Destroy();
|
||||
}
|
||||
|
||||
bool erase(StringRef Key) {
|
||||
bool erase(std::string_view Key) {
|
||||
iterator I = find(Key);
|
||||
if (I == end()) return false;
|
||||
erase(I);
|
||||
@@ -524,23 +524,23 @@ template <typename ValueTy>
|
||||
class StringMapKeyIterator
|
||||
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, StringRef> {
|
||||
std::forward_iterator_tag, std::string_view> {
|
||||
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, StringRef>;
|
||||
std::forward_iterator_tag, std::string_view>;
|
||||
|
||||
public:
|
||||
StringMapKeyIterator() = default;
|
||||
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
||||
: base(std::move(Iter)) {}
|
||||
|
||||
StringRef &operator*() {
|
||||
std::string_view &operator*() {
|
||||
Key = this->wrapped()->getKey();
|
||||
return Key;
|
||||
}
|
||||
|
||||
private:
|
||||
StringRef Key;
|
||||
std::string_view Key;
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
@@ -594,13 +594,13 @@ bool operator<(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
if (&lhs == &rhs) return false;
|
||||
|
||||
// copy into vectors and sort by key
|
||||
SmallVector<StringRef, 16> lhs_keys;
|
||||
SmallVector<std::string_view, 16> lhs_keys;
|
||||
lhs_keys.reserve(lhs.size());
|
||||
for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
lhs_keys.push_back(i->getKey());
|
||||
std::sort(lhs_keys.begin(), lhs_keys.end());
|
||||
|
||||
SmallVector<StringRef, 16> rhs_keys;
|
||||
SmallVector<std::string_view, 16> rhs_keys;
|
||||
rhs_keys.reserve(rhs.size());
|
||||
for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
rhs_keys.push_back(i->getKey());
|
||||
|
||||
@@ -1,956 +0,0 @@
|
||||
//===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STRINGREF_H
|
||||
#define WPIUTIL_WPI_STRINGREF_H
|
||||
|
||||
#include "wpi/STLExtras.h"
|
||||
#include "wpi/iterator_range.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class hash_code;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
class StringRef;
|
||||
|
||||
/// Helper functions for StringRef::getAsInteger.
|
||||
bool getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept;
|
||||
|
||||
bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result) noexcept;
|
||||
|
||||
bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept;
|
||||
bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result) noexcept;
|
||||
|
||||
/// StringRef - Represent a constant reference to a string, i.e. a character
|
||||
/// array and a length, which need not be null terminated.
|
||||
///
|
||||
/// This class does not own the string data, it is expected to be used in
|
||||
/// situations where the character data resides in some other buffer, whose
|
||||
/// lifetime extends past that of the StringRef. For this reason, it is not in
|
||||
/// general safe to store a StringRef.
|
||||
class StringRef {
|
||||
public:
|
||||
static const size_t npos = ~size_t(0);
|
||||
|
||||
using iterator = const char *;
|
||||
using const_iterator = const char *;
|
||||
using size_type = size_t;
|
||||
|
||||
private:
|
||||
/// The start of the string, in an external buffer.
|
||||
const char *Data = nullptr;
|
||||
|
||||
/// The length of the string.
|
||||
size_t Length = 0;
|
||||
|
||||
// Workaround memcmp issue with null pointers (undefined behavior)
|
||||
// by providing a specialized version
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) noexcept {
|
||||
if (Length == 0) { return 0; }
|
||||
return ::memcmp(Lhs,Rhs,Length);
|
||||
}
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
|
||||
/// Construct an empty string ref.
|
||||
/*implicit*/ StringRef() = default;
|
||||
|
||||
/// Disable conversion from nullptr. This prevents things like
|
||||
/// if (S == nullptr)
|
||||
StringRef(std::nullptr_t) = delete;
|
||||
|
||||
/// Construct a string ref from a cstring.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
/*implicit*/ StringRef(const char *Str) noexcept
|
||||
: Data(Str), Length(Str ? ::strlen(Str) : 0) {}
|
||||
|
||||
/// Construct a string ref from a pointer and length.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
/*implicit*/ constexpr StringRef(const char *data, size_t length) noexcept
|
||||
: Data(data), Length(length) {}
|
||||
|
||||
/// Construct a string ref from an std::string.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
/*implicit*/ StringRef(const std::string &Str) noexcept
|
||||
: Data(Str.data()), Length(Str.length()) {}
|
||||
|
||||
/// Construct a string ref from an std::string_view.
|
||||
/*implicit*/ constexpr StringRef(std::string_view Str)
|
||||
: Data(Str.data()), Length(Str.size()) {}
|
||||
|
||||
static StringRef withNullAsEmpty(const char *data) noexcept {
|
||||
return StringRef(data ? data : "");
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Iterators
|
||||
/// @{
|
||||
|
||||
iterator begin() const noexcept { return Data; }
|
||||
|
||||
iterator end() const noexcept { return Data + Length; }
|
||||
|
||||
const unsigned char *bytes_begin() const noexcept {
|
||||
return reinterpret_cast<const unsigned char *>(begin());
|
||||
}
|
||||
const unsigned char *bytes_end() const noexcept {
|
||||
return reinterpret_cast<const unsigned char *>(end());
|
||||
}
|
||||
iterator_range<const unsigned char *> bytes() const noexcept {
|
||||
return make_range(bytes_begin(), bytes_end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Operations
|
||||
/// @{
|
||||
|
||||
/// data - Get a pointer to the start of the string (which may not be null
|
||||
/// terminated).
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
const char *data() const noexcept { return Data; }
|
||||
|
||||
/// empty - Check if the string is empty.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool empty() const noexcept { return Length == 0; }
|
||||
|
||||
/// size - Get the string size.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t size() const noexcept { return Length; }
|
||||
|
||||
/// front - Get the first character in the string.
|
||||
LLVM_NODISCARD
|
||||
char front() const noexcept {
|
||||
assert(!empty());
|
||||
return Data[0];
|
||||
}
|
||||
|
||||
/// back - Get the last character in the string.
|
||||
LLVM_NODISCARD
|
||||
char back() const noexcept {
|
||||
assert(!empty());
|
||||
return Data[Length-1];
|
||||
}
|
||||
|
||||
// copy - Allocate copy in Allocator and return StringRef to it.
|
||||
template <typename Allocator>
|
||||
LLVM_NODISCARD StringRef copy(Allocator &A) const {
|
||||
// Don't request a length 0 copy from the allocator.
|
||||
if (empty())
|
||||
return StringRef();
|
||||
char *S = A.template Allocate<char>(Length);
|
||||
std::copy(begin(), end(), S);
|
||||
return StringRef(S, Length);
|
||||
}
|
||||
|
||||
/// equals - Check for string equality, this is more efficient than
|
||||
/// compare() when the relative ordering of inequal strings isn't needed.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool equals(StringRef RHS) const noexcept {
|
||||
return (Length == RHS.Length &&
|
||||
compareMemory(Data, RHS.Data, RHS.Length) == 0);
|
||||
}
|
||||
|
||||
/// equals_lower - Check for string equality, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
bool equals_lower(StringRef RHS) const noexcept {
|
||||
return Length == RHS.Length && compare_lower(RHS) == 0;
|
||||
}
|
||||
|
||||
/// compare - Compare two strings; the result is -1, 0, or 1 if this string
|
||||
/// is lexicographically less than, equal to, or greater than the \p RHS.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
int compare(StringRef RHS) const noexcept {
|
||||
// Check the prefix for a mismatch.
|
||||
if (int Res = compareMemory(Data, RHS.Data, (std::min)(Length, RHS.Length)))
|
||||
return Res < 0 ? -1 : 1;
|
||||
|
||||
// Otherwise the prefixes match, so we only need to check the lengths.
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
/// compare_lower - Compare two strings, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
int compare_lower(StringRef RHS) const noexcept;
|
||||
|
||||
/// compare_numeric - Compare two strings, treating sequences of digits as
|
||||
/// numbers.
|
||||
LLVM_NODISCARD
|
||||
int compare_numeric(StringRef RHS) const noexcept;
|
||||
|
||||
/// str - Get the contents as an std::string.
|
||||
LLVM_NODISCARD
|
||||
std::string str() const {
|
||||
if (!Data) return std::string();
|
||||
return std::string(Data, Length);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
|
||||
LLVM_NODISCARD
|
||||
char operator[](size_t Index) const noexcept {
|
||||
assert(Index < Length && "Invalid index!");
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
/// Disallow accidental assignment from a temporary std::string.
|
||||
///
|
||||
/// The declaration here is extra complicated so that `stringRef = {}`
|
||||
/// and `stringRef = "abc"` continue to select the move assignment operator.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_same<T, std::string>::value,
|
||||
StringRef>::type &
|
||||
operator=(T &&Str) = delete;
|
||||
|
||||
/// @}
|
||||
/// @name Type Conversions
|
||||
/// @{
|
||||
|
||||
operator std::string() const {
|
||||
return str();
|
||||
}
|
||||
|
||||
operator std::string_view() const {
|
||||
return std::string_view(data(), size());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Predicates
|
||||
/// @{
|
||||
|
||||
/// Check if this string starts with the given \p Prefix.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool startswith(StringRef Prefix) const noexcept {
|
||||
return Length >= Prefix.Length &&
|
||||
compareMemory(Data, Prefix.Data, Prefix.Length) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string starts with the given \p Prefix, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
bool startswith_lower(StringRef Prefix) const noexcept;
|
||||
|
||||
/// Check if this string ends with the given \p Suffix.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool endswith(StringRef Suffix) const noexcept {
|
||||
return Length >= Suffix.Length &&
|
||||
compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string ends with the given \p Suffix, ignoring case.
|
||||
LLVM_NODISCARD
|
||||
bool endswith_lower(StringRef Suffix) const noexcept;
|
||||
|
||||
/// @}
|
||||
/// @name String Searching
|
||||
/// @{
|
||||
|
||||
/// Search for the first character \p C in the string.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t find(char C, size_t From = 0) const noexcept {
|
||||
size_t FindBegin = (std::min)(From, Length);
|
||||
if (FindBegin < Length) { // Avoid calling memchr with nullptr.
|
||||
// Just forward to memchr, which is faster than a hand-rolled loop.
|
||||
if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin))
|
||||
return static_cast<const char *>(P) - Data;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the first character \p C in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_lower(char C, size_t From = 0) const noexcept;
|
||||
|
||||
/// Search for the first character satisfying the predicate \p F
|
||||
///
|
||||
/// \returns The index of the first character satisfying \p F starting from
|
||||
/// \p From, or npos if not found.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t find_if(function_ref<bool(char)> F, size_t From = 0) const noexcept {
|
||||
StringRef S = drop_front(From);
|
||||
while (!S.empty()) {
|
||||
if (F(S.front()))
|
||||
return size() - S.size();
|
||||
S = S.drop_front();
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the first character not satisfying the predicate \p F
|
||||
///
|
||||
/// \returns The index of the first character not satisfying \p F starting
|
||||
/// from \p From, or npos if not found.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
size_t find_if_not(function_ref<bool(char)> F, size_t From = 0) const noexcept {
|
||||
return find_if([F](char c) { return !F(c); }, From);
|
||||
}
|
||||
|
||||
/// Search for the first string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find(StringRef Str, size_t From = 0) const noexcept;
|
||||
|
||||
/// Search for the first string \p Str in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_lower(StringRef Str, size_t From = 0) const noexcept;
|
||||
|
||||
/// Search for the last character \p C in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind(char C, size_t From = npos) const noexcept {
|
||||
From = (std::min)(From, Length);
|
||||
size_t i = From;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
if (Data[i] == C)
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// Search for the last character \p C in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind_lower(char C, size_t From = npos) const noexcept;
|
||||
|
||||
/// Search for the last string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind(StringRef Str) const noexcept;
|
||||
|
||||
/// Search for the last string \p Str in the string, ignoring case.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t rfind_lower(StringRef Str) const noexcept;
|
||||
|
||||
/// Find the first character in the string that is \p C, or npos if not
|
||||
/// found. Same as find.
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_of(char C, size_t From = 0) const noexcept {
|
||||
return find(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is in \p Chars, or npos if
|
||||
/// not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_of(StringRef Chars, size_t From = 0) const noexcept;
|
||||
|
||||
/// Find the first character in the string that is not \p C or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_not_of(char C, size_t From = 0) const noexcept;
|
||||
|
||||
/// Find the first character in the string that is not in the string
|
||||
/// \p Chars, or npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
LLVM_NODISCARD
|
||||
size_t find_first_not_of(StringRef Chars, size_t From = 0) const noexcept;
|
||||
|
||||
/// Find the last character in the string that is \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_of(char C, size_t From = npos) const noexcept {
|
||||
return rfind(C, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is in \p C, or npos if not
|
||||
/// found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_of(StringRef Chars, size_t From = npos) const noexcept;
|
||||
|
||||
/// Find the last character in the string that is not \p C, or npos if not
|
||||
/// found.
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_not_of(char C, size_t From = npos) const noexcept;
|
||||
|
||||
/// Find the last character in the string that is not in \p Chars, or
|
||||
/// npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
LLVM_NODISCARD
|
||||
size_t find_last_not_of(StringRef Chars, size_t From = npos) const noexcept;
|
||||
|
||||
/// Return true if the given string is a substring of *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains(StringRef Other) const noexcept { return find(Other) != npos; }
|
||||
|
||||
/// Return true if the given character is contained in *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains(char C) const noexcept { return find_first_of(C) != npos; }
|
||||
|
||||
/// Return true if the given string is a substring of *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains_lower(StringRef Other) const noexcept {
|
||||
return find_lower(Other) != npos;
|
||||
}
|
||||
|
||||
/// Return true if the given character is contained in *this, and false
|
||||
/// otherwise.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool contains_lower(char C) const noexcept { return find_lower(C) != npos; }
|
||||
|
||||
/// @}
|
||||
/// @name Helpful Algorithms
|
||||
/// @{
|
||||
|
||||
/// Return the number of occurrences of \p C in the string.
|
||||
LLVM_NODISCARD
|
||||
size_t count(char C) const noexcept {
|
||||
size_t Count = 0;
|
||||
for (size_t i = 0, e = Length; i != e; ++i)
|
||||
if (Data[i] == C)
|
||||
++Count;
|
||||
return Count;
|
||||
}
|
||||
|
||||
/// Return the number of non-overlapped occurrences of \p Str in
|
||||
/// the string.
|
||||
size_t count(StringRef Str) const noexcept;
|
||||
|
||||
/// Parse the current string as an integer of the specified radix. If
|
||||
/// \p Radix is specified as zero, this does radix autosensing using
|
||||
/// extended C rules: 0 is octal, 0x is hex, 0b is binary.
|
||||
///
|
||||
/// If the string is invalid or if only a subset of the string is valid,
|
||||
/// this returns true to signify the error. The string is considered
|
||||
/// erroneous if empty or if it overflows T.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
|
||||
getAsInteger(unsigned Radix, T &Result) const noexcept {
|
||||
long long LLVal;
|
||||
if (getAsSignedInteger(*this, Radix, LLVal) ||
|
||||
static_cast<T>(LLVal) != LLVal)
|
||||
return true;
|
||||
Result = LLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
|
||||
getAsInteger(unsigned Radix, T &Result) const noexcept {
|
||||
unsigned long long ULLVal;
|
||||
// The additional cast to unsigned long long is required to avoid the
|
||||
// Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type
|
||||
// 'unsigned __int64' when instantiating getAsInteger with T = bool.
|
||||
if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
|
||||
static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
|
||||
return true;
|
||||
Result = ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Parse the current string as an integer of the specified radix. If
|
||||
/// \p Radix is specified as zero, this does radix autosensing using
|
||||
/// extended C rules: 0 is octal, 0x is hex, 0b is binary.
|
||||
///
|
||||
/// If the string does not begin with a number of the specified radix,
|
||||
/// this returns true to signify the error. The string is considered
|
||||
/// erroneous if empty or if it overflows T.
|
||||
/// The portion of the string representing the discovered numeric value
|
||||
/// is removed from the beginning of the string.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
|
||||
consumeInteger(unsigned Radix, T &Result) noexcept {
|
||||
long long LLVal;
|
||||
if (consumeSignedInteger(*this, Radix, LLVal) ||
|
||||
static_cast<long long>(static_cast<T>(LLVal)) != LLVal)
|
||||
return true;
|
||||
Result = LLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
|
||||
consumeInteger(unsigned Radix, T &Result) noexcept {
|
||||
unsigned long long ULLVal;
|
||||
if (consumeUnsignedInteger(*this, Radix, ULLVal) ||
|
||||
static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
|
||||
return true;
|
||||
Result = ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Operations
|
||||
/// @{
|
||||
|
||||
// Convert the given ASCII string to lowercase.
|
||||
LLVM_NODISCARD
|
||||
std::string lower() const;
|
||||
|
||||
/// Convert the given ASCII string to uppercase.
|
||||
LLVM_NODISCARD
|
||||
std::string upper() const;
|
||||
|
||||
/// @}
|
||||
/// @name Substring Operations
|
||||
/// @{
|
||||
|
||||
/// Return a reference to the substring from [Start, Start + N).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
/// the index is npos or greater than the length of the string then the
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param N The number of characters to included in the substring. If N
|
||||
/// exceeds the number of characters remaining in the string, the string
|
||||
/// suffix (starting with \p Start) will be returned.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef substr(size_t Start, size_t N = npos) const noexcept {
|
||||
Start = (std::min)(Start, Length);
|
||||
return StringRef(Data + Start, (std::min)(N, Length - Start));
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with only the first \p N
|
||||
/// elements remaining. If \p N is greater than the length of the
|
||||
/// string, the entire string is returned.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_front(size_t N = 1) const noexcept {
|
||||
if (N >= size())
|
||||
return *this;
|
||||
return drop_back(size() - N);
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with only the last \p N
|
||||
/// elements remaining. If \p N is greater than the length of the
|
||||
/// string, the entire string is returned.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_back(size_t N = 1) const noexcept {
|
||||
if (N >= size())
|
||||
return *this;
|
||||
return drop_front(size() - N);
|
||||
}
|
||||
|
||||
/// Return the longest prefix of 'this' such that every character
|
||||
/// in the prefix satisfies the given predicate.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_while(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(0, find_if_not(F));
|
||||
}
|
||||
|
||||
/// Return the longest prefix of 'this' such that no character in
|
||||
/// the prefix satisfies the given predicate.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef take_until(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(0, find_if(F));
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with the first \p N elements
|
||||
/// dropped.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_front(size_t N = 1) const noexcept {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return substr(N);
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with the last \p N elements
|
||||
/// dropped.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_back(size_t N = 1) const noexcept {
|
||||
assert(size() >= N && "Dropping more elements than exist");
|
||||
return substr(0, size()-N);
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this', but with all characters satisfying
|
||||
/// the given predicate dropped from the beginning of the string.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_while(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(find_if_not(F));
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this', but with all characters not
|
||||
/// satisfying the given predicate dropped from the beginning of the string.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef drop_until(function_ref<bool(char)> F) const noexcept {
|
||||
return substr(find_if(F));
|
||||
}
|
||||
|
||||
/// Returns true if this StringRef has the given prefix and removes that
|
||||
/// prefix.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool consume_front(StringRef Prefix) noexcept {
|
||||
if (!startswith(Prefix))
|
||||
return false;
|
||||
|
||||
*this = drop_front(Prefix.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true if this StringRef has the given suffix and removes that
|
||||
/// suffix.
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool consume_back(StringRef Suffix) noexcept {
|
||||
if (!endswith(Suffix))
|
||||
return false;
|
||||
|
||||
*this = drop_back(Suffix.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return a reference to the substring from [Start, End).
|
||||
///
|
||||
/// \param Start The index of the starting character in the substring; if
|
||||
/// the index is npos or greater than the length of the string then the
|
||||
/// empty substring will be returned.
|
||||
///
|
||||
/// \param End The index following the last character to include in the
|
||||
/// substring. If this is npos or exceeds the number of characters
|
||||
/// remaining in the string, the string suffix (starting with \p Start)
|
||||
/// will be returned. If this is less than \p Start, an empty string will
|
||||
/// be returned.
|
||||
LLVM_NODISCARD
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
StringRef slice(size_t Start, size_t End) const noexcept {
|
||||
Start = (std::min)(Start, Length);
|
||||
End = (std::min)((std::max)(Start, End), Length);
|
||||
return StringRef(Data + Start, End - Start);
|
||||
}
|
||||
|
||||
/// Split into two substrings around the first occurrence of a separator
|
||||
/// character.
|
||||
///
|
||||
/// If \p Separator is in the string, then the result is a pair (LHS, RHS)
|
||||
/// such that (*this == LHS + Separator + RHS) is true and RHS is
|
||||
/// maximal. If \p Separator is not in the string, then the result is a
|
||||
/// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
|
||||
///
|
||||
/// \param Separator The character to split on.
|
||||
/// \returns The split substrings.
|
||||
LLVM_NODISCARD
|
||||
std::pair<StringRef, StringRef> split(char Separator) const {
|
||||
return split(StringRef(&Separator, 1));
|
||||
}
|
||||
|
||||
/// Split into two substrings around the first occurrence of a separator
|
||||
/// string.
|
||||
///
|
||||
/// If \p Separator is in the string, then the result is a pair (LHS, RHS)
|
||||
/// such that (*this == LHS + Separator + RHS) is true and RHS is
|
||||
/// maximal. If \p Separator is not in the string, then the result is a
|
||||
/// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
|
||||
///
|
||||
/// \param Separator - The string to split on.
|
||||
/// \return - The split substrings.
|
||||
LLVM_NODISCARD
|
||||
std::pair<StringRef, StringRef> split(StringRef Separator) const {
|
||||
size_t Idx = find(Separator);
|
||||
if (Idx == npos)
|
||||
return std::make_pair(*this, StringRef());
|
||||
return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos));
|
||||
}
|
||||
|
||||
/// Split into two substrings around the last occurrence of a separator
|
||||
/// string.
|
||||
///
|
||||
/// If \p Separator is in the string, then the result is a pair (LHS, RHS)
|
||||
/// such that (*this == LHS + Separator + RHS) is true and RHS is
|
||||
/// minimal. If \p Separator is not in the string, then the result is a
|
||||
/// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
|
||||
///
|
||||
/// \param Separator - The string to split on.
|
||||
/// \return - The split substrings.
|
||||
LLVM_NODISCARD
|
||||
std::pair<StringRef, StringRef> rsplit(StringRef Separator) const {
|
||||
size_t Idx = rfind(Separator);
|
||||
if (Idx == npos)
|
||||
return std::make_pair(*this, StringRef());
|
||||
return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos));
|
||||
}
|
||||
|
||||
/// Split into substrings around the occurrences of a separator string.
|
||||
///
|
||||
/// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
|
||||
/// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
|
||||
/// elements are added to A.
|
||||
/// If \p KeepEmpty is false, empty strings are not added to \p A. They
|
||||
/// still count when considering \p MaxSplit
|
||||
/// An useful invariant is that
|
||||
/// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true
|
||||
///
|
||||
/// \param A - Where to put the substrings.
|
||||
/// \param Separator - The string to split on.
|
||||
/// \param MaxSplit - The maximum number of times the string is split.
|
||||
/// \param KeepEmpty - True if empty substring should be added.
|
||||
void split(SmallVectorImpl<StringRef> &A,
|
||||
StringRef Separator, int MaxSplit = -1,
|
||||
bool KeepEmpty = true) const;
|
||||
|
||||
/// Split into substrings around the occurrences of a separator character.
|
||||
///
|
||||
/// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
|
||||
/// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
|
||||
/// elements are added to A.
|
||||
/// If \p KeepEmpty is false, empty strings are not added to \p A. They
|
||||
/// still count when considering \p MaxSplit
|
||||
/// An useful invariant is that
|
||||
/// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true
|
||||
///
|
||||
/// \param A - Where to put the substrings.
|
||||
/// \param Separator - The string to split on.
|
||||
/// \param MaxSplit - The maximum number of times the string is split.
|
||||
/// \param KeepEmpty - True if empty substring should be added.
|
||||
void split(SmallVectorImpl<StringRef> &A, char Separator, int MaxSplit = -1,
|
||||
bool KeepEmpty = true) const;
|
||||
|
||||
/// Split into two substrings around the last occurrence of a separator
|
||||
/// character.
|
||||
///
|
||||
/// If \p Separator is in the string, then the result is a pair (LHS, RHS)
|
||||
/// such that (*this == LHS + Separator + RHS) is true and RHS is
|
||||
/// minimal. If \p Separator is not in the string, then the result is a
|
||||
/// pair (LHS, RHS) where (*this == LHS) and (RHS == "").
|
||||
///
|
||||
/// \param Separator - The character to split on.
|
||||
/// \return - The split substrings.
|
||||
LLVM_NODISCARD
|
||||
std::pair<StringRef, StringRef> rsplit(char Separator) const {
|
||||
return rsplit(StringRef(&Separator, 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// the left removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef ltrim(char Char) const noexcept {
|
||||
return drop_front((std::min)(Length, find_first_not_of(Char)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const noexcept {
|
||||
return drop_front((std::min)(Length, find_first_not_of(Chars)));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef rtrim(char Char) const noexcept {
|
||||
return drop_back(size() - (std::min)(Length, find_last_not_of(Char) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const noexcept {
|
||||
return drop_back(size() - (std::min)(Length, find_last_not_of(Chars) + 1));
|
||||
}
|
||||
|
||||
/// Return string with consecutive \p Char characters starting from the
|
||||
/// left and right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef trim(char Char) const noexcept {
|
||||
return ltrim(Char).rtrim(Char);
|
||||
}
|
||||
|
||||
/// Return string with consecutive characters in \p Chars starting from
|
||||
/// the left and right removed.
|
||||
LLVM_NODISCARD
|
||||
StringRef trim(StringRef Chars = " \t\n\v\f\r") const noexcept {
|
||||
return ltrim(Chars).rtrim(Chars);
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// A wrapper around a string literal that serves as a proxy for constructing
|
||||
/// global tables of StringRefs with the length computed at compile time.
|
||||
/// In order to avoid the invocation of a global constructor, StringLiteral
|
||||
/// should *only* be used in a constexpr context, as such:
|
||||
///
|
||||
/// constexpr StringLiteral S("test");
|
||||
///
|
||||
class StringLiteral : public StringRef {
|
||||
private:
|
||||
constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) {
|
||||
}
|
||||
|
||||
public:
|
||||
template <size_t N>
|
||||
constexpr StringLiteral(const char (&Str)[N])
|
||||
#if defined(__clang__) && __has_attribute(enable_if)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||
__attribute((enable_if(__builtin_strlen(Str) == N - 1,
|
||||
"invalid string literal")))
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
: StringRef(Str, N - 1) {
|
||||
}
|
||||
|
||||
// Explicit construction for strings like "foo\0bar".
|
||||
template <size_t N>
|
||||
static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) {
|
||||
return StringLiteral(Str, N - 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// @name StringRef Comparison Operators
|
||||
/// @{
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool operator==(StringRef LHS, StringRef RHS) noexcept {
|
||||
return LHS.equals(RHS);
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
bool operator!=(StringRef LHS, StringRef RHS) noexcept {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
inline bool operator<(StringRef LHS, StringRef RHS) noexcept {
|
||||
return LHS.compare(RHS) == -1;
|
||||
}
|
||||
|
||||
inline bool operator<=(StringRef LHS, StringRef RHS) noexcept {
|
||||
return LHS.compare(RHS) != 1;
|
||||
}
|
||||
|
||||
inline bool operator>(StringRef LHS, StringRef RHS) noexcept {
|
||||
return LHS.compare(RHS) == 1;
|
||||
}
|
||||
|
||||
inline bool operator>=(StringRef LHS, StringRef RHS) noexcept {
|
||||
return LHS.compare(RHS) != -1;
|
||||
}
|
||||
|
||||
inline bool operator==(StringRef LHS, const char *RHS) noexcept {
|
||||
return LHS.equals(StringRef(RHS));
|
||||
}
|
||||
|
||||
inline bool operator!=(StringRef LHS, const char *RHS) noexcept {
|
||||
return !(LHS == StringRef(RHS));
|
||||
}
|
||||
|
||||
inline bool operator<(StringRef LHS, const char *RHS) noexcept {
|
||||
return LHS.compare(StringRef(RHS)) == -1;
|
||||
}
|
||||
|
||||
inline bool operator<=(StringRef LHS, const char *RHS) noexcept {
|
||||
return LHS.compare(StringRef(RHS)) != 1;
|
||||
}
|
||||
|
||||
inline bool operator>(StringRef LHS, const char *RHS) noexcept {
|
||||
return LHS.compare(StringRef(RHS)) == 1;
|
||||
}
|
||||
|
||||
inline bool operator>=(StringRef LHS, const char *RHS) noexcept {
|
||||
return LHS.compare(StringRef(RHS)) != -1;
|
||||
}
|
||||
|
||||
inline bool operator==(const char *LHS, StringRef RHS) noexcept {
|
||||
return StringRef(LHS).equals(RHS);
|
||||
}
|
||||
|
||||
inline bool operator!=(const char *LHS, StringRef RHS) noexcept {
|
||||
return !(StringRef(LHS) == RHS);
|
||||
}
|
||||
|
||||
inline bool operator<(const char *LHS, StringRef RHS) noexcept {
|
||||
return StringRef(LHS).compare(RHS) == -1;
|
||||
}
|
||||
|
||||
inline bool operator<=(const char *LHS, StringRef RHS) noexcept {
|
||||
return StringRef(LHS).compare(RHS) != 1;
|
||||
}
|
||||
|
||||
inline bool operator>(const char *LHS, StringRef RHS) noexcept {
|
||||
return StringRef(LHS).compare(RHS) == 1;
|
||||
}
|
||||
|
||||
inline bool operator>=(const char *LHS, StringRef RHS) noexcept {
|
||||
return StringRef(LHS).compare(RHS) != -1;
|
||||
}
|
||||
|
||||
inline std::string &operator+=(std::string &buffer, StringRef string) {
|
||||
return buffer.append(string.data(), string.size());
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, StringRef string);
|
||||
|
||||
/// @}
|
||||
|
||||
/// Compute a hash_code for a StringRef.
|
||||
LLVM_NODISCARD
|
||||
hash_code hash_value(StringRef S);
|
||||
|
||||
// StringRefs can be treated like a POD type.
|
||||
template <typename T> struct isPodLike;
|
||||
template <> struct isPodLike<StringRef> { static const bool value = true; };
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // LLVM_ADT_STRINGREF_H
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/NetworkAcceptor.h"
|
||||
#include "wpi/TCPStream.h"
|
||||
@@ -44,7 +45,7 @@ class TCPAcceptor : public NetworkAcceptor {
|
||||
Logger& m_logger;
|
||||
|
||||
public:
|
||||
TCPAcceptor(int port, const char* address, Logger& logger);
|
||||
TCPAcceptor(int port, std::string_view address, Logger& logger);
|
||||
~TCPAcceptor() override;
|
||||
|
||||
int start() override;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/NetworkStream.h"
|
||||
|
||||
@@ -50,7 +51,7 @@ class TCPStream : public NetworkStream {
|
||||
int timeout = 0) override;
|
||||
void close() final;
|
||||
|
||||
StringRef getPeerIP() const override;
|
||||
std::string_view getPeerIP() const override;
|
||||
int getPeerPort() const override;
|
||||
void setNoDelay() override;
|
||||
bool setBlocking(bool enabled) override;
|
||||
|
||||
@@ -1,572 +0,0 @@
|
||||
//===- Twine.h - Fast Temporary String Concatenation ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_TWINE_H
|
||||
#define WPIUTIL_WPI_TWINE_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26495)
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
/// Twine - A lightweight data structure for efficiently representing the
|
||||
/// concatenation of temporary values as strings.
|
||||
///
|
||||
/// A Twine is a kind of rope, it represents a concatenated string using a
|
||||
/// binary-tree, where the string is the preorder of the nodes. Since the
|
||||
/// Twine can be efficiently rendered into a buffer when its result is used,
|
||||
/// it avoids the cost of generating temporary values for intermediate string
|
||||
/// results -- particularly in cases when the Twine result is never
|
||||
/// required. By explicitly tracking the type of leaf nodes, we can also avoid
|
||||
/// the creation of temporary strings for conversions operations (such as
|
||||
/// appending an integer to a string).
|
||||
///
|
||||
/// A Twine is not intended for use directly and should not be stored, its
|
||||
/// implementation relies on the ability to store pointers to temporary stack
|
||||
/// objects which may be deallocated at the end of a statement. Twines should
|
||||
/// only be used accepted as const references in arguments, when an API wishes
|
||||
/// to accept possibly-concatenated strings.
|
||||
///
|
||||
/// Twines support a special 'null' value, which always concatenates to form
|
||||
/// itself, and renders as an empty string. This can be returned from APIs to
|
||||
/// effectively nullify any concatenations performed on the result.
|
||||
///
|
||||
/// \b Implementation
|
||||
///
|
||||
/// Given the nature of a Twine, it is not possible for the Twine's
|
||||
/// concatenation method to construct interior nodes; the result must be
|
||||
/// represented inside the returned value. For this reason a Twine object
|
||||
/// actually holds two values, the left- and right-hand sides of a
|
||||
/// concatenation. We also have nullary Twine objects, which are effectively
|
||||
/// sentinel values that represent empty strings.
|
||||
///
|
||||
/// Thus, a Twine can effectively have zero, one, or two children. The \see
|
||||
/// isNullary(), \see isUnary(), and \see isBinary() predicates exist for
|
||||
/// testing the number of children.
|
||||
///
|
||||
/// We maintain a number of invariants on Twine objects (FIXME: Why):
|
||||
/// - Nullary twines are always represented with their Kind on the left-hand
|
||||
/// side, and the Empty kind on the right-hand side.
|
||||
/// - Unary twines are always represented with the value on the left-hand
|
||||
/// side, and the Empty kind on the right-hand side.
|
||||
/// - If a Twine has another Twine as a child, that child should always be
|
||||
/// binary (otherwise it could have been folded into the parent).
|
||||
///
|
||||
/// These invariants are check by \see isValid().
|
||||
///
|
||||
/// \b Efficiency Considerations
|
||||
///
|
||||
/// The Twine is designed to yield efficient and small code for common
|
||||
/// situations. For this reason, the concat() method is inlined so that
|
||||
/// concatenations of leaf nodes can be optimized into stores directly into a
|
||||
/// single stack allocated object.
|
||||
///
|
||||
/// In practice, not all compilers can be trusted to optimize concat() fully,
|
||||
/// so we provide two additional methods (and accompanying operator+
|
||||
/// overloads) to guarantee that particularly important cases (cstring plus
|
||||
/// StringRef) codegen as desired.
|
||||
class Twine {
|
||||
/// NodeKind - Represent the type of an argument.
|
||||
enum NodeKind : unsigned char {
|
||||
/// An empty string; the result of concatenating anything with it is also
|
||||
/// empty.
|
||||
NullKind,
|
||||
|
||||
/// The empty string.
|
||||
EmptyKind,
|
||||
|
||||
/// A pointer to a Twine instance.
|
||||
TwineKind,
|
||||
|
||||
/// A pointer to a C string instance.
|
||||
CStringKind,
|
||||
|
||||
/// A pointer to an std::string instance.
|
||||
StdStringKind,
|
||||
|
||||
/// A pointer to a StringRef instance.
|
||||
StringRefKind,
|
||||
|
||||
/// A pointer to a std::string_view instance.
|
||||
StringViewKind,
|
||||
|
||||
/// A pointer to a SmallString instance.
|
||||
SmallStringKind,
|
||||
|
||||
/// A char value, to render as a character.
|
||||
CharKind,
|
||||
|
||||
/// An unsigned int value, to render as an unsigned decimal integer.
|
||||
DecUIKind,
|
||||
|
||||
/// An int value, to render as a signed decimal integer.
|
||||
DecIKind,
|
||||
|
||||
/// A pointer to an unsigned long value, to render as an unsigned decimal
|
||||
/// integer.
|
||||
DecULKind,
|
||||
|
||||
/// A pointer to a long value, to render as a signed decimal integer.
|
||||
DecLKind,
|
||||
|
||||
/// A pointer to an unsigned long long value, to render as an unsigned
|
||||
/// decimal integer.
|
||||
DecULLKind,
|
||||
|
||||
/// A pointer to a long long value, to render as a signed decimal integer.
|
||||
DecLLKind,
|
||||
|
||||
/// A pointer to a uint64_t value, to render as an unsigned hexadecimal
|
||||
/// integer.
|
||||
UHexKind
|
||||
};
|
||||
|
||||
union Child
|
||||
{
|
||||
const Twine *twine;
|
||||
const char *cString;
|
||||
const std::string *stdString;
|
||||
const StringRef *stringRef;
|
||||
const std::string_view *stringView;
|
||||
const SmallVectorImpl<char> *smallString;
|
||||
char character;
|
||||
unsigned int decUI;
|
||||
int decI;
|
||||
const unsigned long *decUL;
|
||||
const long *decL;
|
||||
const unsigned long long *decULL;
|
||||
const long long *decLL;
|
||||
const uint64_t *uHex;
|
||||
};
|
||||
|
||||
/// LHS - The prefix in the concatenation, which may be uninitialized for
|
||||
/// Null or Empty kinds.
|
||||
Child LHS;
|
||||
|
||||
/// RHS - The suffix in the concatenation, which may be uninitialized for
|
||||
/// Null or Empty kinds.
|
||||
Child RHS;
|
||||
|
||||
/// LHSKind - The NodeKind of the left hand side, \see getLHSKind().
|
||||
NodeKind LHSKind = EmptyKind;
|
||||
|
||||
/// RHSKind - The NodeKind of the right hand side, \see getRHSKind().
|
||||
NodeKind RHSKind = EmptyKind;
|
||||
|
||||
/// Construct a nullary twine; the kind must be NullKind or EmptyKind.
|
||||
explicit Twine(NodeKind Kind) : LHSKind(Kind) {
|
||||
assert(isNullary() && "Invalid kind!");
|
||||
}
|
||||
|
||||
/// Construct a binary twine.
|
||||
explicit Twine(const Twine &LHS, const Twine &RHS)
|
||||
: LHSKind(TwineKind), RHSKind(TwineKind) {
|
||||
this->LHS.twine = &LHS;
|
||||
this->RHS.twine = &RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct a twine from explicit values.
|
||||
explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind)
|
||||
: LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Check for the empty twine.
|
||||
bool isEmpty() const {
|
||||
return getLHSKind() == EmptyKind;
|
||||
}
|
||||
|
||||
/// Check if this is a nullary twine (null or empty).
|
||||
bool isNullary() const {
|
||||
return isNull() || isEmpty();
|
||||
}
|
||||
|
||||
/// Check if this is a unary twine.
|
||||
bool isUnary() const {
|
||||
return getRHSKind() == EmptyKind && !isNullary();
|
||||
}
|
||||
|
||||
/// Check if this is a binary twine.
|
||||
bool isBinary() const {
|
||||
return getLHSKind() != NullKind && getRHSKind() != EmptyKind;
|
||||
}
|
||||
|
||||
/// Check if this is a valid twine (satisfying the invariants on
|
||||
/// order and number of arguments).
|
||||
bool isValid() const {
|
||||
// Nullary twines always have Empty on the RHS.
|
||||
if (isNullary() && getRHSKind() != EmptyKind)
|
||||
return false;
|
||||
|
||||
// Null should never appear on the RHS.
|
||||
if (getRHSKind() == NullKind)
|
||||
return false;
|
||||
|
||||
// The RHS cannot be non-empty if the LHS is empty.
|
||||
if (getRHSKind() != EmptyKind && getLHSKind() == EmptyKind)
|
||||
return false;
|
||||
#if 0 // causes spurious warnings
|
||||
// A twine child should always be binary.
|
||||
if (getLHSKind() == TwineKind &&
|
||||
!LHS.twine->isBinary())
|
||||
return false;
|
||||
if (getRHSKind() == TwineKind &&
|
||||
!RHS.twine->isBinary())
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Get the NodeKind of the left-hand side.
|
||||
NodeKind getLHSKind() const { return LHSKind; }
|
||||
|
||||
/// Get the NodeKind of the right-hand side.
|
||||
NodeKind getRHSKind() const { return RHSKind; }
|
||||
|
||||
/// Print one child from a twine.
|
||||
void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const;
|
||||
|
||||
/// Print the representation of one child from a twine.
|
||||
void printOneChildRepr(raw_ostream &OS, Child Ptr,
|
||||
NodeKind Kind) const;
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
|
||||
/// Construct from an empty string.
|
||||
/*implicit*/ Twine() {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
Twine(const Twine &) = default;
|
||||
|
||||
/// Construct from a C string.
|
||||
///
|
||||
/// We take care here to optimize "" into the empty twine -- this will be
|
||||
/// optimized out for string constants. This allows Twine arguments have
|
||||
/// default "" values, without introducing unnecessary string constants.
|
||||
/*implicit*/ Twine(const char *Str) {
|
||||
if (Str[0] != '\0') {
|
||||
LHS.cString = Str;
|
||||
LHSKind = CStringKind;
|
||||
} else
|
||||
LHSKind = EmptyKind;
|
||||
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from an std::string.
|
||||
/*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) {
|
||||
LHS.stdString = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a StringRef.
|
||||
/*implicit*/ Twine(const StringRef &Str) : LHSKind(StringRefKind) {
|
||||
LHS.stringRef = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a std::string_view.
|
||||
/*implicit*/ Twine(const std::string_view &Str) : LHSKind(StringViewKind) {
|
||||
LHS.stringView = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a SmallString.
|
||||
/*implicit*/ Twine(const SmallVectorImpl<char> &Str)
|
||||
: LHSKind(SmallStringKind) {
|
||||
LHS.smallString = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a char.
|
||||
explicit Twine(char Val) : LHSKind(CharKind) {
|
||||
LHS.character = Val;
|
||||
}
|
||||
|
||||
/// Construct from a signed char.
|
||||
explicit Twine(signed char Val) : LHSKind(CharKind) {
|
||||
LHS.character = static_cast<char>(Val);
|
||||
}
|
||||
|
||||
/// Construct from an unsigned char.
|
||||
explicit Twine(unsigned char Val) : LHSKind(CharKind) {
|
||||
LHS.character = static_cast<char>(Val);
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as an unsigned decimal integer.
|
||||
explicit Twine(unsigned Val) : LHSKind(DecUIKind) {
|
||||
LHS.decUI = Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as a signed decimal integer.
|
||||
explicit Twine(int Val) : LHSKind(DecIKind) {
|
||||
LHS.decI = Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as an unsigned decimal integer.
|
||||
explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) {
|
||||
LHS.decUL = &Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as a signed decimal integer.
|
||||
explicit Twine(const long &Val) : LHSKind(DecLKind) {
|
||||
LHS.decL = &Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as an unsigned decimal integer.
|
||||
explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) {
|
||||
LHS.decULL = &Val;
|
||||
}
|
||||
|
||||
/// Construct a twine to print \p Val as a signed decimal integer.
|
||||
explicit Twine(const long long &Val) : LHSKind(DecLLKind) {
|
||||
LHS.decLL = &Val;
|
||||
}
|
||||
|
||||
// FIXME: Unfortunately, to make sure this is as efficient as possible we
|
||||
// need extra binary constructors from particular types. We can't rely on
|
||||
// the compiler to be smart enough to fold operator+()/concat() down to the
|
||||
// right thing. Yet.
|
||||
|
||||
/// Construct as the concatenation of a C string and a StringRef.
|
||||
/*implicit*/ Twine(const char *LHS, const StringRef &RHS)
|
||||
: LHSKind(CStringKind), RHSKind(StringRefKind) {
|
||||
this->LHS.cString = LHS;
|
||||
this->RHS.stringRef = &RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct as the concatenation of a StringRef and a C string.
|
||||
/*implicit*/ Twine(const StringRef &LHS, const char *RHS)
|
||||
: LHSKind(StringRefKind), RHSKind(CStringKind) {
|
||||
this->LHS.stringRef = &LHS;
|
||||
this->RHS.cString = RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct as the concatenation of a C string and a std::string_view.
|
||||
/*implicit*/ Twine(const char *LHS, const std::string_view &RHS)
|
||||
: LHSKind(CStringKind), RHSKind(StringViewKind) {
|
||||
this->LHS.cString = LHS;
|
||||
this->RHS.stringView = &RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct as the concatenation of a std::string_view and a C string.
|
||||
/*implicit*/ Twine(const std::string_view &LHS, const char *RHS)
|
||||
: LHSKind(StringViewKind), RHSKind(CStringKind) {
|
||||
this->LHS.stringView = &LHS;
|
||||
this->RHS.cString = RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Since the intended use of twines is as temporary objects, assignments
|
||||
/// when concatenating might cause undefined behavior or stack corruptions
|
||||
Twine &operator=(const Twine &) = delete;
|
||||
|
||||
/// Create a 'null' string, which is an empty string that always
|
||||
/// concatenates to form another empty string.
|
||||
static Twine createNull() {
|
||||
return Twine(NullKind);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Numeric Conversions
|
||||
/// @{
|
||||
|
||||
// Construct a twine to print \p Val as an unsigned hexadecimal integer.
|
||||
static Twine utohexstr(const uint64_t &Val) {
|
||||
Child LHS, RHS;
|
||||
LHS.uHex = &Val;
|
||||
RHS.twine = nullptr;
|
||||
return Twine(LHS, UHexKind, RHS, EmptyKind);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Predicate Operations
|
||||
/// @{
|
||||
|
||||
/// Check for the null twine.
|
||||
bool isNull() const {
|
||||
return getLHSKind() == NullKind;
|
||||
}
|
||||
|
||||
/// Check if this twine is trivially empty; a false return value does not
|
||||
/// necessarily mean the twine is empty.
|
||||
bool isTriviallyEmpty() const {
|
||||
return isNullary();
|
||||
}
|
||||
|
||||
/// Return true if this twine can be dynamically accessed as a single
|
||||
/// StringRef value with getSingleStringRef().
|
||||
bool isSingleStringRef() const {
|
||||
if (getRHSKind() != EmptyKind) return false;
|
||||
|
||||
switch (getLHSKind()) {
|
||||
case EmptyKind:
|
||||
case CStringKind:
|
||||
case StdStringKind:
|
||||
case StringRefKind:
|
||||
case StringViewKind:
|
||||
case SmallStringKind:
|
||||
case CharKind:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Operations
|
||||
/// @{
|
||||
|
||||
Twine concat(const Twine &Suffix) const;
|
||||
|
||||
/// @}
|
||||
/// @name Output & Conversion.
|
||||
/// @{
|
||||
|
||||
/// Return the twine contents as a std::string.
|
||||
std::string str() const;
|
||||
|
||||
/// Append the concatenated string into the given SmallString or SmallVector.
|
||||
void toVector(SmallVectorImpl<char> &Out) const;
|
||||
|
||||
/// This returns the twine as a single StringRef. This method is only valid
|
||||
/// if isSingleStringRef() is true.
|
||||
StringRef getSingleStringRef() const {
|
||||
assert(isSingleStringRef() &&"This cannot be had as a single stringref!");
|
||||
switch (getLHSKind()) {
|
||||
default:
|
||||
// unreachable("Out of sync with isSingleStringRef");
|
||||
return StringRef();
|
||||
case EmptyKind: return StringRef();
|
||||
case CStringKind: return StringRef(LHS.cString);
|
||||
case StdStringKind: return StringRef(*LHS.stdString);
|
||||
case StringRefKind: return *LHS.stringRef;
|
||||
case StringViewKind: return StringRef(*LHS.stringView);
|
||||
case SmallStringKind:
|
||||
return StringRef(LHS.smallString->data(), LHS.smallString->size());
|
||||
case CharKind: return StringRef(&LHS.character, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// This returns the twine as a single StringRef if it can be
|
||||
/// represented as such. Otherwise the twine is written into the given
|
||||
/// SmallVector and a StringRef to the SmallVector's data is returned.
|
||||
StringRef toStringRef(SmallVectorImpl<char> &Out) const {
|
||||
if (isSingleStringRef())
|
||||
return getSingleStringRef();
|
||||
toVector(Out);
|
||||
return StringRef(Out.data(), Out.size());
|
||||
}
|
||||
|
||||
/// This returns the twine as a single null terminated StringRef if it
|
||||
/// can be represented as such. Otherwise the twine is written into the
|
||||
/// given SmallVector and a StringRef to the SmallVector's data is returned.
|
||||
///
|
||||
/// The returned StringRef's size does not include the null terminator.
|
||||
StringRef toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const;
|
||||
|
||||
/// Write the concatenated string represented by this twine to the
|
||||
/// stream \p OS.
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// Dump the concatenated string represented by this twine to stderr.
|
||||
void dump() const;
|
||||
|
||||
/// Write the representation of this twine to the stream \p OS.
|
||||
void printRepr(raw_ostream &OS) const;
|
||||
|
||||
/// Dump the representation of this twine to stderr.
|
||||
void dumpRepr() const;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// @name Twine Inline Implementations
|
||||
/// @{
|
||||
|
||||
inline Twine Twine::concat(const Twine &Suffix) const {
|
||||
// Concatenation with null is null.
|
||||
if (isNull() || Suffix.isNull())
|
||||
return Twine(NullKind);
|
||||
|
||||
// Concatenation with empty yields the other side.
|
||||
if (isEmpty())
|
||||
return Suffix;
|
||||
if (Suffix.isEmpty())
|
||||
return *this;
|
||||
|
||||
// Otherwise we need to create a new node, taking care to fold in unary
|
||||
// twines.
|
||||
Child NewLHS, NewRHS;
|
||||
NewLHS.twine = this;
|
||||
NewRHS.twine = &Suffix;
|
||||
NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind;
|
||||
if (isUnary()) {
|
||||
NewLHS = LHS;
|
||||
NewLHSKind = getLHSKind();
|
||||
}
|
||||
if (Suffix.isUnary()) {
|
||||
NewRHS = Suffix.LHS;
|
||||
NewRHSKind = Suffix.getLHSKind();
|
||||
}
|
||||
|
||||
return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind);
|
||||
}
|
||||
|
||||
inline Twine operator+(const Twine &LHS, const Twine &RHS) {
|
||||
return LHS.concat(RHS);
|
||||
}
|
||||
|
||||
/// Additional overload to guarantee simplified codegen; this is equivalent to
|
||||
/// concat().
|
||||
|
||||
inline Twine operator+(const char *LHS, const StringRef &RHS) {
|
||||
return Twine(LHS, RHS);
|
||||
}
|
||||
|
||||
/// Additional overload to guarantee simplified codegen; this is equivalent to
|
||||
/// concat().
|
||||
|
||||
inline Twine operator+(const StringRef &LHS, const char *RHS) {
|
||||
return Twine(LHS, RHS);
|
||||
}
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) {
|
||||
RHS.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // LLVM_ADT_TWINE_H
|
||||
@@ -6,11 +6,10 @@
|
||||
#define WPIUTIL_WPI_UDPCLIENT_H_
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -25,7 +24,7 @@ class UDPClient {
|
||||
|
||||
public:
|
||||
explicit UDPClient(Logger& logger);
|
||||
UDPClient(const Twine& address, Logger& logger);
|
||||
UDPClient(std::string_view address, Logger& logger);
|
||||
UDPClient(const UDPClient& other) = delete;
|
||||
UDPClient(UDPClient&& other);
|
||||
~UDPClient();
|
||||
@@ -37,8 +36,8 @@ class UDPClient {
|
||||
int start(int port);
|
||||
void shutdown();
|
||||
// The passed in address MUST be a resolved IP address.
|
||||
int send(ArrayRef<uint8_t> data, const Twine& server, int port);
|
||||
int send(StringRef data, const Twine& server, int port);
|
||||
int send(ArrayRef<uint8_t> data, std::string_view server, int port);
|
||||
int send(std::string_view data, std::string_view server, int port);
|
||||
int receive(uint8_t* data_received, int receive_len);
|
||||
int receive(uint8_t* data_received, int receive_len,
|
||||
SmallVectorImpl<char>* addr_received, int* port_received);
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#ifndef WPIUTIL_WPI_URLPARSER_H_
|
||||
#define WPIUTIL_WPI_URLPARSER_H_
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/http_parser.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -21,7 +22,7 @@ class UrlParser {
|
||||
* @param in input
|
||||
* @param isConnect
|
||||
*/
|
||||
UrlParser(StringRef in, bool isConnect) {
|
||||
UrlParser(std::string_view in, bool isConnect) {
|
||||
m_data = in;
|
||||
http_parser_url_init(&m_url);
|
||||
m_error = http_parser_parse_url(in.data(), in.size(), isConnect, &m_url);
|
||||
@@ -50,41 +51,41 @@ class UrlParser {
|
||||
return (m_url.field_set & (1 << UF_USERINFO)) != 0;
|
||||
}
|
||||
|
||||
StringRef GetSchema() const {
|
||||
std::string_view GetSchema() const {
|
||||
return m_data.substr(m_url.field_data[UF_SCHEMA].off,
|
||||
m_url.field_data[UF_SCHEMA].len);
|
||||
}
|
||||
|
||||
StringRef GetHost() const {
|
||||
std::string_view GetHost() const {
|
||||
return m_data.substr(m_url.field_data[UF_HOST].off,
|
||||
m_url.field_data[UF_HOST].len);
|
||||
}
|
||||
|
||||
unsigned int GetPort() const { return m_url.port; }
|
||||
|
||||
StringRef GetPath() const {
|
||||
std::string_view GetPath() const {
|
||||
return m_data.substr(m_url.field_data[UF_PATH].off,
|
||||
m_url.field_data[UF_PATH].len);
|
||||
}
|
||||
|
||||
StringRef GetQuery() const {
|
||||
std::string_view GetQuery() const {
|
||||
return m_data.substr(m_url.field_data[UF_QUERY].off,
|
||||
m_url.field_data[UF_QUERY].len);
|
||||
}
|
||||
|
||||
StringRef GetFragment() const {
|
||||
std::string_view GetFragment() const {
|
||||
return m_data.substr(m_url.field_data[UF_FRAGMENT].off,
|
||||
m_url.field_data[UF_FRAGMENT].len);
|
||||
}
|
||||
|
||||
StringRef GetUserInfo() const {
|
||||
std::string_view GetUserInfo() const {
|
||||
return m_data.substr(m_url.field_data[UF_USERINFO].off,
|
||||
m_url.field_data[UF_USERINFO].len);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_error;
|
||||
StringRef m_data;
|
||||
std::string_view m_data;
|
||||
http_parser_url m_url;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,11 +15,8 @@
|
||||
#ifndef WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
#define WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -137,18 +134,7 @@ public:
|
||||
friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return !(X < Y);
|
||||
}
|
||||
|
||||
/// Retrieve a string representation of the version number.
|
||||
std::string getAsString() const;
|
||||
|
||||
/// Try to parse the given string as a version number.
|
||||
/// \returns \c true if the string does not match the regular expression
|
||||
/// [0-9]+(\.[0-9]+){0,3}
|
||||
bool tryParse(StringRef string);
|
||||
};
|
||||
|
||||
/// Print a version number.
|
||||
raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V);
|
||||
|
||||
} // end namespace wpi
|
||||
#endif // WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
|
||||
@@ -11,13 +11,12 @@
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Buffer.h"
|
||||
#include "wpi/uv/Error.h"
|
||||
#include "wpi/uv/Timer.h"
|
||||
@@ -79,7 +78,7 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
uv::Timer::Time handshakeTimeout; // NOLINT
|
||||
|
||||
/** Additional headers to include in handshake. */
|
||||
ArrayRef<std::pair<StringRef, StringRef>> extraHeaders;
|
||||
ArrayRef<std::pair<std::string_view, std::string_view>> extraHeaders;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -93,9 +92,9 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
* @param options Handshake options
|
||||
*/
|
||||
static std::shared_ptr<WebSocket> CreateClient(
|
||||
uv::Stream& stream, const Twine& uri, const Twine& host,
|
||||
ArrayRef<StringRef> protocols = ArrayRef<StringRef>{},
|
||||
const ClientOptions& options = ClientOptions{});
|
||||
uv::Stream& stream, std::string_view uri, std::string_view host,
|
||||
ArrayRef<std::string_view> protocols = {},
|
||||
const ClientOptions& options = {});
|
||||
|
||||
/**
|
||||
* Starts a client connection by performing the initial client handshake.
|
||||
@@ -108,9 +107,9 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
* @param options Handshake options
|
||||
*/
|
||||
static std::shared_ptr<WebSocket> CreateClient(
|
||||
uv::Stream& stream, const Twine& uri, const Twine& host,
|
||||
std::initializer_list<StringRef> protocols,
|
||||
const ClientOptions& options = ClientOptions{}) {
|
||||
uv::Stream& stream, std::string_view uri, std::string_view host,
|
||||
std::initializer_list<std::string_view> protocols,
|
||||
const ClientOptions& options = {}) {
|
||||
return CreateClient(stream, uri, host,
|
||||
makeArrayRef(protocols.begin(), protocols.end()),
|
||||
options);
|
||||
@@ -130,8 +129,8 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
* Sec-WebSocket-Protocol header field).
|
||||
*/
|
||||
static std::shared_ptr<WebSocket> CreateServer(
|
||||
uv::Stream& stream, StringRef key, StringRef version,
|
||||
StringRef protocol = StringRef{});
|
||||
uv::Stream& stream, std::string_view key, std::string_view version,
|
||||
std::string_view protocol = {});
|
||||
|
||||
/**
|
||||
* Get connection state.
|
||||
@@ -152,7 +151,7 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
/**
|
||||
* Get the selected sub-protocol. Only valid in or after the open() event.
|
||||
*/
|
||||
StringRef GetProtocol() const { return m_protocol; }
|
||||
std::string_view GetProtocol() const { return m_protocol; }
|
||||
|
||||
/**
|
||||
* Set the maximum message size. Default is 128 KB. If configured to combine
|
||||
@@ -176,7 +175,7 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
* @param reason A human-readable string explaining why the connection is
|
||||
* closing (optional).
|
||||
*/
|
||||
void Close(uint16_t code = 1005, const Twine& reason = Twine{});
|
||||
void Close(uint16_t code = 1005, std::string_view reason = {});
|
||||
|
||||
/**
|
||||
* Send a text message.
|
||||
@@ -292,12 +291,12 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
/**
|
||||
* Fail the connection.
|
||||
*/
|
||||
void Fail(uint16_t code = 1002, const Twine& reason = "protocol error");
|
||||
void Fail(uint16_t code = 1002, std::string_view reason = "protocol error");
|
||||
|
||||
/**
|
||||
* Forcibly close the connection.
|
||||
*/
|
||||
void Terminate(uint16_t code = 1006, const Twine& reason = "terminated");
|
||||
void Terminate(uint16_t code = 1006, std::string_view reason = "terminated");
|
||||
|
||||
/**
|
||||
* Gets user-defined data.
|
||||
@@ -318,7 +317,7 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
* Open event. Emitted when the connection is open and ready to communicate.
|
||||
* The parameter is the selected subprotocol.
|
||||
*/
|
||||
sig::Signal<StringRef> open;
|
||||
sig::Signal<std::string_view> open;
|
||||
|
||||
/**
|
||||
* Close event. Emitted when the connection is closed. The first parameter
|
||||
@@ -326,14 +325,14 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
* has been closed. The second parameter is a human-readable string
|
||||
* explaining the reason why the connection has been closed.
|
||||
*/
|
||||
sig::Signal<uint16_t, StringRef> closed;
|
||||
sig::Signal<uint16_t, std::string_view> closed;
|
||||
|
||||
/**
|
||||
* Text message event. Emitted when a text message is received.
|
||||
* The first parameter is the data, the second parameter is true if the
|
||||
* data is the last fragment of the message.
|
||||
*/
|
||||
sig::Signal<StringRef, bool> text;
|
||||
sig::Signal<std::string_view, bool> text;
|
||||
|
||||
/**
|
||||
* Binary message event. Emitted when a binary message is received.
|
||||
@@ -382,11 +381,13 @@ class WebSocket : public std::enable_shared_from_this<WebSocket> {
|
||||
class ClientHandshakeData;
|
||||
std::unique_ptr<ClientHandshakeData> m_clientHandshake;
|
||||
|
||||
void StartClient(const Twine& uri, const Twine& host,
|
||||
ArrayRef<StringRef> protocols, const ClientOptions& options);
|
||||
void StartServer(StringRef key, StringRef version, StringRef protocol);
|
||||
void SendClose(uint16_t code, const Twine& reason);
|
||||
void SetClosed(uint16_t code, const Twine& reason, bool failed = false);
|
||||
void StartClient(std::string_view uri, std::string_view host,
|
||||
ArrayRef<std::string_view> protocols,
|
||||
const ClientOptions& options);
|
||||
void StartServer(std::string_view key, std::string_view version,
|
||||
std::string_view protocol);
|
||||
void SendClose(uint16_t code, std::string_view reason);
|
||||
void SetClosed(uint16_t code, std::string_view reason, bool failed = false);
|
||||
void Shutdown();
|
||||
void HandleIncoming(uv::Buffer& buf, size_t size);
|
||||
void Send(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
@@ -16,7 +17,6 @@
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/WebSocket.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -52,7 +52,8 @@ class WebSocketServerHelper {
|
||||
* Second item is the matched protocol if a match was made, otherwise
|
||||
* is empty.
|
||||
*/
|
||||
std::pair<bool, StringRef> MatchProtocol(ArrayRef<StringRef> protocols);
|
||||
std::pair<bool, std::string_view> MatchProtocol(
|
||||
ArrayRef<std::string_view> protocols);
|
||||
|
||||
/**
|
||||
* Try to find a match to the list of sub-protocols provided by the client.
|
||||
@@ -63,8 +64,8 @@ class WebSocketServerHelper {
|
||||
* Second item is the matched protocol if a match was made, otherwise
|
||||
* is empty.
|
||||
*/
|
||||
std::pair<bool, StringRef> MatchProtocol(
|
||||
std::initializer_list<StringRef> protocols) {
|
||||
std::pair<bool, std::string_view> MatchProtocol(
|
||||
std::initializer_list<std::string_view> protocols) {
|
||||
return MatchProtocol(makeArrayRef(protocols.begin(), protocols.end()));
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ class WebSocketServerHelper {
|
||||
* @param protocol The subprotocol to send to the client
|
||||
*/
|
||||
std::shared_ptr<WebSocket> Accept(uv::Stream& stream,
|
||||
StringRef protocol = StringRef{}) {
|
||||
std::string_view protocol = {}) {
|
||||
return WebSocket::CreateServer(stream, m_key, m_version, protocol);
|
||||
}
|
||||
|
||||
@@ -109,19 +110,19 @@ class WebSocketServer : public std::enable_shared_from_this<WebSocketServer> {
|
||||
* Checker for URL. Return true if URL should be accepted. By default all
|
||||
* URLs are accepted.
|
||||
*/
|
||||
std::function<bool(StringRef)> checkUrl;
|
||||
std::function<bool(std::string_view)> checkUrl;
|
||||
|
||||
/**
|
||||
* Checker for Host header. Return true if Host should be accepted. By
|
||||
* default all hosts are accepted.
|
||||
*/
|
||||
std::function<bool(StringRef)> checkHost;
|
||||
std::function<bool(std::string_view)> checkHost;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
WebSocketServer(uv::Stream& stream, ArrayRef<StringRef> protocols,
|
||||
WebSocketServer(uv::Stream& stream, ArrayRef<std::string_view> protocols,
|
||||
ServerOptions options, const private_init&);
|
||||
|
||||
/**
|
||||
@@ -134,8 +135,8 @@ class WebSocketServer : public std::enable_shared_from_this<WebSocketServer> {
|
||||
* @param options Handshake options
|
||||
*/
|
||||
static std::shared_ptr<WebSocketServer> Create(
|
||||
uv::Stream& stream, ArrayRef<StringRef> protocols = ArrayRef<StringRef>{},
|
||||
const ServerOptions& options = ServerOptions{});
|
||||
uv::Stream& stream, ArrayRef<std::string_view> protocols = {},
|
||||
const ServerOptions& options = {});
|
||||
|
||||
/**
|
||||
* Starts a dedicated WebSocket server on the provided connection. The
|
||||
@@ -147,8 +148,8 @@ class WebSocketServer : public std::enable_shared_from_this<WebSocketServer> {
|
||||
* @param options Handshake options
|
||||
*/
|
||||
static std::shared_ptr<WebSocketServer> Create(
|
||||
uv::Stream& stream, std::initializer_list<StringRef> protocols,
|
||||
const ServerOptions& options = ServerOptions{}) {
|
||||
uv::Stream& stream, std::initializer_list<std::string_view> protocols,
|
||||
const ServerOptions& options = {}) {
|
||||
return Create(stream, makeArrayRef(protocols.begin(), protocols.end()),
|
||||
options);
|
||||
}
|
||||
@@ -156,7 +157,7 @@ class WebSocketServer : public std::enable_shared_from_this<WebSocketServer> {
|
||||
/**
|
||||
* Connected event. First parameter is the URL, second is the websocket.
|
||||
*/
|
||||
sig::Signal<StringRef, WebSocket&> connected;
|
||||
sig::Signal<std::string_view, WebSocket&> connected;
|
||||
|
||||
private:
|
||||
uv::Stream& m_stream;
|
||||
@@ -169,7 +170,7 @@ class WebSocketServer : public std::enable_shared_from_this<WebSocketServer> {
|
||||
sig::ScopedConnection m_errorConn;
|
||||
sig::ScopedConnection m_endConn;
|
||||
|
||||
void Abort(uint16_t code, StringRef reason);
|
||||
void Abort(uint16_t code, std::string_view reason);
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
30
wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h
Normal file
30
wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#ifndef WPIUTIL_WPI_FMT_RAW_OSTREAM_H_
|
||||
#define WPIUTIL_WPI_FMT_RAW_OSTREAM_H_
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
inline void vprint(wpi::raw_ostream& os, string_view format_str,
|
||||
fmt::format_args args) {
|
||||
memory_buffer buffer;
|
||||
detail::vformat_to(buffer, format_str, args);
|
||||
os.write(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints formatted data to the stream *os*.
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
void print(wpi::raw_ostream& os, const S& format_str, Args&&... args) {
|
||||
vprint(os, format_str, fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // WPIUTIL_WPI_FMT_RAW_OSTREAM_H_
|
||||
@@ -6,15 +6,14 @@
|
||||
#define WPIUTIL_WPI_HOSTNAME_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
|
||||
std::string GetHostname();
|
||||
StringRef GetHostname(SmallVectorImpl<char>& name);
|
||||
std::string_view GetHostname(SmallVectorImpl<char>& name);
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_HOSTNAME_H_
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -18,7 +19,7 @@
|
||||
#include "wpi/SafeThread.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/deprecated.h"
|
||||
#include "wpi/mutex.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
@@ -30,7 +31,7 @@ namespace wpi::java {
|
||||
// in the stack trace not starting with excludeFuncPrefix (useful for e.g.
|
||||
// finding the first user call to a series of library functions).
|
||||
std::string GetJavaStackTrace(JNIEnv* env, std::string* func = nullptr,
|
||||
StringRef excludeFuncPrefix = StringRef());
|
||||
std::string_view excludeFuncPrefix = {});
|
||||
|
||||
// Finds a class and keep it as a global reference.
|
||||
// Use with caution, as the destructor does NOT call DeleteGlobalRef due
|
||||
@@ -148,8 +149,8 @@ class JStringRef {
|
||||
m_str.pop_back();
|
||||
}
|
||||
|
||||
operator StringRef() const { return m_str; } // NOLINT
|
||||
StringRef str() const { return m_str; }
|
||||
operator std::string_view() const { return m_str.str(); } // NOLINT
|
||||
std::string_view str() const { return m_str.str(); }
|
||||
const char* c_str() const { return m_str.data(); }
|
||||
size_t size() const { return m_str.size(); }
|
||||
|
||||
@@ -163,18 +164,18 @@ namespace detail {
|
||||
template <typename C, typename T>
|
||||
class JArrayRefInner {};
|
||||
|
||||
// Specialization of JArrayRefBase to provide StringRef conversion.
|
||||
// Specialization of JArrayRefBase to provide std::string_view conversion.
|
||||
template <typename C>
|
||||
class JArrayRefInner<C, jbyte> {
|
||||
public:
|
||||
operator StringRef() const { return str(); }
|
||||
operator std::string_view() const { return str(); }
|
||||
|
||||
StringRef str() const {
|
||||
std::string_view str() const {
|
||||
auto arr = static_cast<const C*>(this)->array();
|
||||
if (arr.empty()) {
|
||||
return {};
|
||||
}
|
||||
return StringRef{reinterpret_cast<const char*>(arr.data()), arr.size()};
|
||||
return {reinterpret_cast<const char*>(arr.data()), arr.size()};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -326,7 +327,7 @@ WPI_JNI_JARRAYREF(jdouble, Double)
|
||||
//
|
||||
|
||||
// Convert a UTF8 string into a jstring.
|
||||
inline jstring MakeJString(JNIEnv* env, StringRef str) {
|
||||
inline jstring MakeJString(JNIEnv* env, std::string_view str) {
|
||||
SmallVector<UTF16, 128> chars;
|
||||
convertUTF8ToUTF16String(str, chars);
|
||||
return env->NewString(chars.begin(), chars.size());
|
||||
@@ -395,8 +396,8 @@ inline jintArray MakeJIntArray(JNIEnv* env, const std::vector<T>& arr) {
|
||||
return detail::ConvertIntArray<T>::ToJava(env, arr);
|
||||
}
|
||||
|
||||
// Convert a StringRef into a jbyteArray.
|
||||
inline jbyteArray MakeJByteArray(JNIEnv* env, StringRef str) {
|
||||
// Convert a std::string_view into a jbyteArray.
|
||||
inline jbyteArray MakeJByteArray(JNIEnv* env, std::string_view str) {
|
||||
jbyteArray jarr = env->NewByteArray(str.size());
|
||||
if (!jarr) {
|
||||
return nullptr;
|
||||
@@ -593,7 +594,7 @@ class JSingletonCallbackManager : public JCallbackManager<T> {
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string GetJavaStackTrace(JNIEnv* env, StringRef skipPrefix) {
|
||||
inline std::string GetJavaStackTrace(JNIEnv* env, std::string_view skipPrefix) {
|
||||
// create a throwable
|
||||
static JClass throwableCls(env, "java/lang/Throwable");
|
||||
if (!throwableCls) {
|
||||
@@ -657,7 +658,7 @@ inline std::string GetJavaStackTrace(JNIEnv* env, StringRef skipPrefix) {
|
||||
// add a line to res
|
||||
JStringRef elem(env, stackElementString);
|
||||
if (!foundFirst) {
|
||||
if (elem.str().startswith(skipPrefix)) {
|
||||
if (wpi::starts_with(elem, skipPrefix)) {
|
||||
continue;
|
||||
}
|
||||
foundFirst = true;
|
||||
@@ -669,7 +670,7 @@ inline std::string GetJavaStackTrace(JNIEnv* env, StringRef skipPrefix) {
|
||||
}
|
||||
|
||||
inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
|
||||
StringRef excludeFuncPrefix) {
|
||||
std::string_view excludeFuncPrefix) {
|
||||
// create a throwable
|
||||
static JClass throwableCls(env, "java/lang/Throwable");
|
||||
if (!throwableCls) {
|
||||
@@ -740,7 +741,7 @@ inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
|
||||
if (i == 1) {
|
||||
*func = elem.str();
|
||||
} else if (i > 1 && !haveLoc && !excludeFuncPrefix.empty() &&
|
||||
!elem.str().startswith(excludeFuncPrefix)) {
|
||||
!wpi::starts_with(elem, excludeFuncPrefix)) {
|
||||
*func = elem.str();
|
||||
haveLoc = true;
|
||||
}
|
||||
@@ -769,7 +770,9 @@ class JException : public JClass {
|
||||
env->Throw(static_cast<jthrowable>(exception));
|
||||
}
|
||||
|
||||
void Throw(JNIEnv* env, StringRef msg) { Throw(env, MakeJString(env, msg)); }
|
||||
void Throw(JNIEnv* env, std::string_view msg) {
|
||||
Throw(env, MakeJString(env, msg));
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_constructor; }
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ SOFTWARE.
|
||||
#include <memory> // allocator, shared_ptr, make_shared, addressof
|
||||
#include <stdexcept> // runtime_error
|
||||
#include <string> // string, char_traits, stoi, to_string
|
||||
#include <string_view>
|
||||
#include <tuple> // tuple, get, make_tuple
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -61,8 +62,6 @@ SOFTWARE.
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/StringMap.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
|
||||
namespace wpi
|
||||
{
|
||||
@@ -239,7 +238,7 @@ template<class RealType, class CompatibleObjectType>
|
||||
struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
|
||||
{
|
||||
static constexpr auto value =
|
||||
std::is_constructible<StringRef, typename CompatibleObjectType::key_type>::value and
|
||||
std::is_constructible<std::string_view, typename CompatibleObjectType::key_type>::value and
|
||||
std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
|
||||
};
|
||||
|
||||
@@ -269,7 +268,7 @@ struct is_compatible_array_type
|
||||
std::conjunction<std::negation<std::is_same<void, CompatibleArrayType>>,
|
||||
std::negation<is_compatible_object_type<
|
||||
BasicJsonType, CompatibleArrayType>>,
|
||||
std::negation<std::is_constructible<StringRef,
|
||||
std::negation<std::is_constructible<std::string_view,
|
||||
CompatibleArrayType>>,
|
||||
std::negation<is_json_nested_type<BasicJsonType, CompatibleArrayType>>,
|
||||
has_value_type<CompatibleArrayType>,
|
||||
@@ -423,7 +422,7 @@ class exception : public std::exception
|
||||
const int id;
|
||||
|
||||
protected:
|
||||
exception(int id_, const Twine& what_arg);
|
||||
exception(int id_, std::string_view what_arg);
|
||||
|
||||
private:
|
||||
/// an exception object as storage for error messages
|
||||
@@ -484,7 +483,7 @@ class parse_error : public exception
|
||||
@param[in] what_arg the explanatory string
|
||||
@return parse_error object
|
||||
*/
|
||||
static parse_error create(int id_, std::size_t byte_, const Twine& what_arg);
|
||||
static parse_error create(int id_, std::size_t byte_, std::string_view what_arg);
|
||||
|
||||
/*!
|
||||
@brief byte index of the parse error
|
||||
@@ -498,7 +497,7 @@ class parse_error : public exception
|
||||
const std::size_t byte;
|
||||
|
||||
private:
|
||||
parse_error(int id_, std::size_t byte_, const Twine& what_arg)
|
||||
parse_error(int id_, std::size_t byte_, std::string_view what_arg)
|
||||
: exception(id_, what_arg), byte(byte_) {}
|
||||
};
|
||||
|
||||
@@ -542,10 +541,11 @@ caught.,invalid_iterator}
|
||||
class invalid_iterator : public exception
|
||||
{
|
||||
public:
|
||||
static invalid_iterator create(int id_, const Twine& what_arg);
|
||||
static invalid_iterator create(int id_, std::string_view what_arg);
|
||||
static invalid_iterator create(int id_, std::string_view what_arg, std::string_view type_info);
|
||||
|
||||
private:
|
||||
invalid_iterator(int id_, const Twine& what_arg)
|
||||
invalid_iterator(int id_, std::string_view what_arg)
|
||||
: exception(id_, what_arg) {}
|
||||
};
|
||||
|
||||
@@ -590,10 +590,11 @@ caught.,type_error}
|
||||
class type_error : public exception
|
||||
{
|
||||
public:
|
||||
static type_error create(int id_, const Twine& what_arg);
|
||||
static type_error create(int id_, std::string_view what_arg);
|
||||
static type_error create(int id_, std::string_view what_arg, std::string_view type_info);
|
||||
|
||||
private:
|
||||
type_error(int id_, const Twine& what_arg) : exception(id_, what_arg) {}
|
||||
type_error(int id_, std::string_view what_arg) : exception(id_, what_arg) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -631,10 +632,10 @@ caught.,out_of_range}
|
||||
class out_of_range : public exception
|
||||
{
|
||||
public:
|
||||
static out_of_range create(int id_, const Twine& what_arg);
|
||||
static out_of_range create(int id_, std::string_view what_arg);
|
||||
|
||||
private:
|
||||
out_of_range(int id_, const Twine& what_arg) : exception(id_, what_arg) {}
|
||||
out_of_range(int id_, std::string_view what_arg) : exception(id_, what_arg) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -664,10 +665,10 @@ caught.,other_error}
|
||||
class other_error : public exception
|
||||
{
|
||||
public:
|
||||
static other_error create(int id_, const Twine& what_arg);
|
||||
static other_error create(int id_, std::string_view what_arg);
|
||||
|
||||
private:
|
||||
other_error(int id_, const Twine& what_arg) : exception(id_, what_arg) {}
|
||||
other_error(int id_, std::string_view what_arg) : exception(id_, what_arg) {}
|
||||
};
|
||||
|
||||
///////////////////////////
|
||||
@@ -760,7 +761,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(type_error::create(302, "type must be number, but is " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be number, but is", j.type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,7 +770,7 @@ void from_json(const BasicJsonType& j, bool& b)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_boolean()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be boolean, but is " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be boolean, but is", j.type_name()));
|
||||
}
|
||||
b = *j.template get_ptr<const bool*>();
|
||||
}
|
||||
@@ -779,7 +780,7 @@ void from_json(const BasicJsonType& j, std::string& s)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_string()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be string, but is " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be string, but is", j.type_name()));
|
||||
}
|
||||
s = *j.template get_ptr<const std::string*>();
|
||||
}
|
||||
@@ -816,7 +817,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is", j.type_name()));
|
||||
}
|
||||
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
@@ -875,8 +876,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " +
|
||||
Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is", j.type_name()));
|
||||
}
|
||||
|
||||
from_json_array_impl(j, arr, priority_tag<2> {});
|
||||
@@ -888,7 +888,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::object_t& obj)
|
||||
{
|
||||
if (!j.is_object())
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be object, but is " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be object, but is", j.type_name()));
|
||||
}
|
||||
|
||||
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
@@ -904,7 +904,7 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
|
||||
{
|
||||
if (JSON_UNLIKELY(not j.is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be object, but is " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be object, but is", j.type_name()));
|
||||
}
|
||||
|
||||
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
@@ -965,7 +965,7 @@ void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(type_error::create(302, "type must be number, but is " + Twine(j.type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be number, but is", j.type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1053,7 +1053,7 @@ template<>
|
||||
struct external_constructor<value_t::string>
|
||||
{
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, StringRef s)
|
||||
static void construct(BasicJsonType& j, std::string_view s)
|
||||
{
|
||||
j.m_type = value_t::string;
|
||||
j.m_value = s;
|
||||
@@ -1206,7 +1206,7 @@ void to_json(BasicJsonType& j, T b) noexcept
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleString,
|
||||
enable_if_t<std::is_constructible<StringRef, CompatibleString>::value, int> = 0>
|
||||
enable_if_t<std::is_constructible<std::string_view, CompatibleString>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, const CompatibleString& s)
|
||||
{
|
||||
external_constructor<value_t::string>::construct(j, s);
|
||||
@@ -1283,7 +1283,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, std::size_t N,
|
||||
enable_if_t<not std::is_constructible<StringRef, T (&)[N]>::value, int> = 0>
|
||||
enable_if_t<not std::is_constructible<std::string_view, T (&)[N]>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, T (&arr)[N])
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, arr);
|
||||
@@ -2044,7 +2044,7 @@ class iter_impl
|
||||
@brief return the key of an object iterator
|
||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||
*/
|
||||
StringRef key() const
|
||||
std::string_view key() const
|
||||
{
|
||||
assert(m_object != nullptr);
|
||||
|
||||
@@ -2348,7 +2348,7 @@ class json_pointer
|
||||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
explicit json_pointer(const Twine& s = {})
|
||||
explicit json_pointer(std::string_view s = {})
|
||||
: reference_tokens(split(s))
|
||||
{}
|
||||
|
||||
@@ -2382,7 +2382,7 @@ class json_pointer
|
||||
|
||||
@throw out_of_range.404 if string @a s could not be converted to an integer
|
||||
*/
|
||||
static int array_index(const Twine& s);
|
||||
static int array_index(std::string_view s);
|
||||
|
||||
private:
|
||||
/*!
|
||||
@@ -2490,7 +2490,7 @@ class json_pointer
|
||||
@throw parse_error.107 if the pointer is not empty or begins with '/'
|
||||
@throw parse_error.108 if character '~' is not followed by '0' or '1'
|
||||
*/
|
||||
static std::vector<std::string> split(const Twine& reference_string);
|
||||
static std::vector<std::string> split(std::string_view reference_string);
|
||||
|
||||
/*!
|
||||
@brief replace all occurrences of a substring by another string
|
||||
@@ -2521,7 +2521,7 @@ class json_pointer
|
||||
|
||||
@note Empty objects or arrays are flattened to `null`.
|
||||
*/
|
||||
static void flatten(const Twine& reference_string,
|
||||
static void flatten(std::string_view reference_string,
|
||||
const json& value,
|
||||
json& result);
|
||||
|
||||
@@ -2970,7 +2970,7 @@ class json
|
||||
json_value(value_t t);
|
||||
|
||||
/// constructor for strings
|
||||
json_value(StringRef value)
|
||||
json_value(std::string_view value)
|
||||
{
|
||||
string = create<std::string>(value);
|
||||
}
|
||||
@@ -3576,8 +3576,7 @@ class json
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " +
|
||||
Twine(first.m_object->type_name())));
|
||||
JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from", first.m_object->type_name()));
|
||||
}
|
||||
|
||||
assert_invariant();
|
||||
@@ -4162,7 +4161,7 @@ class json
|
||||
return m_value.boolean;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(302, "type must be boolean, but is " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(302, "type must be boolean, but is", type_name()));
|
||||
}
|
||||
|
||||
/// get a pointer to the value (object)
|
||||
@@ -4271,7 +4270,7 @@ class json
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + Twine(obj.type_name())));
|
||||
JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is", obj.type_name()));
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -4716,7 +4715,7 @@ class json
|
||||
written using `at()`. It also demonstrates the different exceptions that
|
||||
can be thrown.,at__object_t_key_type}
|
||||
*/
|
||||
reference at(StringRef key);
|
||||
reference at(std::string_view key);
|
||||
|
||||
/*!
|
||||
@brief access specified object element with bounds checking
|
||||
@@ -4748,7 +4747,7 @@ class json
|
||||
`at()`. It also demonstrates the different exceptions that can be thrown.,
|
||||
at__object_t_key_type_const}
|
||||
*/
|
||||
const_reference at(StringRef key) const;
|
||||
const_reference at(std::string_view key) const;
|
||||
|
||||
/*!
|
||||
@brief access specified array element
|
||||
@@ -4825,7 +4824,7 @@ class json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
reference operator[](StringRef key);
|
||||
reference operator[](std::string_view key);
|
||||
|
||||
/*!
|
||||
@brief read-only access specified object element
|
||||
@@ -4857,7 +4856,7 @@ class json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
const_reference operator[](StringRef key) const;
|
||||
const_reference operator[](std::string_view key) const;
|
||||
|
||||
/*!
|
||||
@brief access specified object element
|
||||
@@ -4903,7 +4902,7 @@ class json
|
||||
return m_value.object->operator[](key);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -4946,7 +4945,7 @@ class json
|
||||
return m_value.object->find(key)->second;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -4999,7 +4998,7 @@ class json
|
||||
*/
|
||||
template<class ValueType, typename std::enable_if<
|
||||
std::is_convertible<json_t, ValueType>::value, int>::type = 0>
|
||||
ValueType value(StringRef key, const ValueType& default_value) const
|
||||
ValueType value(std::string_view key, const ValueType& default_value) const
|
||||
{
|
||||
// at only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
@@ -5014,14 +5013,14 @@ class json
|
||||
return default_value;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(306, "cannot use value() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(306, "cannot use value() with", type_name()));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief overload for a default value of type const char*
|
||||
@copydoc json::value(const typename object_t::key_type&, ValueType) const
|
||||
*/
|
||||
std::string value(StringRef key, const char* default_value) const
|
||||
std::string value(std::string_view key, const char* default_value) const
|
||||
{
|
||||
return value(key, std::string(default_value));
|
||||
}
|
||||
@@ -5085,7 +5084,7 @@ class json
|
||||
}
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(306, "cannot use value() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(306, "cannot use value() with", type_name()));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -5220,7 +5219,7 @@ class json
|
||||
|
||||
@sa @ref erase(IteratorType, IteratorType) -- removes the elements in
|
||||
the given range
|
||||
@sa @ref erase(StringRef) -- removes the element
|
||||
@sa @ref erase(std::string_view) -- removes the element
|
||||
from an object at the given key
|
||||
@sa @ref erase(const size_type) -- removes the element from an array at
|
||||
the given index
|
||||
@@ -5278,7 +5277,7 @@ class json
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5377,7 +5376,7 @@ class json
|
||||
}
|
||||
|
||||
default:
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -5412,7 +5411,7 @@ class json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
size_type erase(StringRef key);
|
||||
size_type erase(std::string_view key);
|
||||
|
||||
/*!
|
||||
@brief remove element from a JSON array given an index
|
||||
@@ -5472,13 +5471,13 @@ class json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
iterator find(StringRef key);
|
||||
iterator find(std::string_view key);
|
||||
|
||||
/*!
|
||||
@brief find an element in a JSON object
|
||||
@copydoc find(KeyT&&)
|
||||
*/
|
||||
const_iterator find(StringRef key) const;
|
||||
const_iterator find(std::string_view key) const;
|
||||
|
||||
/*!
|
||||
@brief returns the number of occurrences of a key in a JSON object
|
||||
@@ -5501,7 +5500,7 @@ class json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
size_type count(StringRef key) const;
|
||||
size_type count(std::string_view key) const;
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -6113,7 +6112,7 @@ class json
|
||||
// push_back only works for null objects or objects
|
||||
if (JSON_UNLIKELY(not(is_null() or is_object())))
|
||||
{
|
||||
JSON_THROW(type_error::create(308, "cannot use push_back() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(308, "cannot use push_back() with", type_name()));
|
||||
}
|
||||
|
||||
// transform null object into an object
|
||||
@@ -6203,7 +6202,7 @@ class json
|
||||
// emplace_back only works for null objects or arrays
|
||||
if (JSON_UNLIKELY(not(is_null() or is_array())))
|
||||
{
|
||||
JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(311, "cannot use emplace_back() with", type_name()));
|
||||
}
|
||||
|
||||
// transform null object into an array
|
||||
@@ -6246,12 +6245,12 @@ class json
|
||||
@since version 2.0.8
|
||||
*/
|
||||
template<class... Args>
|
||||
std::pair<iterator, bool> emplace(StringRef key, Args&& ... args)
|
||||
std::pair<iterator, bool> emplace(std::string_view key, Args&& ... args)
|
||||
{
|
||||
// emplace only works for null objects or arrays
|
||||
if (JSON_UNLIKELY(not(is_null() or is_object())))
|
||||
{
|
||||
JSON_THROW(type_error::create(311, "cannot use emplace() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(311, "cannot use emplace() with", type_name()));
|
||||
}
|
||||
|
||||
// transform null object into an object
|
||||
@@ -6521,7 +6520,7 @@ class json
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, "cannot use swap() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(310, "cannot use swap() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6554,7 +6553,7 @@ class json
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, "cannot use swap() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(310, "cannot use swap() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6587,7 +6586,7 @@ class json
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, "cannot use swap() with " + Twine(type_name())));
|
||||
JSON_THROW(type_error::create(310, "cannot use swap() with", type_name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7011,7 +7010,7 @@ class json
|
||||
|
||||
@since version 2.0.3 (contiguous containers)
|
||||
*/
|
||||
static json parse(StringRef s,
|
||||
static json parse(std::string_view s,
|
||||
const parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true);
|
||||
|
||||
@@ -7026,7 +7025,7 @@ class json
|
||||
const parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true);
|
||||
|
||||
static bool accept(StringRef s);
|
||||
static bool accept(std::string_view s);
|
||||
|
||||
static bool accept(ArrayRef<uint8_t> arr);
|
||||
|
||||
@@ -8074,7 +8073,7 @@ if no parse error occurred.
|
||||
*/
|
||||
inline wpi::json operator "" _json(const char* s, std::size_t n)
|
||||
{
|
||||
return wpi::json::parse(wpi::StringRef(s, n));
|
||||
return wpi::json::parse(std::string_view(s, n));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -8092,7 +8091,7 @@ object if no parse error occurred.
|
||||
*/
|
||||
inline wpi::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
|
||||
{
|
||||
return wpi::json::json_pointer(wpi::StringRef(s, n));
|
||||
return wpi::json::json_pointer(std::string_view(s, n));
|
||||
}
|
||||
|
||||
#ifndef WPI_JSON_IMPLEMENTATION
|
||||
|
||||
@@ -10,13 +10,12 @@
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
@@ -100,7 +99,7 @@ class raw_istream {
|
||||
// @param buf Buffer for output
|
||||
// @param maxLen Maximum length
|
||||
// @return Line
|
||||
StringRef getline(SmallVectorImpl<char>& buf, int maxLen);
|
||||
std::string_view getline(SmallVectorImpl<char>& buf, int maxLen);
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
@@ -154,7 +153,7 @@ class raw_mem_istream : public raw_istream {
|
||||
|
||||
class raw_fd_istream : public raw_istream {
|
||||
public:
|
||||
raw_fd_istream(const Twine& filename, std::error_code& ec,
|
||||
raw_fd_istream(std::string_view filename, std::error_code& ec,
|
||||
size_t bufSize = 4096);
|
||||
raw_fd_istream(int fd, bool shouldClose, size_t bufSize = 4096);
|
||||
~raw_fd_istream() override;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -34,11 +33,6 @@ enum CreationDisposition : unsigned;
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class format_object_base;
|
||||
class FormattedString;
|
||||
class FormattedNumber;
|
||||
class FormattedBytes;
|
||||
|
||||
/// This class implements an extremely fast bulk output stream that can *only*
|
||||
/// output to a stream. It does not support seeking, reopening, rewinding, line
|
||||
/// buffered disciplines etc. It is a simple buffer that outputs
|
||||
@@ -180,21 +174,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(StringRef Str) {
|
||||
// Inline fast path, particularly for strings with a known length.
|
||||
size_t Size = Str.size();
|
||||
|
||||
// Make sure we can use the fast path.
|
||||
if (Size > (size_t)(OutBufEnd - OutBufCur))
|
||||
return write(Str.data(), Size);
|
||||
|
||||
if (Size) {
|
||||
memcpy(OutBufCur, Str.data(), Size);
|
||||
OutBufCur += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(std::string_view Str) {
|
||||
// Inline fast path, particularly for strings with a known length.
|
||||
size_t Size = Str.size();
|
||||
@@ -214,7 +193,7 @@ public:
|
||||
// Inline fast path, particularly for constant strings where a sufficiently
|
||||
// smart compiler will simplify strlen.
|
||||
|
||||
return this->operator<<(StringRef(Str));
|
||||
return this->operator<<(std::string_view(Str));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const std::string &Str) {
|
||||
@@ -235,28 +214,9 @@ public:
|
||||
return write(Arr.data(), Arr.size());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(unsigned long N);
|
||||
raw_ostream &operator<<(long N);
|
||||
raw_ostream &operator<<(unsigned long long N);
|
||||
raw_ostream &operator<<(long long N);
|
||||
raw_ostream &operator<<(const void *P);
|
||||
|
||||
raw_ostream &operator<<(unsigned int N) {
|
||||
return this->operator<<(static_cast<unsigned long>(N));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(int N) {
|
||||
return this->operator<<(static_cast<long>(N));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(double N);
|
||||
|
||||
/// Output \p N in hexadecimal, without any prefix or padding.
|
||||
raw_ostream &write_hex(unsigned long long N);
|
||||
|
||||
/// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
|
||||
/// satisfy wpi::isPrint into an escape sequence.
|
||||
raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false);
|
||||
raw_ostream &write_escaped(std::string_view Str, bool UseHexEscapes = false);
|
||||
|
||||
raw_ostream &write(unsigned char C);
|
||||
raw_ostream &write(const char *Ptr, size_t Size);
|
||||
@@ -264,18 +224,6 @@ public:
|
||||
return write(reinterpret_cast<const char *>(Ptr), Size);
|
||||
}
|
||||
|
||||
// Formatted output, see the format() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const format_object_base &Fmt);
|
||||
|
||||
// Formatted output, see the leftJustify() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedString &);
|
||||
|
||||
// Formatted output, see the formatHex() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedNumber &);
|
||||
|
||||
// Formatted output, see the format_bytes() function in Support/Format.h.
|
||||
raw_ostream &operator<<(const FormattedBytes &);
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &indent(unsigned NumSpaces);
|
||||
|
||||
@@ -443,14 +391,14 @@ public:
|
||||
/// As a special case, if Filename is "-", then the stream will use
|
||||
/// STDOUT_FILENO instead of opening a file. This will not close the stdout
|
||||
/// descriptor.
|
||||
raw_fd_ostream(StringRef Filename, std::error_code &EC);
|
||||
raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp);
|
||||
raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::FileAccess Access);
|
||||
raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::OpenFlags Flags);
|
||||
raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp, fs::FileAccess Access,
|
||||
fs::OpenFlags Flags);
|
||||
|
||||
@@ -559,8 +507,8 @@ public:
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a StringRef for the vector contents.
|
||||
StringRef str() { return StringRef(OS.data(), OS.size()); }
|
||||
/// Return a std::string_view for the vector contents.
|
||||
std::string_view str() { return std::string_view(OS.data(), OS.size()); }
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to a vector. This is a
|
||||
@@ -592,8 +540,8 @@ public:
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a StringRef for the vector contents.
|
||||
StringRef str() { return StringRef(OS.data(), OS.size()); }
|
||||
/// Return a std::string_view for the vector contents.
|
||||
std::string_view str() { return std::string_view(OS.data(), OS.size()); }
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to an SmallVector or SmallString. This is a
|
||||
@@ -658,7 +606,7 @@ public:
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a StringRef for the vector contents.
|
||||
/// Return a ArrayRef for the vector contents.
|
||||
ArrayRef<uint8_t> array() { return ArrayRef<uint8_t>(OS.data(), OS.size()); }
|
||||
};
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
template <typename T>
|
||||
@@ -34,12 +33,12 @@ class raw_istream;
|
||||
class SHA1 {
|
||||
public:
|
||||
SHA1();
|
||||
void Update(StringRef s);
|
||||
void Update(std::string_view s);
|
||||
void Update(raw_istream& is);
|
||||
std::string Final();
|
||||
StringRef Final(SmallVectorImpl<char>& buf);
|
||||
StringRef RawFinal(SmallVectorImpl<char>& buf);
|
||||
static std::string FromFile(StringRef filename);
|
||||
std::string_view Final(SmallVectorImpl<char>& buf);
|
||||
std::string_view RawFinal(SmallVectorImpl<char>& buf);
|
||||
static std::string FromFile(std::string_view filename);
|
||||
|
||||
private:
|
||||
uint32_t digest[5];
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringRef.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
@@ -30,7 +30,7 @@ class Buffer : public uv_buf_t {
|
||||
base = oth.base;
|
||||
len = oth.len;
|
||||
}
|
||||
/*implicit*/ Buffer(StringRef str) // NOLINT
|
||||
/*implicit*/ Buffer(std::string_view str) // NOLINT
|
||||
: Buffer{str.data(), str.size()} {}
|
||||
/*implicit*/ Buffer(ArrayRef<uint8_t> arr) // NOLINT
|
||||
: Buffer{reinterpret_cast<const char*>(arr.data()), arr.size()} {}
|
||||
@@ -51,7 +51,7 @@ class Buffer : public uv_buf_t {
|
||||
|
||||
static Buffer Allocate(size_t size) { return Buffer{new char[size], size}; }
|
||||
|
||||
static Buffer Dup(StringRef in) {
|
||||
static Buffer Dup(std::string_view in) {
|
||||
Buffer buf = Allocate(in.size());
|
||||
std::memcpy(buf.base, in.data(), in.size());
|
||||
return buf;
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
@@ -51,7 +51,7 @@ class FsEvent final : public HandleImpl<FsEvent, uv_fs_event_t> {
|
||||
* @param events Bitmask of event flags. Only UV_FS_EVENT_RECURSIVE is
|
||||
* supported (and only on OSX and Windows).
|
||||
*/
|
||||
void Start(const Twine& path, unsigned int flags = 0);
|
||||
void Start(std::string_view path, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Stop watching for changes.
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
@@ -40,7 +40,7 @@ class GetAddrInfoReq : public RequestImpl<GetAddrInfoReq, uv_getaddrinfo_t> {
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
* Either node or service may be empty but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
@@ -50,7 +50,7 @@ class GetAddrInfoReq : public RequestImpl<GetAddrInfoReq, uv_getaddrinfo_t> {
|
||||
* type constraints.
|
||||
*/
|
||||
void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
const Twine& node, const Twine& service = Twine::createNull(),
|
||||
std::string_view node, std::string_view service = {},
|
||||
const addrinfo* hints = nullptr);
|
||||
|
||||
/**
|
||||
@@ -58,7 +58,7 @@ void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
* request when the resolution completes. HandleError() is called on the
|
||||
* request if any errors occur.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
* Either node or service may be empty but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param req request
|
||||
@@ -69,8 +69,7 @@ void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
*/
|
||||
inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<GetAddrInfoReq>& req,
|
||||
const Twine& node,
|
||||
const Twine& service = Twine::createNull(),
|
||||
std::string_view node, std::string_view service = {},
|
||||
const addrinfo* hints = nullptr) {
|
||||
GetAddrInfo(*loop, req, node, service, hints);
|
||||
}
|
||||
@@ -80,7 +79,7 @@ inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
|
||||
* completes, and errors are forwarded to the loop. This is a convenience
|
||||
* wrapper.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
* Either node or service may be empty but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
@@ -90,7 +89,7 @@ inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
|
||||
* type constraints.
|
||||
*/
|
||||
void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
|
||||
const Twine& node, const Twine& service = Twine::createNull(),
|
||||
std::string_view node, std::string_view service = {},
|
||||
const addrinfo* hints = nullptr);
|
||||
|
||||
/**
|
||||
@@ -98,7 +97,7 @@ void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
|
||||
* completes, and errors are forwarded to the loop. This is a convenience
|
||||
* wrapper.
|
||||
*
|
||||
* Either node or service may be null (`Twine::createNull()`) but not both.
|
||||
* Either node or service may be empty but not both.
|
||||
*
|
||||
* @param loop Event loop
|
||||
* @param callback Callback function to call when resolution completes
|
||||
@@ -109,8 +108,7 @@ void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
|
||||
*/
|
||||
inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void(const addrinfo&)> callback,
|
||||
const Twine& node,
|
||||
const Twine& service = Twine::createNull(),
|
||||
std::string_view node, std::string_view service = {},
|
||||
const addrinfo* hints = nullptr) {
|
||||
GetAddrInfo(*loop, callback, node, service, hints);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
@@ -105,7 +105,7 @@ inline void GetNameInfo(const std::shared_ptr<Loop>& loop,
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
std::string_view ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv4 getnameinfo(3). HandleResolvedName() is called on the
|
||||
@@ -120,7 +120,8 @@ void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
*/
|
||||
inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
std::string_view ip, unsigned int port,
|
||||
int flags = 0) {
|
||||
return GetNameInfo4(*loop, req, ip, port, flags);
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
|
||||
*/
|
||||
void GetNameInfo4(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
std::string_view ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv4 getnameinfo(3). The callback is called when the resolution
|
||||
@@ -151,7 +152,8 @@ void GetNameInfo4(Loop& loop,
|
||||
*/
|
||||
inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
std::string_view ip, unsigned int port,
|
||||
int flags = 0) {
|
||||
return GetNameInfo4(*loop, callback, ip, port, flags);
|
||||
}
|
||||
|
||||
@@ -167,7 +169,7 @@ inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
|
||||
* @param flags Optional flags to modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
std::string_view ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv6 getnameinfo(3). HandleResolvedName() is called on the
|
||||
@@ -182,7 +184,8 @@ void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
|
||||
*/
|
||||
inline void GetNameInfo6(const std::shared_ptr<Loop>& loop,
|
||||
const std::shared_ptr<GetNameInfoReq>& req,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
std::string_view ip, unsigned int port,
|
||||
int flags = 0) {
|
||||
GetNameInfo6(*loop, req, ip, port, flags);
|
||||
}
|
||||
|
||||
@@ -199,7 +202,7 @@ inline void GetNameInfo6(const std::shared_ptr<Loop>& loop,
|
||||
*/
|
||||
void GetNameInfo6(Loop& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0);
|
||||
std::string_view ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* Asynchronous IPv6 getnameinfo(3). The callback is called when the resolution
|
||||
@@ -214,7 +217,8 @@ void GetNameInfo6(Loop& loop,
|
||||
*/
|
||||
inline void GetNameInfo6(const std::shared_ptr<Loop>& loop,
|
||||
std::function<void(const char*, const char*)> callback,
|
||||
const Twine& ip, unsigned int port, int flags = 0) {
|
||||
std::string_view ip, unsigned int port,
|
||||
int flags = 0) {
|
||||
return GetNameInfo6(*loop, callback, ip, port, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/uv/Buffer.h"
|
||||
#include "wpi/uv/Error.h"
|
||||
#include "wpi/uv/Loop.h"
|
||||
@@ -50,7 +50,7 @@ class Handle : public std::enable_shared_from_this<Handle> {
|
||||
/**
|
||||
* Get the name of the type of the handle. E.g. "pipe" for pipe handles.
|
||||
*/
|
||||
StringRef GetTypeName() const noexcept {
|
||||
std::string_view GetTypeName() const noexcept {
|
||||
return uv_handle_type_name(m_uv_handle->type);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/NetworkStream.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
@@ -119,7 +119,7 @@ class Pipe final : public NetworkStreamImpl<Pipe, uv_pipe_t> {
|
||||
*
|
||||
* @param name File path (Unix) or name (Windows).
|
||||
*/
|
||||
void Bind(const Twine& name);
|
||||
void Bind(std::string_view name);
|
||||
|
||||
/**
|
||||
* Connect to the Unix domain socket or the named pipe.
|
||||
@@ -135,7 +135,8 @@ class Pipe final : public NetworkStreamImpl<Pipe, uv_pipe_t> {
|
||||
* @param name File path (Unix) or name (Windows).
|
||||
* @param req connection request
|
||||
*/
|
||||
void Connect(const Twine& name, const std::shared_ptr<PipeConnectReq>& req);
|
||||
void Connect(std::string_view name,
|
||||
const std::shared_ptr<PipeConnectReq>& req);
|
||||
|
||||
/**
|
||||
* Connect to the Unix domain socket or the named pipe.
|
||||
@@ -149,7 +150,7 @@ class Pipe final : public NetworkStreamImpl<Pipe, uv_pipe_t> {
|
||||
* @param name File path (Unix) or name (Windows).
|
||||
* @param callback Callback function to call when connection established
|
||||
*/
|
||||
void Connect(const Twine& name, std::function<void()> callback);
|
||||
void Connect(std::string_view name, std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* Get the name of the Unix domain socket or the named pipe.
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
@@ -35,9 +35,9 @@ class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
~Process() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Structure for Spawn() option temporaries. This is a reference type
|
||||
* similar to StringRef, so if this value is stored outside of a temporary,
|
||||
* be careful about overwriting what it points to.
|
||||
* Structure for Spawn() option temporaries. This is a reference type, so if
|
||||
* this value is stored outside of a temporary, be careful about overwriting
|
||||
* what it points to.
|
||||
*/
|
||||
struct Option {
|
||||
enum Type {
|
||||
@@ -65,7 +65,7 @@ class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
m_data.str = arg.data();
|
||||
}
|
||||
|
||||
/*implicit*/ Option(StringRef arg) // NOLINT
|
||||
/*implicit*/ Option(std::string_view arg) // NOLINT
|
||||
: m_strData(arg) {
|
||||
m_data.str = m_strData.c_str();
|
||||
}
|
||||
@@ -75,11 +75,6 @@ class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
m_data.str = m_strData.c_str();
|
||||
}
|
||||
|
||||
/*implicit*/ Option(const Twine& arg) // NOLINT
|
||||
: m_strData(arg.str()) {
|
||||
m_data.str = m_strData.c_str();
|
||||
}
|
||||
|
||||
explicit Option(Type type) : m_type(type) {}
|
||||
|
||||
Type m_type = kArg;
|
||||
@@ -105,9 +100,9 @@ class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
* environment is used.
|
||||
* @param env environment variable
|
||||
*/
|
||||
static Option Env(const Twine& env) {
|
||||
static Option Env(std::string_view env) {
|
||||
Option o(Option::kEnv);
|
||||
o.m_strData = env.str();
|
||||
o.m_strData = env;
|
||||
o.m_data.str = o.m_strData.c_str();
|
||||
return o;
|
||||
}
|
||||
@@ -116,9 +111,9 @@ class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
* Set the current working directory for the subprocess.
|
||||
* @param cwd current working directory
|
||||
*/
|
||||
static Option Cwd(const Twine& cwd) {
|
||||
static Option Cwd(std::string_view cwd) {
|
||||
Option o(Option::kCwd);
|
||||
o.m_strData = cwd.str();
|
||||
o.m_strData = cwd;
|
||||
o.m_data.str = o.m_strData.c_str();
|
||||
return o;
|
||||
}
|
||||
@@ -236,16 +231,17 @@ class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
* @param file Path pointing to the program to be executed
|
||||
* @param options Process options
|
||||
*/
|
||||
static std::shared_ptr<Process> SpawnArray(Loop& loop, const Twine& file,
|
||||
static std::shared_ptr<Process> SpawnArray(Loop& loop, std::string_view file,
|
||||
ArrayRef<Option> options);
|
||||
|
||||
static std::shared_ptr<Process> SpawnArray(
|
||||
Loop& loop, const Twine& file, std::initializer_list<Option> options) {
|
||||
Loop& loop, std::string_view file,
|
||||
std::initializer_list<Option> options) {
|
||||
return SpawnArray(loop, file, makeArrayRef(options.begin(), options.end()));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static std::shared_ptr<Process> Spawn(Loop& loop, const Twine& file,
|
||||
static std::shared_ptr<Process> Spawn(Loop& loop, std::string_view file,
|
||||
const Args&... options) {
|
||||
return SpawnArray(loop, file, {options...});
|
||||
}
|
||||
@@ -264,20 +260,20 @@ class Process final : public HandleImpl<Process, uv_process_t> {
|
||||
* @param options Process options
|
||||
*/
|
||||
static std::shared_ptr<Process> SpawnArray(const std::shared_ptr<Loop>& loop,
|
||||
const Twine& file,
|
||||
std::string_view file,
|
||||
ArrayRef<Option> options) {
|
||||
return SpawnArray(*loop, file, options);
|
||||
}
|
||||
|
||||
static std::shared_ptr<Process> SpawnArray(
|
||||
const std::shared_ptr<Loop>& loop, const Twine& file,
|
||||
const std::shared_ptr<Loop>& loop, std::string_view file,
|
||||
std::initializer_list<Option> options) {
|
||||
return SpawnArray(*loop, file, options);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static std::shared_ptr<Process> Spawn(const std::shared_ptr<Loop>& loop,
|
||||
const Twine& file,
|
||||
std::string_view file,
|
||||
const Args&... options) {
|
||||
return SpawnArray(*loop, file, {options...});
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/NetworkStream.h"
|
||||
|
||||
namespace wpi::uv {
|
||||
@@ -185,7 +185,7 @@ class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
void Bind(std::string_view ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv6 address and port.
|
||||
@@ -201,7 +201,7 @@ class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind6(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
void Bind6(std::string_view ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Get the current address to which the handle is bound.
|
||||
@@ -281,7 +281,7 @@ class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
|
||||
* @param port The port to which to connect to.
|
||||
* @param req connection request
|
||||
*/
|
||||
void Connect(const Twine& ip, unsigned int port,
|
||||
void Connect(std::string_view ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req);
|
||||
|
||||
/**
|
||||
@@ -298,7 +298,7 @@ class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
|
||||
* @param port The port to which to connect to.
|
||||
* @param callback Callback function to call when connection established
|
||||
*/
|
||||
void Connect(const Twine& ip, unsigned int port,
|
||||
void Connect(std::string_view ip, unsigned int port,
|
||||
std::function<void()> callback);
|
||||
|
||||
/**
|
||||
@@ -317,7 +317,7 @@ class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
|
||||
* @param port The port to which to connect to.
|
||||
* @param req connection request
|
||||
*/
|
||||
void Connect6(const Twine& ip, unsigned int port,
|
||||
void Connect6(std::string_view ip, unsigned int port,
|
||||
const std::shared_ptr<TcpConnectReq>& req);
|
||||
|
||||
/**
|
||||
@@ -334,7 +334,7 @@ class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
|
||||
* @param port The port to which to connect to.
|
||||
* @param callback Callback function to call when connection established
|
||||
*/
|
||||
void Connect6(const Twine& ip, unsigned int port,
|
||||
void Connect6(std::string_view ip, unsigned int port,
|
||||
std::function<void()> callback);
|
||||
|
||||
private:
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
#include "wpi/uv/Request.h"
|
||||
|
||||
@@ -100,7 +100,7 @@ class Udp final : public HandleImpl<Udp, uv_udp_t> {
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
void Bind(std::string_view ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Bind the handle to an IPv6 address and port.
|
||||
@@ -109,7 +109,7 @@ class Udp final : public HandleImpl<Udp, uv_udp_t> {
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Bind6(const Twine& ip, unsigned int port, unsigned int flags = 0);
|
||||
void Bind6(std::string_view ip, unsigned int port, unsigned int flags = 0);
|
||||
|
||||
/**
|
||||
* Associate the handle to a remote address and port, so every message sent
|
||||
@@ -136,7 +136,7 @@ class Udp final : public HandleImpl<Udp, uv_udp_t> {
|
||||
* @param ip The address to which to bind.
|
||||
* @param port The port to which to bind.
|
||||
*/
|
||||
void Connect(const Twine& ip, unsigned int port);
|
||||
void Connect(std::string_view ip, unsigned int port);
|
||||
|
||||
/**
|
||||
* Associate the handle to an IPv6 address and port, so every message sent
|
||||
@@ -146,7 +146,7 @@ class Udp final : public HandleImpl<Udp, uv_udp_t> {
|
||||
* @param port The port to which to bind.
|
||||
* @param flags Optional additional flags.
|
||||
*/
|
||||
void Connect6(const Twine& ip, unsigned int port);
|
||||
void Connect6(std::string_view ip, unsigned int port);
|
||||
|
||||
/**
|
||||
* Get the remote IP and port on connected UDP handles.
|
||||
@@ -167,8 +167,8 @@ class Udp final : public HandleImpl<Udp, uv_udp_t> {
|
||||
* @param interfaceAddr Interface address
|
||||
* @param membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP
|
||||
*/
|
||||
void SetMembership(const Twine& multicastAddr, const Twine& interfaceAddr,
|
||||
uv_membership membership);
|
||||
void SetMembership(std::string_view multicastAddr,
|
||||
std::string_view interfaceAddr, uv_membership membership);
|
||||
|
||||
/**
|
||||
* Set IP multicast loop flag. Makes multicast packets loop back to local
|
||||
@@ -194,7 +194,7 @@ class Udp final : public HandleImpl<Udp, uv_udp_t> {
|
||||
*
|
||||
* @param interfaceAddr Interface address
|
||||
*/
|
||||
void SetMulticastInterface(const Twine& interfaceAddr);
|
||||
void SetMulticastInterface(std::string_view interfaceAddr);
|
||||
|
||||
/**
|
||||
* Set broadcast on or off.
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi::uv {
|
||||
|
||||
@@ -116,7 +115,7 @@ int AddrToName(const in6_addr& addr, T* ip) {
|
||||
* @param addr Output binary structure
|
||||
* @return Error (same as `uv_ip4_addr()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in* addr);
|
||||
int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in* addr);
|
||||
|
||||
/**
|
||||
* Convert a string containing an IPv6 address to a binary structure.
|
||||
@@ -125,7 +124,7 @@ int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in* addr);
|
||||
* @param addr Output binary structure
|
||||
* @return Error (same as `uv_ip6_addr()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in6* addr);
|
||||
int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in6* addr);
|
||||
|
||||
/**
|
||||
* Convert a string containing an IPv4 address to binary format.
|
||||
@@ -133,7 +132,7 @@ int NameToAddr(const Twine& ip, unsigned int port, sockaddr_in6* addr);
|
||||
* @param addr Output binary
|
||||
* @return Error (same as `uv_inet_pton()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, in_addr* addr);
|
||||
int NameToAddr(std::string_view ip, in_addr* addr);
|
||||
|
||||
/**
|
||||
* Convert a string containing an IPv6 address to binary format.
|
||||
@@ -141,7 +140,7 @@ int NameToAddr(const Twine& ip, in_addr* addr);
|
||||
* @param addr Output binary
|
||||
* @return Error (same as `uv_inet_pton()`).
|
||||
*/
|
||||
int NameToAddr(const Twine& ip, in6_addr* addr);
|
||||
int NameToAddr(std::string_view ip, in6_addr* addr);
|
||||
|
||||
} // namespace wpi::uv
|
||||
|
||||
|
||||
@@ -12,14 +12,12 @@
|
||||
|
||||
namespace wpi {
|
||||
|
||||
std::string Demangle(const Twine& mangledSymbol) {
|
||||
SmallString<128> buf;
|
||||
std::string Demangle(std::string_view mangledSymbol) {
|
||||
SmallString<128> buf{mangledSymbol};
|
||||
size_t length;
|
||||
int32_t status;
|
||||
|
||||
char* symbol =
|
||||
abi::__cxa_demangle(mangledSymbol.toNullTerminatedStringRef(buf).data(),
|
||||
nullptr, &length, &status);
|
||||
char* symbol = abi::__cxa_demangle(buf.c_str(), nullptr, &length, &status);
|
||||
if (status == 0) {
|
||||
std::string rv{symbol};
|
||||
std::free(symbol);
|
||||
@@ -27,7 +25,7 @@ std::string Demangle(const Twine& mangledSymbol) {
|
||||
}
|
||||
|
||||
// If everything else failed, just return the mangled symbol
|
||||
return mangledSymbol.str();
|
||||
return std::string{mangledSymbol};
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "wpi/Demangle.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
@@ -24,19 +24,18 @@ std::string GetStackTrace(int offset) {
|
||||
// Only print recursive functions once in a row.
|
||||
if (i == 0 || stackTrace[i] != stackTrace[i - 1]) {
|
||||
// extract just function name from "pathToExe(functionName+offset)"
|
||||
StringRef sym{mangledSymbols[i]};
|
||||
sym = sym.split('(').second;
|
||||
StringRef offset;
|
||||
std::tie(sym, offset) = sym.split('+');
|
||||
StringRef addr;
|
||||
std::tie(offset, addr) = offset.split(')');
|
||||
std::string_view sym = split(mangledSymbols[i], '(').second;
|
||||
std::string_view offset;
|
||||
std::tie(sym, offset) = split(sym, '+');
|
||||
std::string_view addr;
|
||||
std::tie(offset, addr) = split(offset, ')');
|
||||
trace << "\tat " << Demangle(sym) << " + " << offset << addr << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::free(mangledSymbols);
|
||||
|
||||
return trace.str();
|
||||
return std::string{trace.str()};
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
@@ -15,16 +15,15 @@
|
||||
|
||||
namespace wpi {
|
||||
|
||||
std::string Demangle(const Twine& mangledSymbol) {
|
||||
std::string Demangle(std::string_view mangledSymbol) {
|
||||
static wpi::mutex m;
|
||||
std::scoped_lock lock(m);
|
||||
SmallString<128> buf;
|
||||
SmallString<128> buf{mangledSymbol};
|
||||
char buffer[256];
|
||||
DWORD sz =
|
||||
UnDecorateSymbolName(mangledSymbol.toNullTerminatedStringRef(buf).data(),
|
||||
buffer, sizeof(buffer), UNDNAME_COMPLETE);
|
||||
DWORD sz = UnDecorateSymbolName(buf.c_str(), buffer, sizeof(buffer),
|
||||
UNDNAME_COMPLETE);
|
||||
if (sz == 0)
|
||||
return mangledSymbol.str();
|
||||
return std::string{mangledSymbol};
|
||||
return std::string(buffer, sz);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user