mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
Use std::string_view and fmtlib across all libraries (#3402)
- Twine, StringRef, Format, and NativeFormatting have been removed - Logging now uses fmtlib style formatting - Nearly all uses of wpi::outs/errs have been replaced with fmt::print() or std::puts()/std::fputs() (for unformatted strings). - A wpi/fmt/raw_ostream.h header has been added to enable fmt::print() with wpi::raw_ostream
This commit is contained in:
@@ -744,10 +744,10 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
|
||||
namespace sys {
|
||||
namespace windows {
|
||||
std::error_code CodePageToUTF16(unsigned codepage,
|
||||
wpi::StringRef original,
|
||||
std::string_view original,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
if (!original.empty()) {
|
||||
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
|
||||
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), 0);
|
||||
|
||||
if (len == 0) {
|
||||
@@ -757,7 +757,7 @@ std::error_code CodePageToUTF16(unsigned codepage,
|
||||
utf16.reserve(len + 1);
|
||||
utf16.set_size(len);
|
||||
|
||||
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
|
||||
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), utf16.size());
|
||||
|
||||
if (len == 0) {
|
||||
@@ -772,12 +772,12 @@ std::error_code CodePageToUTF16(unsigned codepage,
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code UTF8ToUTF16(wpi::StringRef utf8,
|
||||
std::error_code UTF8ToUTF16(std::string_view utf8,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_UTF8, utf8, utf16);
|
||||
}
|
||||
|
||||
std::error_code CurCPToUTF16(wpi::StringRef curcp,
|
||||
std::error_code CurCPToUTF16(std::string_view curcp,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_ACP, curcp, utf16);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ bool convertUTF16ToUTF8String(ArrayRef<UTF16> SrcUTF16,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertUTF8ToUTF16String(StringRef SrcUTF8,
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16) {
|
||||
assert(DstUTF16.empty());
|
||||
|
||||
@@ -91,8 +91,8 @@ bool convertUTF8ToUTF16String(StringRef SrcUTF8,
|
||||
return true;
|
||||
}
|
||||
|
||||
const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.begin());
|
||||
const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.end());
|
||||
const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.data());
|
||||
const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.data() + SrcUTF8.size());
|
||||
|
||||
// Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding
|
||||
// as UTF-16 should always require the same amount or less code units than the
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
//===----- lib/Support/Error.cpp - Error and associated utilities ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/Error.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/ManagedStatic.h"
|
||||
#include <system_error>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
namespace {
|
||||
|
||||
enum class ErrorErrorCode : int {
|
||||
MultipleErrors = 1,
|
||||
FileError,
|
||||
InconvertibleError
|
||||
};
|
||||
|
||||
// FIXME: This class is only here to support the transition to wpi::Error. It
|
||||
// will be removed once this transition is complete. Clients should prefer to
|
||||
// deal with the Error value directly, rather than converting to error_code.
|
||||
class ErrorErrorCategory : public std::error_category {
|
||||
public:
|
||||
const char *name() const noexcept override { return "Error"; }
|
||||
|
||||
std::string message(int condition) const override {
|
||||
switch (static_cast<ErrorErrorCode>(condition)) {
|
||||
case ErrorErrorCode::MultipleErrors:
|
||||
return "Multiple errors";
|
||||
case ErrorErrorCode::InconvertibleError:
|
||||
return "Inconvertible error value. An error has occurred that could "
|
||||
"not be converted to a known std::error_code. Please file a "
|
||||
"bug.";
|
||||
case ErrorErrorCode::FileError:
|
||||
return "A file error occurred.";
|
||||
}
|
||||
wpi_unreachable("Unhandled error code");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
|
||||
|
||||
namespace wpi {
|
||||
|
||||
void ErrorInfoBase::anchor() {}
|
||||
char ErrorInfoBase::ID = 0;
|
||||
char ErrorList::ID = 0;
|
||||
void ECError::anchor() {}
|
||||
char ECError::ID = 0;
|
||||
char StringError::ID = 0;
|
||||
char FileError::ID = 0;
|
||||
|
||||
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {
|
||||
if (!E)
|
||||
return;
|
||||
OS << ErrorBanner;
|
||||
handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
|
||||
EI.log(OS);
|
||||
OS << "\n";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
std::error_code ErrorList::convertToErrorCode() const {
|
||||
return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
|
||||
*ErrorErrorCat);
|
||||
}
|
||||
|
||||
std::error_code inconvertibleErrorCode() {
|
||||
return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError),
|
||||
*ErrorErrorCat);
|
||||
}
|
||||
|
||||
std::error_code FileError::convertToErrorCode() const {
|
||||
return std::error_code(static_cast<int>(ErrorErrorCode::FileError),
|
||||
*ErrorErrorCat);
|
||||
}
|
||||
|
||||
Error errorCodeToError(std::error_code EC) {
|
||||
if (!EC)
|
||||
return Error::success();
|
||||
return Error(std::make_unique<ECError>(ECError(EC)));
|
||||
}
|
||||
|
||||
std::error_code errorToErrorCode(Error Err) {
|
||||
std::error_code EC;
|
||||
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
|
||||
EC = EI.convertToErrorCode();
|
||||
});
|
||||
if (EC == inconvertibleErrorCode())
|
||||
report_fatal_error(EC.message());
|
||||
return EC;
|
||||
}
|
||||
|
||||
StringError::StringError(std::error_code EC, const Twine &S)
|
||||
: Msg(S.str()), EC(EC) {}
|
||||
|
||||
StringError::StringError(const Twine &S, std::error_code EC)
|
||||
: Msg(S.str()), EC(EC), PrintMsgOnly(true) {}
|
||||
|
||||
void StringError::log(raw_ostream &OS) const {
|
||||
if (PrintMsgOnly) {
|
||||
OS << Msg;
|
||||
} else {
|
||||
OS << EC.message();
|
||||
if (!Msg.empty())
|
||||
OS << (" " + Msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code StringError::convertToErrorCode() const {
|
||||
return EC;
|
||||
}
|
||||
|
||||
Error createStringError(std::error_code EC, char const *Msg) {
|
||||
return make_error<StringError>(Msg, EC);
|
||||
}
|
||||
|
||||
void report_fatal_error(Error Err, bool GenCrashDiag) {
|
||||
assert(Err && "report_fatal_error called with success value");
|
||||
std::string ErrMsg;
|
||||
{
|
||||
raw_string_ostream ErrStream(ErrMsg);
|
||||
logAllUnhandledErrors(std::move(Err), ErrStream);
|
||||
}
|
||||
report_fatal_error(ErrMsg);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
@@ -14,11 +14,10 @@
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/Error.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "fmt/format.h"
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
@@ -68,18 +67,14 @@ void wpi::remove_fatal_error_handler() {
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const char *Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
|
||||
void wpi::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
|
||||
wpi::fatal_error_handler_t handler = nullptr;
|
||||
void* handlerData = nullptr;
|
||||
{
|
||||
@@ -91,21 +86,9 @@ void wpi::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(handlerData, Reason.str(), GenCrashDiag);
|
||||
handler(handlerData, std::string{Reason}, GenCrashDiag);
|
||||
} else {
|
||||
// Blast the result out to stderr. We don't try hard to make sure this
|
||||
// succeeds (e.g. handling EINTR) and we can't use errs() here because
|
||||
// raw ostreams can call report_fatal_error.
|
||||
SmallVector<char, 64> Buffer;
|
||||
raw_svector_ostream OS(Buffer);
|
||||
OS << "LLVM ERROR: " << Reason << "\n";
|
||||
StringRef MessageStr = OS.str();
|
||||
#ifdef _WIN32
|
||||
int written = ::_write(2, MessageStr.data(), MessageStr.size());
|
||||
#else
|
||||
ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
|
||||
#endif
|
||||
(void)written; // If something went wrong, we deliberately just give up.
|
||||
fmt::print(stderr, "LLVM ERROR: {}\n");
|
||||
}
|
||||
|
||||
exit(1);
|
||||
@@ -185,11 +168,11 @@ void wpi::wpi_unreachable_internal(const char *msg, const char *file,
|
||||
// wpi_unreachable is intended to be used to indicate "impossible"
|
||||
// situations, and not legitimate runtime errors.
|
||||
if (msg)
|
||||
errs() << msg << "\n";
|
||||
errs() << "UNREACHABLE executed";
|
||||
fmt::print(stderr, "{}\n", msg);
|
||||
std::fputs("UNREACHABLE executed", stderr);
|
||||
if (file)
|
||||
errs() << " at " << file << ":" << line;
|
||||
errs() << "!\n";
|
||||
fmt::print(stderr, " at {}:{}", file, line);
|
||||
fmt::print(stderr, "{}", "!\n");
|
||||
abort();
|
||||
#ifdef LLVM_BUILTIN_UNREACHABLE
|
||||
// Windows systems and possibly others don't declare abort() to be noreturn,
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/NativeFormatting.h"
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Format.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
static int format_to_buffer(T Value, char (&Buffer)[N]) {
|
||||
char *EndPtr = std::end(Buffer);
|
||||
char *CurPtr = EndPtr;
|
||||
|
||||
do {
|
||||
*--CurPtr = '0' + char(Value % 10);
|
||||
Value /= 10;
|
||||
} while (Value);
|
||||
return EndPtr - CurPtr;
|
||||
}
|
||||
|
||||
static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
|
||||
assert(!Buffer.empty());
|
||||
|
||||
ArrayRef<char> ThisGroup;
|
||||
int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
|
||||
ThisGroup = Buffer.take_front(InitialDigits);
|
||||
S.write(ThisGroup.data(), ThisGroup.size());
|
||||
|
||||
Buffer = Buffer.drop_front(InitialDigits);
|
||||
assert(Buffer.size() % 3 == 0);
|
||||
while (!Buffer.empty()) {
|
||||
S << ',';
|
||||
ThisGroup = Buffer.take_front(3);
|
||||
S.write(ThisGroup.data(), 3);
|
||||
Buffer = Buffer.drop_front(3);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style, bool IsNegative) {
|
||||
static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
|
||||
|
||||
char NumberBuffer[128];
|
||||
std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
|
||||
|
||||
size_t Len = 0;
|
||||
Len = format_to_buffer(N, NumberBuffer);
|
||||
|
||||
if (IsNegative)
|
||||
S << '-';
|
||||
|
||||
if (Len < MinDigits && Style != IntegerStyle::Number) {
|
||||
for (size_t I = Len; I < MinDigits; ++I)
|
||||
S << '0';
|
||||
}
|
||||
|
||||
if (Style == IntegerStyle::Number) {
|
||||
writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
|
||||
} else {
|
||||
S.write(std::end(NumberBuffer) - Len, Len);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style, bool IsNegative = false) {
|
||||
// Output using 32-bit div/mod if possible.
|
||||
if (N == static_cast<uint32_t>(N))
|
||||
write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
|
||||
IsNegative);
|
||||
else
|
||||
write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_signed(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
static_assert(std::is_signed<T>::value, "Value is not signed!");
|
||||
|
||||
using UnsignedT = typename std::make_unsigned<T>::type;
|
||||
|
||||
if (N >= 0) {
|
||||
write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
|
||||
return;
|
||||
}
|
||||
|
||||
UnsignedT UN = -(UnsignedT)N;
|
||||
write_unsigned(S, UN, MinDigits, Style, true);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, int N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, long long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
|
||||
std::optional<size_t> Width) {
|
||||
const size_t kMaxWidth = 128u;
|
||||
|
||||
size_t W = std::min(kMaxWidth, Width.value_or(0u));
|
||||
|
||||
unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
|
||||
bool Prefix = (Style == HexPrintStyle::PrefixLower ||
|
||||
Style == HexPrintStyle::PrefixUpper);
|
||||
bool Upper =
|
||||
(Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
|
||||
unsigned PrefixChars = Prefix ? 2 : 0;
|
||||
unsigned NumChars =
|
||||
std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
|
||||
|
||||
char NumberBuffer[kMaxWidth];
|
||||
::memset(NumberBuffer, '0', wpi::array_lengthof(NumberBuffer));
|
||||
if (Prefix)
|
||||
NumberBuffer[1] = 'x';
|
||||
char *EndPtr = NumberBuffer + NumChars;
|
||||
char *CurPtr = EndPtr;
|
||||
while (N) {
|
||||
unsigned char x = static_cast<unsigned char>(N) % 16;
|
||||
*--CurPtr = hexdigit(x, !Upper);
|
||||
N /= 16;
|
||||
}
|
||||
|
||||
S.write(NumberBuffer, NumChars);
|
||||
}
|
||||
|
||||
void wpi::write_double(raw_ostream &S, double N, FloatStyle Style,
|
||||
std::optional<size_t> Precision) {
|
||||
size_t Prec = Precision.value_or(getDefaultPrecision(Style));
|
||||
|
||||
if (std::isnan(N)) {
|
||||
S << "nan";
|
||||
return;
|
||||
} else if (std::isinf(N)) {
|
||||
S << "INF";
|
||||
return;
|
||||
}
|
||||
|
||||
char Letter;
|
||||
if (Style == FloatStyle::Exponent)
|
||||
Letter = 'e';
|
||||
else if (Style == FloatStyle::ExponentUpper)
|
||||
Letter = 'E';
|
||||
else
|
||||
Letter = 'f';
|
||||
|
||||
SmallString<8> Spec;
|
||||
wpi::raw_svector_ostream Out(Spec);
|
||||
Out << "%." << Prec << Letter;
|
||||
|
||||
if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
|
||||
#ifdef _WIN32
|
||||
// On MSVCRT and compatible, output of %e is incompatible to Posix
|
||||
// by default. Number of exponent digits should be at least 2. "%+03d"
|
||||
// FIXME: Implement our formatter to here or Support/Format.h!
|
||||
#if defined(__MINGW32__)
|
||||
// FIXME: It should be generic to C++11.
|
||||
if (N == 0.0 && std::signbit(N)) {
|
||||
char NegativeZero[] = "-0.000000e+00";
|
||||
if (Style == FloatStyle::ExponentUpper)
|
||||
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
||||
S << NegativeZero;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
int fpcl = _fpclass(N);
|
||||
|
||||
// negative zero
|
||||
if (fpcl == _FPCLASS_NZ) {
|
||||
char NegativeZero[] = "-0.000000e+00";
|
||||
if (Style == FloatStyle::ExponentUpper)
|
||||
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
||||
S << NegativeZero;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
char buf[32];
|
||||
unsigned len;
|
||||
len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
|
||||
if (len <= sizeof(buf) - 2) {
|
||||
if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
|
||||
buf[len - 3] == '0') {
|
||||
int cs = buf[len - 4];
|
||||
if (cs == '+' || cs == '-') {
|
||||
int c1 = buf[len - 2];
|
||||
int c0 = buf[len - 1];
|
||||
if (isdigit(static_cast<unsigned char>(c1)) &&
|
||||
isdigit(static_cast<unsigned char>(c0))) {
|
||||
// Trim leading '0': "...e+012" -> "...e+12\0"
|
||||
buf[len - 3] = c1;
|
||||
buf[len - 2] = c0;
|
||||
buf[--len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
S << buf;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Style == FloatStyle::Percent)
|
||||
N *= 100.0;
|
||||
|
||||
char Buf[32];
|
||||
format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
|
||||
S << Buf;
|
||||
if (Style == FloatStyle::Percent)
|
||||
S << '%';
|
||||
}
|
||||
|
||||
bool wpi::isPrefixedHexStyle(HexPrintStyle S) {
|
||||
return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
|
||||
}
|
||||
|
||||
size_t wpi::getDefaultPrecision(FloatStyle Style) {
|
||||
switch (Style) {
|
||||
case FloatStyle::Exponent:
|
||||
case FloatStyle::ExponentUpper:
|
||||
return 6; // Number of decimal places.
|
||||
case FloatStyle::Fixed:
|
||||
case FloatStyle::Percent:
|
||||
return 2; // Number of decimal places.
|
||||
}
|
||||
LLVM_BUILTIN_UNREACHABLE;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ void StringMapImpl::init(unsigned InitSize) {
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) { // Hash table unallocated so far?
|
||||
init(16);
|
||||
@@ -128,7 +128,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
// Do the comparison like this because Name isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char*)BucketItem+ItemSize;
|
||||
if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) {
|
||||
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int StringMapImpl::FindKey(StringRef Key) const {
|
||||
int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) return -1; // Really empty table?
|
||||
unsigned FullHashValue = HashString(Key);
|
||||
@@ -171,7 +171,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
|
||||
// Do the comparison like this because NameStart isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char*)BucketItem+ItemSize;
|
||||
if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) {
|
||||
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
@@ -190,14 +190,14 @@ int StringMapImpl::FindKey(StringRef Key) const {
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
const char *VStr = (char*)V + ItemSize;
|
||||
StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength()));
|
||||
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
|
||||
(void)V2;
|
||||
assert(V == V2 && "Didn't find key?");
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return nullptr;
|
||||
|
||||
|
||||
@@ -1,507 +0,0 @@
|
||||
//===-- StringRef.cpp - Lightweight String References ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <bitset>
|
||||
#include <climits>
|
||||
#include <ostream>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
// MSVC emits references to this into the translation units which reference it.
|
||||
#ifndef _MSC_VER
|
||||
const size_t StringRef::npos;
|
||||
#endif
|
||||
|
||||
// strncasecmp() is not available on non-POSIX systems, so define an
|
||||
// alternative function here.
|
||||
static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) noexcept {
|
||||
for (size_t I = 0; I < Length; ++I) {
|
||||
unsigned char LHC = toLower(LHS[I]);
|
||||
unsigned char RHC = toLower(RHS[I]);
|
||||
if (LHC != RHC)
|
||||
return LHC < RHC ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// compare_lower - Compare strings, ignoring case.
|
||||
int StringRef::compare_lower(StringRef RHS) const noexcept {
|
||||
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(Length, RHS.Length)))
|
||||
return Res;
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
/// Check if this string starts with the given \p Prefix, ignoring case.
|
||||
bool StringRef::startswith_lower(StringRef Prefix) const noexcept {
|
||||
return Length >= Prefix.Length &&
|
||||
ascii_strncasecmp(Data, Prefix.Data, Prefix.Length) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string ends with the given \p Suffix, ignoring case.
|
||||
bool StringRef::endswith_lower(StringRef Suffix) const noexcept {
|
||||
return Length >= Suffix.Length &&
|
||||
ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
|
||||
}
|
||||
|
||||
size_t StringRef::find_lower(char C, size_t From) const noexcept {
|
||||
char L = toLower(C);
|
||||
return find_if([L](char D) { return toLower(D) == L; }, From);
|
||||
}
|
||||
|
||||
/// compare_numeric - Compare strings, handle embedded numbers.
|
||||
int StringRef::compare_numeric(StringRef RHS) const noexcept {
|
||||
for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) {
|
||||
// Check for sequences of digits.
|
||||
if (isDigit(Data[I]) && isDigit(RHS.Data[I])) {
|
||||
// The longer sequence of numbers is considered larger.
|
||||
// This doesn't really handle prefixed zeros well.
|
||||
size_t J;
|
||||
for (J = I + 1; J != E + 1; ++J) {
|
||||
bool ld = J < Length && isDigit(Data[J]);
|
||||
bool rd = J < RHS.Length && isDigit(RHS.Data[J]);
|
||||
if (ld != rd)
|
||||
return rd ? -1 : 1;
|
||||
if (!rd)
|
||||
break;
|
||||
}
|
||||
// The two number sequences have the same length (J-I), just memcmp them.
|
||||
if (int Res = compareMemory(Data + I, RHS.Data + I, J - I))
|
||||
return Res < 0 ? -1 : 1;
|
||||
// Identical number sequences, continue search after the numbers.
|
||||
I = J - 1;
|
||||
continue;
|
||||
}
|
||||
if (Data[I] != RHS.Data[I])
|
||||
return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1;
|
||||
}
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// String Operations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
std::string StringRef::lower() const {
|
||||
std::string Result(size(), char());
|
||||
for (size_type i = 0, e = size(); i != e; ++i) {
|
||||
Result[i] = toLower(Data[i]);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string StringRef::upper() const {
|
||||
std::string Result(size(), char());
|
||||
for (size_type i = 0, e = size(); i != e; ++i) {
|
||||
Result[i] = toUpper(Data[i]);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// String Searching
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/// find - Search for the first string \arg Str in the string.
|
||||
///
|
||||
/// \return - The index of the first occurrence of \arg Str, or npos if not
|
||||
/// found.
|
||||
size_t StringRef::find(StringRef Str, size_t From) const noexcept {
|
||||
if (From > Length)
|
||||
return npos;
|
||||
|
||||
const char *Start = Data + From;
|
||||
size_t Size = Length - From;
|
||||
|
||||
const char *Needle = Str.data();
|
||||
size_t N = Str.size();
|
||||
if (N == 0)
|
||||
return From;
|
||||
if (Size < N)
|
||||
return npos;
|
||||
if (N == 1) {
|
||||
const char *Ptr = (const char *)::memchr(Start, Needle[0], Size);
|
||||
return Ptr == nullptr ? npos : Ptr - Data;
|
||||
}
|
||||
|
||||
const char *Stop = Start + (Size - N + 1);
|
||||
|
||||
// For short haystacks or unsupported needles fall back to the naive algorithm
|
||||
if (Size < 16 || N > 255) {
|
||||
do {
|
||||
if (std::memcmp(Start, Needle, N) == 0)
|
||||
return Start - Data;
|
||||
++Start;
|
||||
} while (Start < Stop);
|
||||
return npos;
|
||||
}
|
||||
|
||||
// Build the bad char heuristic table, with uint8_t to reduce cache thrashing.
|
||||
uint8_t BadCharSkip[256];
|
||||
std::memset(BadCharSkip, N, 256);
|
||||
for (unsigned i = 0; i != N-1; ++i)
|
||||
BadCharSkip[(uint8_t)Str[i]] = N-1-i;
|
||||
|
||||
do {
|
||||
uint8_t Last = Start[N - 1];
|
||||
if (LLVM_UNLIKELY(Last == (uint8_t)Needle[N - 1]))
|
||||
if (std::memcmp(Start, Needle, N - 1) == 0)
|
||||
return Start - Data;
|
||||
|
||||
// Otherwise skip the appropriate number of bytes.
|
||||
Start += BadCharSkip[Last];
|
||||
} while (Start < Stop);
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::find_lower(StringRef Str, size_t From) const noexcept {
|
||||
StringRef This = substr(From);
|
||||
while (This.size() >= Str.size()) {
|
||||
if (This.startswith_lower(Str))
|
||||
return From;
|
||||
This = This.drop_front();
|
||||
++From;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::rfind_lower(char C, size_t From) const noexcept {
|
||||
From = std::min(From, Length);
|
||||
size_t i = From;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
if (toLower(Data[i]) == toLower(C))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// rfind - Search for the last string \arg Str in the string.
|
||||
///
|
||||
/// \return - The index of the last occurrence of \arg Str, or npos if not
|
||||
/// found.
|
||||
size_t StringRef::rfind(StringRef Str) const noexcept {
|
||||
size_t N = Str.size();
|
||||
if (N > Length)
|
||||
return npos;
|
||||
for (size_t i = Length - N + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (substr(i, N).equals(Str))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::rfind_lower(StringRef Str) const noexcept {
|
||||
size_t N = Str.size();
|
||||
if (N > Length)
|
||||
return npos;
|
||||
for (size_t i = Length - N + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (substr(i, N).equals_lower(Str))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_first_of - Find the first character in the string that is in \arg
|
||||
/// Chars, or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_first_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_first_not_of - Find the first character in the string that is not
|
||||
/// \arg C or npos if not found.
|
||||
StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const noexcept {
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (Data[i] != C)
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_first_not_of - Find the first character in the string that is not
|
||||
/// in the string \arg Chars, or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_first_not_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (!CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_last_of - Find the last character in the string that is in \arg C,
|
||||
/// or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_last_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_last_not_of - Find the last character in the string that is not
|
||||
/// \arg C, or npos if not found.
|
||||
StringRef::size_type StringRef::find_last_not_of(char C, size_t From) const noexcept {
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (Data[i] != C)
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_last_not_of - Find the last character in the string that is not in
|
||||
/// \arg Chars, or npos if not found.
|
||||
///
|
||||
/// Note: O(size() + Chars.size())
|
||||
StringRef::size_type StringRef::find_last_not_of(StringRef Chars,
|
||||
size_t From) const noexcept {
|
||||
std::bitset<1 << CHAR_BIT> CharBits;
|
||||
for (size_type i = 0, e = Chars.size(); i != e; ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (!CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
|
||||
void StringRef::split(SmallVectorImpl<StringRef> &A,
|
||||
StringRef Separator, int MaxSplit,
|
||||
bool KeepEmpty) const {
|
||||
StringRef S = *this;
|
||||
|
||||
// Count down from MaxSplit. When MaxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make MaxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (MaxSplit-- != 0) {
|
||||
size_t Idx = S.find(Separator);
|
||||
if (Idx == npos)
|
||||
break;
|
||||
|
||||
// Push this split.
|
||||
if (KeepEmpty || Idx > 0)
|
||||
A.push_back(S.slice(0, Idx));
|
||||
|
||||
// Jump forward.
|
||||
S = S.slice(Idx + Separator.size(), npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (KeepEmpty || !S.empty())
|
||||
A.push_back(S);
|
||||
}
|
||||
|
||||
void StringRef::split(SmallVectorImpl<StringRef> &A, char Separator,
|
||||
int MaxSplit, bool KeepEmpty) const {
|
||||
StringRef S = *this;
|
||||
|
||||
// Count down from MaxSplit. When MaxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make MaxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (MaxSplit-- != 0) {
|
||||
size_t Idx = S.find(Separator);
|
||||
if (Idx == npos)
|
||||
break;
|
||||
|
||||
// Push this split.
|
||||
if (KeepEmpty || Idx > 0)
|
||||
A.push_back(S.slice(0, Idx));
|
||||
|
||||
// Jump forward.
|
||||
S = S.slice(Idx + 1, npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (KeepEmpty || !S.empty())
|
||||
A.push_back(S);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Helpful Algorithms
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// count - Return the number of non-overlapped occurrences of \arg Str in
|
||||
/// the string.
|
||||
size_t StringRef::count(StringRef Str) const noexcept {
|
||||
size_t Count = 0;
|
||||
size_t N = Str.size();
|
||||
if (N > Length)
|
||||
return 0;
|
||||
for (size_t i = 0, e = Length - N + 1; i != e; ++i)
|
||||
if (substr(i, N).equals(Str))
|
||||
++Count;
|
||||
return Count;
|
||||
}
|
||||
|
||||
static unsigned GetAutoSenseRadix(StringRef &Str) noexcept {
|
||||
if (Str.empty())
|
||||
return 10;
|
||||
|
||||
if (Str.startswith("0x") || Str.startswith("0X")) {
|
||||
Str = Str.substr(2);
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (Str.startswith("0b") || Str.startswith("0B")) {
|
||||
Str = Str.substr(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (Str.startswith("0o")) {
|
||||
Str = Str.substr(2);
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (Str[0] == '0' && Str.size() > 1 && isDigit(Str[1])) {
|
||||
Str = Str.substr(1);
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
|
||||
bool wpi::consumeUnsignedInteger(StringRef &Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept {
|
||||
// Autosense radix if not specified.
|
||||
if (Radix == 0)
|
||||
Radix = GetAutoSenseRadix(Str);
|
||||
|
||||
// Empty strings (after the radix autosense) are invalid.
|
||||
if (Str.empty()) return true;
|
||||
|
||||
// Parse all the bytes of the string given this radix. Watch for overflow.
|
||||
StringRef Str2 = Str;
|
||||
Result = 0;
|
||||
while (!Str2.empty()) {
|
||||
unsigned CharVal;
|
||||
if (Str2[0] >= '0' && Str2[0] <= '9')
|
||||
CharVal = Str2[0] - '0';
|
||||
else if (Str2[0] >= 'a' && Str2[0] <= 'z')
|
||||
CharVal = Str2[0] - 'a' + 10;
|
||||
else if (Str2[0] >= 'A' && Str2[0] <= 'Z')
|
||||
CharVal = Str2[0] - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
// If the parsed value is larger than the integer radix, we cannot
|
||||
// consume any more characters.
|
||||
if (CharVal >= Radix)
|
||||
break;
|
||||
|
||||
// Add in this character.
|
||||
unsigned long long PrevResult = Result;
|
||||
Result = Result * Radix + CharVal;
|
||||
|
||||
// Check for overflow by shifting back and seeing if bits were lost.
|
||||
if (Result / Radix < PrevResult)
|
||||
return true;
|
||||
|
||||
Str2 = Str2.substr(1);
|
||||
}
|
||||
|
||||
// We consider the operation a failure if no characters were consumed
|
||||
// successfully.
|
||||
if (Str.size() == Str2.size())
|
||||
return true;
|
||||
|
||||
Str = Str2;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::consumeSignedInteger(StringRef &Str, unsigned Radix,
|
||||
long long &Result) noexcept {
|
||||
unsigned long long ULLVal;
|
||||
|
||||
// Handle positive strings first.
|
||||
if (Str.empty() || Str.front() != '-') {
|
||||
if (consumeUnsignedInteger(Str, Radix, ULLVal) ||
|
||||
// Check for value so large it overflows a signed value.
|
||||
(long long)ULLVal < 0)
|
||||
return true;
|
||||
Result = ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the positive part of the value.
|
||||
StringRef Str2 = Str.drop_front(1);
|
||||
if (consumeUnsignedInteger(Str2, Radix, ULLVal) ||
|
||||
// Reject values so large they'd overflow as negative signed, but allow
|
||||
// "-0". This negates the unsigned so that the negative isn't undefined
|
||||
// on signed overflow.
|
||||
(long long)-ULLVal > 0)
|
||||
return true;
|
||||
|
||||
Str = Str2;
|
||||
Result = -ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
|
||||
/// sequence of radix up to 36 to an unsigned long long value.
|
||||
bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept {
|
||||
if (consumeUnsignedInteger(Str, Radix, Result))
|
||||
return true;
|
||||
|
||||
// For getAsUnsignedInteger, we require the whole string to be consumed or
|
||||
// else we consider it a failure.
|
||||
return !Str.empty();
|
||||
}
|
||||
|
||||
bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
|
||||
long long &Result) noexcept {
|
||||
if (consumeSignedInteger(Str, Radix, Result))
|
||||
return true;
|
||||
|
||||
// For getAsSignedInteger, we require the whole string to be consumed or else
|
||||
// we consider it a failure.
|
||||
return !Str.empty();
|
||||
}
|
||||
|
||||
std::ostream &wpi::operator<<(std::ostream &os, StringRef string) {
|
||||
os.write(string.data(), string.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
// Implementation of StringRef hashing.
|
||||
hash_code wpi::hash_value(StringRef S) {
|
||||
return hash_combine_range(S.begin(), S.end());
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
//===-- Twine.cpp - Fast Temporary String Concatenation -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
using namespace wpi;
|
||||
|
||||
std::string Twine::str() const {
|
||||
// If we're storing only a std::string, just return it.
|
||||
if (LHSKind == StdStringKind && RHSKind == EmptyKind)
|
||||
return *LHS.stdString;
|
||||
|
||||
// Otherwise, flatten and copy the contents first.
|
||||
SmallString<256> Vec;
|
||||
return toStringRef(Vec).str();
|
||||
}
|
||||
|
||||
void Twine::toVector(SmallVectorImpl<char> &Out) const {
|
||||
raw_svector_ostream OS(Out);
|
||||
print(OS);
|
||||
}
|
||||
|
||||
StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const {
|
||||
if (isUnary()) {
|
||||
switch (getLHSKind()) {
|
||||
case CStringKind:
|
||||
// Already null terminated, yay!
|
||||
return StringRef(LHS.cString);
|
||||
case StdStringKind: {
|
||||
const std::string *str = LHS.stdString;
|
||||
return StringRef(str->c_str(), str->size());
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
toVector(Out);
|
||||
Out.push_back(0);
|
||||
Out.pop_back();
|
||||
return StringRef(Out.data(), Out.size());
|
||||
}
|
||||
|
||||
void Twine::printOneChild(raw_ostream &OS, Child Ptr,
|
||||
NodeKind Kind) const {
|
||||
switch (Kind) {
|
||||
case Twine::NullKind: break;
|
||||
case Twine::EmptyKind: break;
|
||||
case Twine::TwineKind:
|
||||
Ptr.twine->print(OS);
|
||||
break;
|
||||
case Twine::CStringKind:
|
||||
OS << Ptr.cString;
|
||||
break;
|
||||
case Twine::StdStringKind:
|
||||
OS << *Ptr.stdString;
|
||||
break;
|
||||
case Twine::StringRefKind:
|
||||
OS << *Ptr.stringRef;
|
||||
break;
|
||||
case Twine::StringViewKind:
|
||||
OS << *Ptr.stringView;
|
||||
break;
|
||||
case Twine::SmallStringKind:
|
||||
OS << *Ptr.smallString;
|
||||
break;
|
||||
case Twine::CharKind:
|
||||
OS << Ptr.character;
|
||||
break;
|
||||
case Twine::DecUIKind:
|
||||
OS << Ptr.decUI;
|
||||
break;
|
||||
case Twine::DecIKind:
|
||||
OS << Ptr.decI;
|
||||
break;
|
||||
case Twine::DecULKind:
|
||||
OS << *Ptr.decUL;
|
||||
break;
|
||||
case Twine::DecLKind:
|
||||
OS << *Ptr.decL;
|
||||
break;
|
||||
case Twine::DecULLKind:
|
||||
OS << *Ptr.decULL;
|
||||
break;
|
||||
case Twine::DecLLKind:
|
||||
OS << *Ptr.decLL;
|
||||
break;
|
||||
case Twine::UHexKind:
|
||||
OS.write_hex(*Ptr.uHex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr,
|
||||
NodeKind Kind) const {
|
||||
switch (Kind) {
|
||||
case Twine::NullKind:
|
||||
OS << "null"; break;
|
||||
case Twine::EmptyKind:
|
||||
OS << "empty"; break;
|
||||
case Twine::TwineKind:
|
||||
OS << "rope:";
|
||||
Ptr.twine->printRepr(OS);
|
||||
break;
|
||||
case Twine::CStringKind:
|
||||
OS << "cstring:\""
|
||||
<< Ptr.cString << "\"";
|
||||
break;
|
||||
case Twine::StdStringKind:
|
||||
OS << "std::string:\""
|
||||
<< Ptr.stdString << "\"";
|
||||
break;
|
||||
case Twine::StringRefKind:
|
||||
OS << "stringref:\""
|
||||
<< Ptr.stringRef << "\"";
|
||||
break;
|
||||
case Twine::StringViewKind:
|
||||
OS << "std::string_view:\""
|
||||
<< Ptr.stringView << "\"";
|
||||
break;
|
||||
case Twine::SmallStringKind:
|
||||
OS << "smallstring:\"" << *Ptr.smallString << "\"";
|
||||
break;
|
||||
case Twine::CharKind:
|
||||
OS << "char:\"" << Ptr.character << "\"";
|
||||
break;
|
||||
case Twine::DecUIKind:
|
||||
OS << "decUI:\"" << Ptr.decUI << "\"";
|
||||
break;
|
||||
case Twine::DecIKind:
|
||||
OS << "decI:\"" << Ptr.decI << "\"";
|
||||
break;
|
||||
case Twine::DecULKind:
|
||||
OS << "decUL:\"" << *Ptr.decUL << "\"";
|
||||
break;
|
||||
case Twine::DecLKind:
|
||||
OS << "decL:\"" << *Ptr.decL << "\"";
|
||||
break;
|
||||
case Twine::DecULLKind:
|
||||
OS << "decULL:\"" << *Ptr.decULL << "\"";
|
||||
break;
|
||||
case Twine::DecLLKind:
|
||||
OS << "decLL:\"" << *Ptr.decLL << "\"";
|
||||
break;
|
||||
case Twine::UHexKind:
|
||||
OS << "uhex:\"" << Ptr.uHex << "\"";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Twine::print(raw_ostream &OS) const {
|
||||
printOneChild(OS, LHS, getLHSKind());
|
||||
printOneChild(OS, RHS, getRHSKind());
|
||||
}
|
||||
|
||||
void Twine::printRepr(raw_ostream &OS) const {
|
||||
OS << "(Twine ";
|
||||
printOneChildRepr(OS, LHS, getLHSKind());
|
||||
OS << " ";
|
||||
printOneChildRepr(OS, RHS, getRHSKind());
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void Twine::dump() const {
|
||||
print(errs());
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void Twine::dumpRepr() const {
|
||||
printRepr(errs());
|
||||
}
|
||||
@@ -36,13 +36,12 @@
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/Chrono.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/VersionTuple.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/Format.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/NativeFormatting.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "wpi/fs.h"
|
||||
#include <algorithm>
|
||||
@@ -113,32 +111,7 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
||||
assert(OutBufStart <= OutBufEnd && "Invalid size!");
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long N) {
|
||||
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long N) {
|
||||
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long long N) {
|
||||
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long long N) {
|
||||
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_hex(unsigned long long N) {
|
||||
wpi::write_hex(*this, N, HexPrintStyle::Lower);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_escaped(StringRef Str,
|
||||
raw_ostream &raw_ostream::write_escaped(std::string_view Str,
|
||||
bool UseHexEscapes) {
|
||||
for (unsigned char c : Str) {
|
||||
switch (c) {
|
||||
@@ -178,16 +151,6 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str,
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const void *P) {
|
||||
wpi::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(double N) {
|
||||
wpi::write_double(*this, N, FloatStyle::Exponent);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void raw_ostream::flush_nonempty() {
|
||||
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
|
||||
size_t Length = OutBufCur - OutBufStart;
|
||||
@@ -277,170 +240,6 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
|
||||
OutBufCur += Size;
|
||||
}
|
||||
|
||||
// Formatted output.
|
||||
raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
|
||||
// If we have more than a few bytes left in our output buffer, try
|
||||
// formatting directly onto its end.
|
||||
size_t NextBufferSize = 127;
|
||||
size_t BufferBytesLeft = OutBufEnd - OutBufCur;
|
||||
if (BufferBytesLeft > 3) {
|
||||
size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
|
||||
|
||||
// Common case is that we have plenty of space.
|
||||
if (BytesUsed <= BufferBytesLeft) {
|
||||
OutBufCur += BytesUsed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Otherwise, we overflowed and the return value tells us the size to try
|
||||
// again with.
|
||||
NextBufferSize = BytesUsed;
|
||||
}
|
||||
|
||||
// If we got here, we didn't have enough space in the output buffer for the
|
||||
// string. Try printing into a SmallVector that is resized to have enough
|
||||
// space. Iterate until we win.
|
||||
SmallVector<char, 128> V;
|
||||
|
||||
while (true) {
|
||||
V.resize(NextBufferSize);
|
||||
|
||||
// Try formatting into the SmallVector.
|
||||
size_t BytesUsed = Fmt.print(V.data(), NextBufferSize);
|
||||
|
||||
// If BytesUsed fit into the vector, we win.
|
||||
if (BytesUsed <= NextBufferSize)
|
||||
return write(V.data(), BytesUsed);
|
||||
|
||||
// Otherwise, try again with a new size.
|
||||
assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
|
||||
NextBufferSize = BytesUsed;
|
||||
}
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
|
||||
if (FS.Str.size() >= FS.Width || FS.Justify == FormattedString::JustifyNone) {
|
||||
this->operator<<(FS.Str);
|
||||
return *this;
|
||||
}
|
||||
const size_t Difference = FS.Width - FS.Str.size();
|
||||
switch (FS.Justify) {
|
||||
case FormattedString::JustifyLeft:
|
||||
this->operator<<(FS.Str);
|
||||
this->indent(Difference);
|
||||
break;
|
||||
case FormattedString::JustifyRight:
|
||||
this->indent(Difference);
|
||||
this->operator<<(FS.Str);
|
||||
break;
|
||||
case FormattedString::JustifyCenter: {
|
||||
int PadAmount = Difference / 2;
|
||||
this->indent(PadAmount);
|
||||
this->operator<<(FS.Str);
|
||||
this->indent(Difference - PadAmount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
wpi_unreachable("Bad Justification");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
|
||||
if (FN.Hex) {
|
||||
HexPrintStyle Style;
|
||||
if (FN.Upper && FN.HexPrefix)
|
||||
Style = HexPrintStyle::PrefixUpper;
|
||||
else if (FN.Upper && !FN.HexPrefix)
|
||||
Style = HexPrintStyle::Upper;
|
||||
else if (!FN.Upper && FN.HexPrefix)
|
||||
Style = HexPrintStyle::PrefixLower;
|
||||
else
|
||||
Style = HexPrintStyle::Lower;
|
||||
wpi::write_hex(*this, FN.HexValue, Style, FN.Width);
|
||||
} else {
|
||||
wpi::SmallString<16> Buffer;
|
||||
wpi::raw_svector_ostream Stream(Buffer);
|
||||
wpi::write_integer(Stream, FN.DecValue, 0, IntegerStyle::Integer);
|
||||
if (Buffer.size() < FN.Width)
|
||||
indent(FN.Width - Buffer.size());
|
||||
(*this) << Buffer;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
|
||||
if (FB.Bytes.empty())
|
||||
return *this;
|
||||
|
||||
size_t LineIndex = 0;
|
||||
auto Bytes = FB.Bytes;
|
||||
const size_t Size = Bytes.size();
|
||||
HexPrintStyle HPS = FB.Upper ? HexPrintStyle::Upper : HexPrintStyle::Lower;
|
||||
uint64_t OffsetWidth = 0;
|
||||
if (FB.FirstByteOffset.has_value()) {
|
||||
// Figure out how many nibbles are needed to print the largest offset
|
||||
// represented by this data set, so that we can align the offset field
|
||||
// to the right width.
|
||||
size_t Lines = Size / FB.NumPerLine;
|
||||
uint64_t MaxOffset = *FB.FirstByteOffset + Lines * FB.NumPerLine;
|
||||
unsigned Power = 0;
|
||||
if (MaxOffset > 0)
|
||||
Power = wpi::Log2_64_Ceil(MaxOffset);
|
||||
OffsetWidth = std::max<uint64_t>(4, wpi::alignTo(Power, 4) / 4);
|
||||
}
|
||||
|
||||
// The width of a block of data including all spaces for group separators.
|
||||
unsigned NumByteGroups =
|
||||
alignTo(FB.NumPerLine, FB.ByteGroupSize) / FB.ByteGroupSize;
|
||||
unsigned BlockCharWidth = FB.NumPerLine * 2 + NumByteGroups - 1;
|
||||
|
||||
while (!Bytes.empty()) {
|
||||
indent(FB.IndentLevel);
|
||||
|
||||
if (FB.FirstByteOffset.has_value()) {
|
||||
uint64_t Offset = FB.FirstByteOffset.value();
|
||||
wpi::write_hex(*this, Offset + LineIndex, HPS, OffsetWidth);
|
||||
*this << ": ";
|
||||
}
|
||||
|
||||
auto Line = Bytes.take_front(FB.NumPerLine);
|
||||
|
||||
size_t CharsPrinted = 0;
|
||||
// Print the hex bytes for this line in groups
|
||||
for (size_t I = 0; I < Line.size(); ++I, CharsPrinted += 2) {
|
||||
if (I && (I % FB.ByteGroupSize) == 0) {
|
||||
++CharsPrinted;
|
||||
*this << " ";
|
||||
}
|
||||
wpi::write_hex(*this, Line[I], HPS, 2);
|
||||
}
|
||||
|
||||
if (FB.ASCII) {
|
||||
// Print any spaces needed for any bytes that we didn't print on this
|
||||
// line so that the ASCII bytes are correctly aligned.
|
||||
assert(BlockCharWidth >= CharsPrinted);
|
||||
indent(BlockCharWidth - CharsPrinted + 2);
|
||||
*this << "|";
|
||||
|
||||
// Print the ASCII char values for each byte on this line
|
||||
for (uint8_t Byte : Line) {
|
||||
if (isPrint(Byte))
|
||||
*this << static_cast<char>(Byte);
|
||||
else
|
||||
*this << '.';
|
||||
}
|
||||
*this << '|';
|
||||
}
|
||||
|
||||
Bytes = Bytes.drop_front(Line.size());
|
||||
LineIndex += Line.size();
|
||||
if (LineIndex < Size)
|
||||
*this << '\n';
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <char C>
|
||||
static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
|
||||
static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
@@ -474,19 +273,11 @@ raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
|
||||
|
||||
void raw_ostream::anchor() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Formatted Output
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Out of line virtual method.
|
||||
void format_object_base::home() {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_fd_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static int getFD(StringRef Filename, std::error_code &EC,
|
||||
static int getFD(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp, fs::FileAccess Access,
|
||||
fs::OpenFlags Flags) {
|
||||
assert((Access & fs::FA_Write) &&
|
||||
@@ -521,25 +312,25 @@ static int getFD(StringRef Filename, std::error_code &EC,
|
||||
return FD;
|
||||
}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC)
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp)
|
||||
: raw_fd_ostream(Filename, EC, Disp, fs::FA_Write, fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::FileAccess Access)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, Access,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::OpenFlags Flags)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
Flags) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp,
|
||||
fs::FileAccess Access,
|
||||
fs::OpenFlags Flags)
|
||||
@@ -622,7 +413,7 @@ raw_fd_ostream::~raw_fd_ostream() {
|
||||
// the input is UTF-8 or transcode from the local codepage to UTF-8 before
|
||||
// quoting it. If they don't, this may mess up the encoding, but this is still
|
||||
// probably the best compromise we can make.
|
||||
static bool write_console_impl(int FD, StringRef Data) {
|
||||
static bool write_console_impl(int FD, std::string_view Data) {
|
||||
SmallVector<wchar_t, 256> WideText;
|
||||
|
||||
// Fall back to ::write if it wasn't valid UTF-8.
|
||||
@@ -665,7 +456,7 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
// If this is a Windows console device, try re-encoding from UTF-8 to UTF-16
|
||||
// and using WriteConsoleW. If that fails, fall back to plain write().
|
||||
if (IsWindowsConsole)
|
||||
if (write_console_impl(FD, StringRef(Ptr, Size)))
|
||||
if (write_console_impl(FD, std::string_view(Ptr, Size)))
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user