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:
Peter Johnson
2021-06-06 16:13:58 -07:00
committed by GitHub
parent 4f1cecb8e7
commit b2c3b2dd8e
441 changed files with 5061 additions and 9749 deletions

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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

View 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());
}

View File

@@ -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();

View File

@@ -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},

View File

@@ -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 <>

View File

@@ -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;
}

View File

@@ -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

View File

@@ -168,7 +168,7 @@ void TCPStream::close() {
m_sd = -1;
}
StringRef TCPStream::getPeerIP() const {
std::string_view TCPStream::getPeerIP() const {
return m_peerIP;
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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";
}

View File

@@ -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

View File

@@ -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},

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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())));
}
}

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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());
}

View File

@@ -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());
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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) {}

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,