Update LLVM to latest upstream. (#1080)

Also change header guards to WPI header guards.
Remove StringRef::c_str() customization, replacing the handful of uses with Twine or SmallString.
TCPStream: Include errno.h and make Windows includes lowercase for consistency.

Upstream LLVM version: eb4186cca7924fb1706357545311a2fa3de40c59
This commit is contained in:
Peter Johnson
2018-05-22 23:31:08 -07:00
committed by GitHub
parent 680aabbe7c
commit a2ecb1027a
62 changed files with 5956 additions and 2522 deletions

View File

@@ -620,7 +620,7 @@ cs::MjpegServer CameraServer::AddServer(wpi::StringRef name, int port) {
void CameraServer::AddServer(const cs::VideoSink& server) {
std::lock_guard<wpi::mutex> lock(m_mutex);
m_sinks.emplace_second(server.GetName(), server);
m_sinks.try_emplace(server.GetName(), server);
}
void CameraServer::RemoveServer(wpi::StringRef name) {
@@ -661,7 +661,7 @@ void CameraServer::AddCamera(const cs::VideoSource& camera) {
std::string name = camera.GetName();
std::lock_guard<wpi::mutex> lock(m_mutex);
if (m_primarySourceName.empty()) m_primarySourceName = name;
m_sources.emplace_second(name, camera);
m_sources.try_emplace(name, camera);
}
void CameraServer::RemoveCamera(wpi::StringRef name) {

View File

@@ -262,9 +262,9 @@ std::shared_ptr<Value> LoadPersistentImpl::ReadBooleanValue() {
std::shared_ptr<Value> LoadPersistentImpl::ReadDoubleValue() {
// need to convert to null-terminated string for std::strtod()
wpi::SmallString<64> buf;
wpi::SmallString<64> buf = m_line;
char* end;
double v = std::strtod(m_line.c_str(buf), &end);
double v = std::strtod(buf.c_str(), &end);
if (*end != '\0') {
Warn("invalid double value");
return nullptr;
@@ -318,9 +318,9 @@ std::shared_ptr<Value> LoadPersistentImpl::ReadDoubleArrayValue() {
std::tie(tok, m_line) = m_line.split(',');
tok = tok.trim(" \t");
// need to convert to null-terminated string for std::strtod()
wpi::SmallString<64> buf;
wpi::SmallString<64> buf = tok;
char* end;
double v = std::strtod(tok.c_str(buf), &end);
double v = std::strtod(buf.c_str(), &end);
if (*end != '\0') {
Warn("invalid double value");
return nullptr;

View File

@@ -9,6 +9,7 @@
#include <string>
#include <wpi/Base64.h>
#include <wpi/FileSystem.h>
#include <wpi/Format.h>
#include <wpi/SmallString.h>
#include <wpi/StringExtras.h>

View File

@@ -73,7 +73,7 @@ SerialPort::SerialPort(int baudRate, Port port, int dataBits,
* @param stopBits The number of stop bits to use as defined by the enum
* StopBits.
*/
SerialPort::SerialPort(int baudRate, wpi::StringRef portName, Port port,
SerialPort::SerialPort(int baudRate, const wpi::Twine& portName, Port port,
int dataBits, SerialPort::Parity parity,
SerialPort::StopBits stopBits) {
int32_t status = 0;
@@ -81,7 +81,7 @@ SerialPort::SerialPort(int baudRate, wpi::StringRef portName, Port port,
m_port = port;
wpi::SmallVector<char, 64> buf;
const char* portNameC = portName.c_str(buf);
const char* portNameC = portName.toNullTerminatedStringRef(buf).data();
HAL_InitializeSerialPortDirect(static_cast<HAL_SerialPort>(port), portNameC,
&status);

View File

@@ -10,6 +10,7 @@
#include <string>
#include <wpi/StringRef.h>
#include <wpi/Twine.h>
#include <wpi/deprecated.h>
#include "ErrorBase.h"
@@ -58,7 +59,7 @@ class SerialPort : public ErrorBase {
SerialPort(int baudRate, Port port = kOnboard, int dataBits = 8,
Parity parity = kParity_None, StopBits stopBits = kStopBits_One);
WPI_DEPRECATED("Will be removed for 2019")
SerialPort(int baudRate, wpi::StringRef portName, Port port = kOnboard,
SerialPort(int baudRate, const wpi::Twine& portName, Port port = kOnboard,
int dataBits = 8, Parity parity = kParity_None,
StopBits stopBits = kStopBits_One);
~SerialPort();

View File

@@ -17,11 +17,13 @@ generatedFileExclude {
src/main/native/include/wpi/DenseMap\.h$
src/main/native/include/wpi/DenseMapInfo\.h$
src/main/native/include/wpi/EpochTracker\.h$
src/main/native/include/wpi/ErrorOr\.h$
src/main/native/include/wpi/FileSystem\.h$
src/main/native/include/wpi/Format\.h$
src/main/native/include/wpi/Hashing\.h$
src/main/native/include/wpi/IntrusiveRefCntPtr\.h$
src/main/native/include/wpi/MathExtras\.h$
src/main/native/include/wpi/NativeFormatting\.h$
src/main/native/include/wpi/None\.h$
src/main/native/include/wpi/Optional\.h$
src/main/native/include/wpi/Path\.h$
@@ -36,6 +38,7 @@ generatedFileExclude {
src/main/native/include/wpi/StringRef\.h$
src/main/native/include/wpi/Twine\.h$
src/main/native/include/wpi/WindowsError\.h$
src/main/native/include/wpi/iterator\.h$
src/main/native/include/wpi/iterator_range\.h$
src/main/native/include/wpi/raw_os_ostream\.h$
src/main/native/include/wpi/raw_ostream\.h$

View File

@@ -26,14 +26,16 @@
#include <fcntl.h>
#ifdef _WIN32
#include <WinSock2.h>
#include <Ws2tcpip.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <unistd.h>
#endif
#include <cerrno>
using namespace wpi;
TCPStream::TCPStream(int sd, sockaddr_in* address)

View File

@@ -25,8 +25,8 @@ using namespace wpi;
UDPClient::UDPClient(Logger& logger) : UDPClient("", logger) {}
UDPClient::UDPClient(StringRef address, Logger& logger)
: m_lsd(0), m_address(address), m_logger(logger) {}
UDPClient::UDPClient(const Twine& address, Logger& logger)
: m_lsd(0), m_address(address.str()), m_logger(logger) {}
UDPClient::UDPClient(UDPClient&& other)
: m_lsd(other.m_lsd),
@@ -109,27 +109,27 @@ void UDPClient::shutdown() {
}
}
int UDPClient::send(ArrayRef<uint8_t> data, StringRef server, int port) {
int UDPClient::send(ArrayRef<uint8_t> data, const Twine& 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;
if (server.size() > 0) {
SmallVector<char, 128> addr_store;
auto remoteAddr = server.c_str(addr_store);
#ifdef _WIN32
int res = InetPton(AF_INET, remoteAddr, &(addr.sin_addr));
#else
int res = inet_pton(AF_INET, remoteAddr, &(addr.sin_addr));
#endif
if (res != 1) {
WPI_ERROR(m_logger, "could not resolve " << server << " address");
return -1;
}
} else {
SmallVector<char, 128> addr_store;
StringRef remoteAddr = server.toNullTerminatedStringRef(addr_store);
if (remoteAddr.empty()) {
WPI_ERROR(m_logger, "server must be passed");
return -1;
}
#ifdef _WIN32
int res = InetPton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
#else
int res = inet_pton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
#endif
if (res != 1) {
WPI_ERROR(m_logger, "could not resolve " << server << " address");
return -1;
}
addr.sin_port = htons(port);
// sendto should not block
@@ -139,27 +139,27 @@ int UDPClient::send(ArrayRef<uint8_t> data, StringRef server, int port) {
return result;
}
int UDPClient::send(StringRef data, StringRef server, int port) {
int UDPClient::send(StringRef data, const Twine& 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;
if (server.size() > 0) {
SmallVector<char, 128> addr_store;
auto remoteAddr = server.c_str(addr_store);
#ifdef _WIN32
int res = InetPton(AF_INET, remoteAddr, &(addr.sin_addr));
#else
int res = inet_pton(AF_INET, remoteAddr, &(addr.sin_addr));
#endif
if (res != 1) {
WPI_ERROR(m_logger, "could not resolve " << server << " address");
return -1;
}
} else {
SmallVector<char, 128> addr_store;
StringRef remoteAddr = server.toNullTerminatedStringRef(addr_store);
if (remoteAddr.empty()) {
WPI_ERROR(m_logger, "server must be passed");
return -1;
}
#ifdef _WIN32
int res = InetPton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
#else
int res = inet_pton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
#endif
if (res != 1) {
WPI_ERROR(m_logger, "could not resolve " << server << " address");
return -1;
}
addr.sin_port = htons(port);
// sendto should not block

View File

@@ -60,6 +60,6 @@ StringRef GetHostname(SmallVectorImpl<char>& name) {
name.clear();
name.append(tmpName, tmpName + std::strlen(tmpName) + 1);
return StringRef{name.data(), name.size(), true};
return StringRef{name.data(), name.size()};
}
} // namespace wpi

View File

@@ -207,7 +207,7 @@ json::json(initializer_list_t init,
std::for_each(init.begin(), init.end(), [this](const detail::json_ref<json>& element_ref)
{
auto element = element_ref.moved_or_copied();
m_value.object->emplace_second(
m_value.object->try_emplace(
*((*element.m_value.array)[0].m_value.string),
std::move((*element.m_value.array)[1]));
});

View File

@@ -39,6 +39,7 @@ SOFTWARE.
#include <cstdlib>
#include "wpi/Format.h"
#include "wpi/SmallString.h"
#include "wpi/raw_istream.h"
#include "wpi/raw_ostream.h"
@@ -1604,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->emplace_second(StringRef(key.data(), key.size()), std::move(value));
result.m_value.object->try_emplace(StringRef(key.data(), key.size()), std::move(value));
}
// comma -> next value

View File

@@ -46,13 +46,42 @@
------------------------------------------------------------------------ */
#include "wpi/ConvertUTF.h"
#ifdef CVTUTF_DEBUG
#include <stdio.h>
#endif
#include <assert.h>
/*
* This code extensively uses fall-through switches.
* Keep the compiler from warning about that.
*/
#if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wimplicit-fallthrough")
# define ConvertUTF_DISABLE_WARNINGS \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"")
# define ConvertUTF_RESTORE_WARNINGS \
_Pragma("clang diagnostic pop")
# endif
#elif defined(__GNUC__) && __GNUC__ > 6
# define ConvertUTF_DISABLE_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
# define ConvertUTF_RESTORE_WARNINGS \
_Pragma("GCC diagnostic pop")
#endif
#ifndef ConvertUTF_DISABLE_WARNINGS
# define ConvertUTF_DISABLE_WARNINGS
#endif
#ifndef ConvertUTF_RESTORE_WARNINGS
# define ConvertUTF_RESTORE_WARNINGS
#endif
ConvertUTF_DISABLE_WARNINGS
namespace wpi {
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
@@ -110,7 +139,7 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
* into an inline function.
*/
extern "C" {
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (
@@ -272,9 +301,9 @@ ConversionResult ConvertUTF16toUTF8 (
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
@@ -325,9 +354,9 @@ ConversionResult ConvertUTF32toUTF8 (
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
@@ -356,8 +385,8 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
switch (length) {
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; /* FALLTHRU */
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; /* FALLTHRU */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
switch (*source) {
@@ -368,7 +397,6 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
/* FALLTHRU */
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
}
@@ -532,11 +560,11 @@ ConversionResult ConvertUTF8toUTF16 (
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6; /* FALLTHRU */ /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* FALLTHRU */ /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6; /* FALLTHRU */
case 2: ch += *source++; ch <<= 6; /* FALLTHRU */
case 1: ch += *source++; ch <<= 6; /* FALLTHRU */
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
@@ -636,11 +664,11 @@ static ConversionResult ConvertUTF8toUTF32Impl(
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6; /* FALLTHRU */
case 4: ch += *source++; ch <<= 6; /* FALLTHRU */
case 3: ch += *source++; ch <<= 6; /* FALLTHRU */
case 2: ch += *source++; ch <<= 6; /* FALLTHRU */
case 1: ch += *source++; ch <<= 6; /* FALLTHRU */
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
@@ -687,8 +715,6 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
flags, /*InputIsPartial=*/false);
}
}
/* ---------------------------------------------------------------------
Note A.
@@ -707,3 +733,7 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
similarly unrolled loops.
--------------------------------------------------------------------- */
} // namespace llvm
ConvertUTF_RESTORE_WARNINGS

View File

@@ -0,0 +1,264 @@
//===- 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,
Optional<size_t> Width) {
const size_t kMaxWidth = 128u;
size_t W = std::min(kMaxWidth, Width.getValueOr(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,
Optional<size_t> Precision) {
size_t Prec = Precision.getValueOr(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

@@ -30,16 +30,29 @@ using namespace wpi;
namespace {
using wpi::StringRef;
using wpi::sys::path::is_separator;
using wpi::sys::path::Style;
inline Style real_style(Style style) {
#ifdef _WIN32
const char *separators = "\\/";
const char preferred_separator = '\\';
return (style == Style::posix) ? Style::posix : Style::windows;
#else
const char separators = '/';
const char preferred_separator = '/';
return (style == Style::windows) ? Style::windows : Style::posix;
#endif
}
StringRef find_first_component(StringRef path) {
inline const char *separators(Style style) {
if (real_style(style) == Style::windows)
return "\\/";
return "/";
}
inline char preferred_separator(Style style) {
if (real_style(style) == Style::windows)
return '\\';
return '/';
}
StringRef find_first_component(StringRef path, Style style) {
// Look for this first component in the following order.
// * empty (in this case we return an empty string)
// * either C: or {//,\\}net.
@@ -49,101 +62,94 @@ namespace {
if (path.empty())
return path;
#ifdef _WIN32
// C:
if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) &&
path[1] == ':')
return path.substr(0, 2);
#endif
if (real_style(style) == Style::windows) {
// C:
if (path.size() >= 2 &&
std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
return path.substr(0, 2);
}
// //net
if ((path.size() > 2) &&
is_separator(path[0]) &&
path[0] == path[1] &&
!is_separator(path[2])) {
if ((path.size() > 2) && is_separator(path[0], style) &&
path[0] == path[1] && !is_separator(path[2], style)) {
// Find the next directory separator.
size_t end = path.find_first_of(separators, 2);
size_t end = path.find_first_of(separators(style), 2);
return path.substr(0, end);
}
// {/,\}
if (is_separator(path[0]))
if (is_separator(path[0], style))
return path.substr(0, 1);
// * {file,directory}name
size_t end = path.find_first_of(separators);
size_t end = path.find_first_of(separators(style));
return path.substr(0, end);
}
size_t filename_pos(StringRef str) {
if (str.size() == 2 &&
is_separator(str[0]) &&
str[0] == str[1])
return 0;
if (str.size() > 0 && is_separator(str[str.size() - 1]))
// Returns the first character of the filename in str. For paths ending in
// '/', it returns the position of the '/'.
size_t filename_pos(StringRef str, Style style) {
if (str.size() > 0 && is_separator(str[str.size() - 1], style))
return str.size() - 1;
size_t pos = str.find_last_of(separators, str.size() - 1);
size_t pos = str.find_last_of(separators(style), str.size() - 1);
#ifdef _WIN32
if (pos == StringRef::npos)
pos = str.find_last_of(':', str.size() - 2);
#endif
if (real_style(style) == Style::windows) {
if (pos == StringRef::npos)
pos = str.find_last_of(':', str.size() - 2);
}
if (pos == StringRef::npos ||
(pos == 1 && is_separator(str[0])))
if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
return 0;
return pos + 1;
}
size_t root_dir_start(StringRef str) {
// Returns the position of the root directory in str. If there is no root
// directory in str, it returns StringRef::npos.
size_t root_dir_start(StringRef str, Style style) {
// case "c:/"
#ifdef _WIN32
if (str.size() > 2 &&
str[1] == ':' &&
is_separator(str[2]))
return 2;
#endif
// case "//"
if (str.size() == 2 &&
is_separator(str[0]) &&
str[0] == str[1])
return StringRef::npos;
if (real_style(style) == Style::windows) {
if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
return 2;
}
// case "//net"
if (str.size() > 3 &&
is_separator(str[0]) &&
str[0] == str[1] &&
!is_separator(str[2])) {
return str.find_first_of(separators, 2);
if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
!is_separator(str[2], style)) {
return str.find_first_of(separators(style), 2);
}
// case "/"
if (str.size() > 0 && is_separator(str[0]))
if (str.size() > 0 && is_separator(str[0], style))
return 0;
return StringRef::npos;
}
size_t parent_path_end(StringRef path) {
size_t end_pos = filename_pos(path);
// Returns the position past the end of the "parent path" of path. The parent
// path will not end in '/', unless the parent is the root directory. If the
// path has no parent, 0 is returned.
size_t parent_path_end(StringRef path, Style style) {
size_t end_pos = filename_pos(path, style);
bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]);
bool filename_was_sep =
path.size() > 0 && is_separator(path[end_pos], style);
// Skip separators except for root dir.
size_t root_dir_pos = root_dir_start(path.substr(0, end_pos));
while(end_pos > 0 &&
(end_pos - 1) != root_dir_pos &&
is_separator(path[end_pos - 1]))
// Skip separators until we reach root dir (or the start of the string).
size_t root_dir_pos = root_dir_start(path, style);
while (end_pos > 0 &&
(root_dir_pos == StringRef::npos || end_pos > root_dir_pos) &&
is_separator(path[end_pos - 1], style))
--end_pos;
if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
return StringRef::npos;
if (end_pos == root_dir_pos && !filename_was_sep) {
// We've reached the root dir and the input path was *not* ending in a
// sequence of slashes. Include the root dir in the parent path.
return root_dir_pos + 1;
}
// Otherwise, just include before the last slash.
return end_pos;
}
} // end unnamed namespace
@@ -152,11 +158,12 @@ namespace wpi {
namespace sys {
namespace path {
const_iterator begin(StringRef path) {
const_iterator begin(StringRef path, Style style) {
const_iterator i;
i.Path = path;
i.Component = find_first_component(path);
i.Component = find_first_component(path, style);
i.Position = 0;
i.S = style;
return i;
}
@@ -181,32 +188,26 @@ const_iterator &const_iterator::operator++() {
// Both POSIX and Windows treat paths that begin with exactly two separators
// specially.
bool was_net = Component.size() > 2 &&
is_separator(Component[0]) &&
Component[1] == Component[0] &&
!is_separator(Component[2]);
bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
Component[1] == Component[0] && !is_separator(Component[2], S);
// Handle separators.
if (is_separator(Path[Position])) {
if (is_separator(Path[Position], S)) {
// Root dir.
if (was_net
#ifdef _WIN32
if (was_net ||
// c:/
|| Component.endswith(":")
#endif
) {
(real_style(S) == Style::windows && Component.endswith(":"))) {
Component = Path.substr(Position, 1);
return *this;
}
// Skip extra separators.
while (Position != Path.size() &&
is_separator(Path[Position])) {
while (Position != Path.size() && is_separator(Path[Position], S)) {
++Position;
}
// Treat trailing '/' as a '.'.
if (Position == Path.size()) {
// Treat trailing '/' as a '.', unless it is the root dir.
if (Position == Path.size() && Component != "/") {
--Position;
Component = ".";
return *this;
@@ -214,7 +215,7 @@ const_iterator &const_iterator::operator++() {
}
// Find next component.
size_t end_pos = Path.find_first_of(separators, Position);
size_t end_pos = Path.find_first_of(separators(S), Position);
Component = Path.slice(Position, end_pos);
return *this;
@@ -228,10 +229,11 @@ ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
return Position - RHS.Position;
}
reverse_iterator rbegin(StringRef Path) {
reverse_iterator rbegin(StringRef Path, Style style) {
reverse_iterator I;
I.Path = Path;
I.Position = Path.size();
I.S = style;
return ++I;
}
@@ -244,27 +246,25 @@ reverse_iterator rend(StringRef Path) {
}
reverse_iterator &reverse_iterator::operator++() {
// If we're at the end and the previous char was a '/', return '.' unless
// we are the root path.
size_t root_dir_pos = root_dir_start(Path);
if (Position == Path.size() &&
Path.size() > root_dir_pos + 1 &&
is_separator(Path[Position - 1])) {
size_t root_dir_pos = root_dir_start(Path, S);
// Skip separators unless it's the root directory.
size_t end_pos = Position;
while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
is_separator(Path[end_pos - 1], S))
--end_pos;
// Treat trailing '/' as a '.', unless it is the root dir.
if (Position == Path.size() && !Path.empty() &&
is_separator(Path.back(), S) &&
(root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) {
--Position;
Component = ".";
return *this;
}
// Skip separators unless it's the root directory.
size_t end_pos = Position;
while(end_pos > 0 &&
(end_pos - 1) != root_dir_pos &&
is_separator(Path[end_pos - 1]))
--end_pos;
// Find next separator.
size_t start_pos = filename_pos(Path.substr(0, end_pos));
size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
Component = Path.slice(start_pos, end_pos);
Position = start_pos;
return *this;
@@ -279,21 +279,15 @@ ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const {
return Position - RHS.Position;
}
StringRef root_path(StringRef path) {
const_iterator b = begin(path),
pos = b,
e = end(path);
StringRef root_path(StringRef path, Style style) {
const_iterator b = begin(path, style), pos = b, e = end(path);
if (b != e) {
bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
bool has_drive =
#ifdef _WIN32
b->endswith(":");
#else
false;
#endif
bool has_net =
b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if (has_net || has_drive) {
if ((++pos != e) && is_separator((*pos)[0])) {
if ((++pos != e) && is_separator((*pos)[0], style)) {
// {C:/,//net/}, so get the first two components.
return path.substr(0, b->size() + pos->size());
} else {
@@ -303,7 +297,7 @@ StringRef root_path(StringRef path) {
}
// POSIX style root directory.
if (is_separator((*b)[0])) {
if (is_separator((*b)[0], style)) {
return *b;
}
}
@@ -311,17 +305,12 @@ StringRef root_path(StringRef path) {
return StringRef();
}
StringRef root_name(StringRef path) {
const_iterator b = begin(path),
e = end(path);
StringRef root_name(StringRef path, Style style) {
const_iterator b = begin(path, style), e = end(path);
if (b != e) {
bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
bool has_drive =
#ifdef _WIN32
b->endswith(":");
#else
false;
#endif
bool has_net =
b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if (has_net || has_drive) {
// just {C:,//net}, return the first component.
@@ -333,27 +322,21 @@ StringRef root_name(StringRef path) {
return StringRef();
}
StringRef root_directory(StringRef path) {
const_iterator b = begin(path),
pos = b,
e = end(path);
StringRef root_directory(StringRef path, Style style) {
const_iterator b = begin(path, style), pos = b, e = end(path);
if (b != e) {
bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
bool has_drive =
#ifdef _WIN32
b->endswith(":");
#else
false;
#endif
bool has_net =
b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
if ((has_net || has_drive) &&
// {C:,//net}, skip to the next component.
(++pos != e) && is_separator((*pos)[0])) {
(++pos != e) && is_separator((*pos)[0], style)) {
return *pos;
}
// POSIX style root directory.
if (!has_net && is_separator((*b)[0])) {
if (!has_net && is_separator((*b)[0], style)) {
return *b;
}
}
@@ -362,15 +345,13 @@ StringRef root_directory(StringRef path) {
return StringRef();
}
StringRef relative_path(StringRef path) {
StringRef root = root_path(path);
StringRef relative_path(StringRef path, Style style) {
StringRef root = root_path(path, style);
return path.substr(root.size());
}
void append(SmallVectorImpl<char> &path, const Twine &a,
const Twine &b,
const Twine &c,
const Twine &d) {
void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
const Twine &b, const Twine &c, const Twine &d) {
SmallString<32> a_storage;
SmallString<32> b_storage;
SmallString<32> c_storage;
@@ -383,13 +364,11 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
for (auto &component : components) {
bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
bool component_has_sep = !component.empty() && is_separator(component[0]);
bool is_root_name = has_root_name(component);
bool path_has_sep =
!path.empty() && is_separator(path[path.size() - 1], style);
if (path_has_sep) {
// Strip separators from beginning of component.
size_t loc = component.find_first_not_of(separators);
size_t loc = component.find_first_not_of(separators(style));
StringRef c = component.substr(loc);
// Append it.
@@ -397,43 +376,52 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
continue;
}
if (!component_has_sep && !(path.empty() || is_root_name)) {
bool component_has_sep =
!component.empty() && is_separator(component[0], style);
if (!component_has_sep &&
!(path.empty() || has_root_name(component, style))) {
// Add a separator.
path.push_back(preferred_separator);
path.push_back(preferred_separator(style));
}
path.append(component.begin(), component.end());
}
}
void append(SmallVectorImpl<char> &path,
const_iterator begin, const_iterator end) {
for (; begin != end; ++begin)
path::append(path, *begin);
void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b,
const Twine &c, const Twine &d) {
append(path, Style::native, a, b, c, d);
}
StringRef parent_path(StringRef path) {
size_t end_pos = parent_path_end(path);
void append(SmallVectorImpl<char> &path, const_iterator begin,
const_iterator end, Style style) {
for (; begin != end; ++begin)
path::append(path, style, *begin);
}
StringRef parent_path(StringRef path, Style style) {
size_t end_pos = parent_path_end(path, style);
if (end_pos == StringRef::npos)
return StringRef();
else
return path.substr(0, end_pos);
}
void remove_filename(SmallVectorImpl<char> &path) {
size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()));
void remove_filename(SmallVectorImpl<char> &path, Style style) {
size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
if (end_pos != StringRef::npos)
path.set_size(end_pos);
}
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
Style style) {
StringRef p(path.begin(), path.size());
SmallString<32> ext_storage;
StringRef ext = extension.toStringRef(ext_storage);
// Erase existing extension.
size_t pos = p.find_last_of('.');
if (pos != StringRef::npos && pos >= filename_pos(p))
if (pos != StringRef::npos && pos >= filename_pos(p, style))
path.set_size(pos);
// Append '.' if needed.
@@ -445,8 +433,8 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
}
void replace_path_prefix(SmallVectorImpl<char> &Path,
const StringRef &OldPrefix,
const StringRef &NewPrefix) {
const StringRef &OldPrefix, const StringRef &NewPrefix,
Style style) {
if (OldPrefix.empty() && NewPrefix.empty())
return;
@@ -462,43 +450,58 @@ void replace_path_prefix(SmallVectorImpl<char> &Path,
StringRef RelPath = OrigPath.substr(OldPrefix.size());
SmallString<256> NewPath;
path::append(NewPath, NewPrefix);
path::append(NewPath, RelPath);
path::append(NewPath, style, NewPrefix);
path::append(NewPath, style, RelPath);
Path.swap(NewPath);
}
void native(const Twine &path, SmallVectorImpl<char> &result) {
void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
assert((!path.isSingleStringRef() ||
path.getSingleStringRef().data() != result.data()) &&
"path and result are not allowed to overlap!");
// Clear result.
result.clear();
path.toVector(result);
native(result);
native(result, style);
}
void native(SmallVectorImpl<char> &Path) {
#ifdef _WIN32
std::replace(Path.begin(), Path.end(), '/', '\\');
#else
for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
if (*PI == '\\') {
auto PN = PI + 1;
if (PN < PE && *PN == '\\')
++PI; // increment once, the for loop will move over the escaped slash
else
*PI = '/';
void native(SmallVectorImpl<char> &Path, Style style) {
if (Path.empty())
return;
if (real_style(style) == Style::windows) {
std::replace(Path.begin(), Path.end(), '/', '\\');
if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
SmallString<128> PathHome;
home_directory(PathHome);
PathHome.append(Path.begin() + 1, Path.end());
Path = PathHome;
}
} else {
for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
if (*PI == '\\') {
auto PN = PI + 1;
if (PN < PE && *PN == '\\')
++PI; // increment once, the for loop will move over the escaped slash
else
*PI = '/';
}
}
}
#endif
}
StringRef filename(StringRef path) {
return *rbegin(path);
std::string convert_to_slash(StringRef path, Style style) {
if (real_style(style) != Style::windows)
return path;
std::string s = path.str();
std::replace(s.begin(), s.end(), '\\', '/');
return s;
}
StringRef stem(StringRef path) {
StringRef fname = filename(path);
StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
StringRef stem(StringRef path, Style style) {
StringRef fname = filename(path, style);
size_t pos = fname.find_last_of('.');
if (pos == StringRef::npos)
return fname;
@@ -510,8 +513,8 @@ StringRef stem(StringRef path) {
return fname.substr(0, pos);
}
StringRef extension(StringRef path) {
StringRef fname = filename(path);
StringRef extension(StringRef path, Style style) {
StringRef fname = filename(path, style);
size_t pos = fname.find_last_of('.');
if (pos == StringRef::npos)
return StringRef();
@@ -523,132 +526,134 @@ StringRef extension(StringRef path) {
return fname.substr(pos);
}
bool is_separator(char value) {
switch(value) {
#ifdef _WIN32
case '\\': // fall through
#endif
case '/': return true;
default: return false;
}
bool is_separator(char value, Style style) {
if (value == '/')
return true;
if (real_style(style) == Style::windows)
return value == '\\';
return false;
}
static const char preferred_separator_string[] = { preferred_separator, '\0' };
StringRef get_separator() {
return preferred_separator_string;
StringRef get_separator(Style style) {
if (real_style(style) == Style::windows)
return "\\";
return "/";
}
bool has_root_name(const Twine &path) {
bool has_root_name(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !root_name(p).empty();
return !root_name(p, style).empty();
}
bool has_root_directory(const Twine &path) {
bool has_root_directory(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !root_directory(p).empty();
return !root_directory(p, style).empty();
}
bool has_root_path(const Twine &path) {
bool has_root_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !root_path(p).empty();
return !root_path(p, style).empty();
}
bool has_relative_path(const Twine &path) {
bool has_relative_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !relative_path(p).empty();
return !relative_path(p, style).empty();
}
bool has_filename(const Twine &path) {
bool has_filename(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !filename(p).empty();
return !filename(p, style).empty();
}
bool has_parent_path(const Twine &path) {
bool has_parent_path(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !parent_path(p).empty();
return !parent_path(p, style).empty();
}
bool has_stem(const Twine &path) {
bool has_stem(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !stem(p).empty();
return !stem(p, style).empty();
}
bool has_extension(const Twine &path) {
bool has_extension(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
return !extension(p).empty();
return !extension(p, style).empty();
}
bool is_absolute(const Twine &path) {
bool is_absolute(const Twine &path, Style style) {
SmallString<128> path_storage;
StringRef p = path.toStringRef(path_storage);
bool rootDir = has_root_directory(p),
#ifdef _WIN32
rootName = has_root_name(p);
#else
rootName = true;
#endif
bool rootDir = has_root_directory(p, style);
bool rootName =
(real_style(style) != Style::windows) || has_root_name(p, style);
return rootDir && rootName;
}
bool is_relative(const Twine &path) { return !is_absolute(path); }
bool is_relative(const Twine &path, Style style) {
return !is_absolute(path, style);
}
StringRef remove_leading_dotslash(StringRef Path) {
StringRef remove_leading_dotslash(StringRef Path, Style style) {
// Remove leading "./" (or ".//" or "././" etc.)
while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) {
while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
Path = Path.substr(2);
while (Path.size() > 0 && is_separator(Path[0]))
while (Path.size() > 0 && is_separator(Path[0], style))
Path = Path.substr(1);
}
return Path;
}
static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) {
static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot,
Style style) {
SmallVector<StringRef, 16> components;
// Skip the root path, then look for traversal in the components.
StringRef rel = path::relative_path(path);
for (StringRef C : wpi::make_range(path::begin(rel), path::end(rel))) {
StringRef rel = path::relative_path(path, style);
for (StringRef C :
wpi::make_range(path::begin(rel, style), path::end(rel))) {
if (C == ".")
continue;
if (remove_dot_dot) {
if (C == "..") {
if (!components.empty())
components.pop_back();
// Leading ".." will remain in the path unless it's at the root.
if (remove_dot_dot && C == "..") {
if (!components.empty() && components.back() != "..") {
components.pop_back();
continue;
}
if (path::is_absolute(path, style))
continue;
}
components.push_back(C);
}
SmallString<256> buffer = path::root_path(path);
SmallString<256> buffer = path::root_path(path, style);
for (StringRef C : components)
path::append(buffer, C);
path::append(buffer, style, C);
return buffer;
}
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot) {
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot,
Style style) {
StringRef p(path.data(), path.size());
SmallString<256> result = remove_dots(p, remove_dot_dot);
SmallString<256> result = remove_dots(p, remove_dot_dot, style);
if (result == path)
return false;
@@ -674,12 +679,9 @@ static std::error_code make_absolute(const Twine &current_directory,
bool use_current_directory) {
StringRef p(path.data(), path.size());
bool rootDirectory = path::has_root_directory(p),
#ifdef _WIN32
rootName = path::has_root_name(p);
#else
rootName = true;
#endif
bool rootDirectory = path::has_root_directory(p);
bool rootName =
(real_style(Style::native) != Style::windows) || path::has_root_name(p);
// Already absolute.
if (rootName && rootDirectory)
@@ -736,15 +738,22 @@ std::error_code make_absolute(SmallVectorImpl<char> &path) {
return make_absolute(Twine(), path, false);
}
bool exists(file_status status) {
bool exists(const basic_file_status &status) {
return status_known(status) && status.type() != file_type::file_not_found;
}
bool status_known(file_status s) {
bool status_known(const basic_file_status &s) {
return s.type() != file_type::status_error;
}
bool is_directory(file_status status) {
file_type get_file_type(const Twine &Path, bool Follow) {
file_status st;
if (status(Path, st, Follow))
return file_type::status_error;
return st.type();
}
bool is_directory(const basic_file_status &status) {
return status.type() == file_type::directory_file;
}
@@ -756,7 +765,7 @@ std::error_code is_directory(const Twine &path, bool &result) {
return std::error_code();
}
bool is_regular_file(file_status status) {
bool is_regular_file(const basic_file_status &status) {
return status.type() == file_type::regular_file;
}
@@ -768,7 +777,19 @@ std::error_code is_regular_file(const Twine &path, bool &result) {
return std::error_code();
}
bool is_other(file_status status) {
bool is_symlink_file(const basic_file_status &status) {
return status.type() == file_type::symlink_file;
}
std::error_code is_symlink_file(const Twine &path, bool &result) {
file_status st;
if (std::error_code ec = status(path, st, false))
return ec;
result = is_symlink_file(st);
return std::error_code();
}
bool is_other(const basic_file_status &status) {
return exists(status) &&
!is_regular_file(status) &&
!is_directory(status);
@@ -782,15 +803,20 @@ std::error_code is_other(const Twine &Path, bool &Result) {
return std::error_code();
}
void directory_entry::replace_filename(const Twine &filename, file_status st) {
void directory_entry::replace_filename(const Twine &filename,
basic_file_status st) {
SmallString<128> path = path::parent_path(Path);
path::append(path, filename);
Path = path.str();
Status = st;
}
std::error_code directory_entry::status(file_status &result) const {
return fs::status(Path, result);
ErrorOr<perms> getPermissions(const Twine &Path) {
file_status Status;
if (std::error_code EC = status(Path, Status))
return EC;
return Status.permissions();
}
} // end namespace fs

View File

@@ -15,7 +15,9 @@
#include "wpi/SmallPtrSet.h"
#include "wpi/DenseMapInfo.h"
#include "wpi/MathExtras.h"
#include "wpi/memory.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
using namespace wpi;
@@ -30,8 +32,7 @@ void SmallPtrSetImplBase::shrink_and_clear() {
NumNonEmpty = NumTombstones = 0;
// Install the new array. Clear all the buckets to empty.
CurArray = (const void**)malloc(sizeof(void*) * CurArraySize);
assert(CurArray && "Failed to allocate memory?");
CurArray = (const void**)CheckedMalloc(sizeof(void*) * CurArraySize);
memset(CurArray, -1, CurArraySize*sizeof(void*));
}
@@ -60,38 +61,13 @@ SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
return std::make_pair(Bucket, true);
}
bool SmallPtrSetImplBase::erase_imp(const void * Ptr) {
if (isSmall()) {
// Check to see if it is in the set.
for (const void **APtr = CurArray, **E = CurArray + NumNonEmpty; APtr != E;
++APtr)
if (*APtr == Ptr) {
// If it is in the set, replace this element.
*APtr = getTombstoneMarker();
++NumTombstones;
return true;
}
return false;
}
// Okay, we know we have space. Find a hash bucket.
void **Bucket = const_cast<void**>(FindBucketFor(Ptr));
if (*Bucket != Ptr) return false; // Not in the set?
// Set this as a tombstone.
*Bucket = getTombstoneMarker();
++NumTombstones;
return true;
}
const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {
unsigned Bucket = DenseMapInfo<void *>::getHashValue(Ptr) & (CurArraySize-1);
unsigned ArraySize = CurArraySize;
unsigned ProbeAmt = 1;
const void *const *Array = CurArray;
const void *const *Tombstone = nullptr;
while (1) {
while (true) {
// If we found an empty bucket, the pointer doesn't exist in the set.
// Return a tombstone if we've seen one so far, or the empty bucket if
// not.
@@ -120,8 +96,7 @@ void SmallPtrSetImplBase::Grow(unsigned NewSize) {
bool WasSmall = isSmall();
// Install the new array. Clear all the buckets to empty.
CurArray = (const void**)malloc(sizeof(void*) * NewSize);
assert(CurArray && "Failed to allocate memory?");
CurArray = (const void**) CheckedMalloc(sizeof(void*) * NewSize);
CurArraySize = NewSize;
memset(CurArray, -1, NewSize*sizeof(void*));
@@ -148,8 +123,7 @@ SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
CurArray = SmallArray;
// Otherwise, allocate new heap space (unless we were the same size)
} else {
CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize);
assert(CurArray && "Failed to allocate memory?");
CurArray = (const void**)CheckedMalloc(sizeof(void*) * that.CurArraySize);
}
// Copy over the that array.

View File

@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "wpi/SmallVector.h"
#include "wpi/memory.h"
using namespace wpi;
/// grow_pod - This is an implementation of the grow() method which only works
@@ -25,15 +26,14 @@ void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
void *NewElts;
if (BeginX == FirstEl) {
NewElts = malloc(NewCapacityInBytes);
NewElts = CheckedMalloc(NewCapacityInBytes);
// Copy the elements over. No need to run dtors on PODs.
memcpy(NewElts, this->BeginX, CurSizeBytes);
} else {
// If this wasn't grown from the inline copy, grow the allocated space.
NewElts = realloc(this->BeginX, NewCapacityInBytes);
NewElts = CheckedRealloc(this->BeginX, NewCapacityInBytes);
}
assert(NewElts && "Out of memory");
this->EndX = (char*)NewElts+CurSizeBytes;
this->BeginX = NewElts;

View File

@@ -13,6 +13,7 @@
#include "wpi/StringExtras.h"
#include "wpi/SmallVector.h"
#include "wpi/raw_ostream.h"
using namespace wpi;
/// StrInStrNoCase - Portable version of strcasestr. Locates the first
@@ -56,3 +57,18 @@ void wpi::SplitString(StringRef Source,
S = getToken(S.second, Delimiters);
}
}
void wpi::PrintEscapedString(StringRef Name, raw_ostream &Out) {
for (unsigned i = 0, e = Name.size(); i != e; ++i) {
unsigned char C = Name[i];
if (isprint(C) && C != '\\' && C != '"')
Out << C;
else
Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
}
}
void wpi::printLowerCase(StringRef String, raw_ostream &Out) {
for (const char C : String)
Out << toLower(C);
}

View File

@@ -12,10 +12,12 @@
//===----------------------------------------------------------------------===//
#include "wpi/StringMap.h"
#include "wpi/MathExtras.h"
#include "wpi/StringExtras.h"
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
#include "wpi/memory.h"
#include <cassert>
using namespace wpi;
/// Returns the number of buckets to allocate to ensure that the DenseMap can
@@ -51,20 +53,23 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
void StringMapImpl::init(unsigned InitSize) {
assert((InitSize & (InitSize-1)) == 0 &&
"Init Size must be a power of 2 or zero!");
NumBuckets = InitSize ? InitSize : 16;
unsigned NewNumBuckets = InitSize ? InitSize : 16;
NumItems = 0;
NumTombstones = 0;
TheTable = (StringMapEntryBase **)calloc(NumBuckets+1,
sizeof(StringMapEntryBase **) +
sizeof(unsigned));
TheTable = static_cast<StringMapEntryBase **>(
CheckedCalloc(NewNumBuckets+1,
sizeof(StringMapEntryBase **) + sizeof(unsigned)));
// Set the member only if TheTable was successfully allocated
NumBuckets = NewNumBuckets;
// Allocate one extra bucket, set it to look filled so the iterators stop at
// end.
TheTable[NumBuckets] = (StringMapEntryBase*)2;
}
/// LookupBucketFor - Look up the bucket that the specified string should end
/// up in. If it already exists as a key in the map, the Item pointer for the
/// specified bucket will be non-null. Otherwise, it will be null. In either
@@ -82,7 +87,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
unsigned ProbeAmt = 1;
int FirstTombstone = -1;
while (1) {
while (true) {
StringMapEntryBase *BucketItem = TheTable[BucketNo];
// If we found an empty bucket, this key isn't in the table yet, return it.
if (LLVM_LIKELY(!BucketItem)) {
@@ -136,7 +141,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
unsigned ProbeAmt = 1;
while (1) {
while (true) {
StringMapEntryBase *BucketItem = TheTable[BucketNo];
// If we found an empty bucket, this key isn't in the table yet, return.
if (LLVM_LIKELY(!BucketItem))
@@ -192,8 +197,6 @@ StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
return Result;
}
/// RehashTable - Grow the table, redistributing values into the buckets with
/// the appropriate mod-of-hashtable-size.
unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
@@ -215,9 +218,9 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
unsigned NewBucketNo = BucketNo;
// Allocate one extra bucket which will always be non-empty. This allows the
// iterators to stop at end.
StringMapEntryBase **NewTableArray =
(StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) +
sizeof(unsigned));
auto NewTableArray = static_cast<StringMapEntryBase **>(
CheckedCalloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
NewTableArray[NewSize] = (StringMapEntryBase*)2;

View File

@@ -9,9 +9,11 @@
#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;
@@ -20,28 +22,12 @@ using namespace wpi;
const size_t StringRef::npos;
#endif
static char ascii_tolower(char x) noexcept {
if (x >= 'A' && x <= 'Z')
return x - 'A' + 'a';
return x;
}
static char ascii_toupper(char x) noexcept {
if (x >= 'a' && x <= 'z')
return x - 'a' + 'A';
return x;
}
static bool ascii_isdigit(char x) noexcept {
return x >= '0' && x <= '9';
}
// 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 = ascii_tolower(LHS[I]);
unsigned char RHC = ascii_tolower(RHS[I]);
unsigned char LHC = toLower(LHS[I]);
unsigned char RHC = toLower(RHS[I]);
if (LHC != RHC)
return LHC < RHC ? -1 : 1;
}
@@ -50,36 +36,41 @@ static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) no
/// compare_lower - Compare strings, ignoring case.
int StringRef::compare_lower(StringRef RHS) const noexcept {
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(size(), RHS.size())))
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(Length, RHS.Length)))
return Res;
if (size() == RHS.size())
if (Length == RHS.Length)
return 0;
return size() < RHS.size() ? -1 : 1;
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 size() >= Prefix.size() &&
ascii_strncasecmp(Data, Prefix.Data, Prefix.size()) == 0;
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 size() >= Suffix.size() &&
ascii_strncasecmp(end() - Suffix.size(), Suffix.Data, Suffix.size()) == 0;
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(size(), RHS.size()); I != E; ++I) {
for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) {
// Check for sequences of digits.
if (ascii_isdigit(Data[I]) && ascii_isdigit(RHS.Data[I])) {
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 < size() && ascii_isdigit(Data[J]);
bool rd = J < RHS.size() && ascii_isdigit(RHS.Data[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)
@@ -95,9 +86,9 @@ int StringRef::compare_numeric(StringRef RHS) const noexcept {
if (Data[I] != RHS.Data[I])
return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1;
}
if (size() == RHS.size())
if (Length == RHS.Length)
return 0;
return size() < RHS.size() ? -1 : 1;
return Length < RHS.Length ? -1 : 1;
}
//===----------------------------------------------------------------------===//
@@ -107,7 +98,7 @@ int StringRef::compare_numeric(StringRef RHS) const noexcept {
std::string StringRef::lower() const {
std::string Result(size(), char());
for (size_type i = 0, e = size(); i != e; ++i) {
Result[i] = ascii_tolower(Data[i]);
Result[i] = toLower(Data[i]);
}
return Result;
}
@@ -115,25 +106,11 @@ std::string StringRef::lower() const {
std::string StringRef::upper() const {
std::string Result(size(), char());
for (size_type i = 0, e = size(); i != e; ++i) {
Result[i] = ascii_toupper(Data[i]);
Result[i] = toUpper(Data[i]);
}
return Result;
}
const char *StringRef::c_str(wpi::SmallVectorImpl<char>& buf) const {
if (is_null_terminated()) {
// If null terminated, return data directly
return data();
} else {
// If not null terminated, use SmallVectorImpl to store data
// copy data, and return a known null terminated string
buf.clear();
buf.append(begin(), end());
buf.push_back(0);
return buf.begin();
}
}
//===----------------------------------------------------------------------===//
// String Searching
//===----------------------------------------------------------------------===//
@@ -144,19 +121,23 @@ const char *StringRef::c_str(wpi::SmallVectorImpl<char>& buf) const {
/// \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 > size())
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;
size_t Size = size() - 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 *Start = Data + From;
const char *Stop = Start + (Size - N + 1);
// For short haystacks or unsupported needles fall back to the naive algorithm
@@ -176,25 +157,49 @@ size_t StringRef::find(StringRef Str, size_t From) const noexcept {
BadCharSkip[(uint8_t)Str[i]] = N-1-i;
do {
if (std::memcmp(Start, Needle, N) == 0)
return Start - Data;
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[(uint8_t)Start[N-1]];
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 > size())
if (N > Length)
return npos;
for (size_t i = size() - N + 1, e = 0; i != e;) {
for (size_t i = Length - N + 1, e = 0; i != e;) {
--i;
if (substr(i, N).equals(Str))
return i;
@@ -202,6 +207,18 @@ size_t StringRef::rfind(StringRef Str) const noexcept {
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.
///
@@ -212,7 +229,7 @@ StringRef::size_type StringRef::find_first_of(StringRef Chars,
for (size_type i = 0; i != Chars.size(); ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()), e = size(); i != e; ++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;
@@ -221,7 +238,7 @@ StringRef::size_type StringRef::find_first_of(StringRef Chars,
/// 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, size()), e = size(); i != e; ++i)
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
if (Data[i] != C)
return i;
return npos;
@@ -237,7 +254,7 @@ StringRef::size_type StringRef::find_first_not_of(StringRef Chars,
for (size_type i = 0; i != Chars.size(); ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()), e = size(); i != e; ++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;
@@ -253,7 +270,7 @@ StringRef::size_type StringRef::find_last_of(StringRef Chars,
for (size_type i = 0; i != Chars.size(); ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --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;
@@ -262,7 +279,7 @@ StringRef::size_type StringRef::find_last_of(StringRef Chars,
/// 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, size()) - 1, e = -1; i != e; --i)
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
if (Data[i] != C)
return i;
return npos;
@@ -278,7 +295,7 @@ StringRef::size_type StringRef::find_last_not_of(StringRef Chars,
for (size_type i = 0, e = Chars.size(); i != e; ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --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;
@@ -346,15 +363,18 @@ void StringRef::split(SmallVectorImpl<StringRef> &A, char Separator,
size_t StringRef::count(StringRef Str) const noexcept {
size_t Count = 0;
size_t N = Str.size();
if (N > size())
if (N > Length)
return 0;
for (size_t i = 0, e = size() - N + 1; i != e; ++i)
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;
@@ -370,17 +390,16 @@ static unsigned GetAutoSenseRadix(StringRef &Str) noexcept {
return 8;
}
if (Str.startswith("0"))
if (Str[0] == '0' && Str.size() > 1 && isDigit(Str[1])) {
Str = Str.substr(1);
return 8;
}
return 10;
}
/// 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 {
bool wpi::consumeUnsignedInteger(StringRef &Str, unsigned Radix,
unsigned long long &Result) noexcept {
// Autosense radix if not specified.
if (Radix == 0)
Radix = GetAutoSenseRadix(Str);
@@ -389,44 +408,51 @@ bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
if (Str.empty()) return true;
// Parse all the bytes of the string given this radix. Watch for overflow.
StringRef Str2 = Str;
Result = 0;
while (!Str.empty()) {
while (!Str2.empty()) {
unsigned CharVal;
if (Str[0] >= '0' && Str[0] <= '9')
CharVal = Str[0]-'0';
else if (Str[0] >= 'a' && Str[0] <= 'z')
CharVal = Str[0]-'a'+10;
else if (Str[0] >= 'A' && Str[0] <= 'Z')
CharVal = Str[0]-'A'+10;
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
return true;
break;
// If the parsed value is larger than the integer radix, the string is
// invalid.
// If the parsed value is larger than the integer radix, we cannot
// consume any more characters.
if (CharVal >= Radix)
return true;
break;
// Add in this character.
unsigned long long PrevResult = Result;
Result = Result*Radix+CharVal;
Result = Result * Radix + CharVal;
// Check for overflow by shifting back and seeing if bits were lost.
if (Result/Radix < PrevResult)
if (Result / Radix < PrevResult)
return true;
Str = Str.substr(1);
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::getAsSignedInteger(StringRef Str, unsigned Radix,
long long &Result) noexcept {
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 (getAsUnsignedInteger(Str, Radix, ULLVal) ||
if (consumeUnsignedInteger(Str, Radix, ULLVal) ||
// Check for value so large it overflows a signed value.
(long long)ULLVal < 0)
return true;
@@ -435,17 +461,46 @@ bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
}
// Get the positive part of the value.
if (getAsUnsignedInteger(Str.substr(1), Radix, ULLVal) ||
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

@@ -160,10 +160,10 @@ void Twine::printRepr(raw_ostream &OS) const {
OS << ")";
}
void Twine::dump() const {
LLVM_DUMP_METHOD void Twine::dump() const {
print(errs());
}
void Twine::dumpRepr() const {
LLVM_DUMP_METHOD void Twine::dumpRepr() const {
printRepr(errs());
}

View File

@@ -145,21 +145,20 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status,
else if (S_ISLNK(Status.st_mode))
Type = file_type::symlink_file;
perms Perms = static_cast<perms>(Status.st_mode);
Result =
file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime,
Status.st_mtime, Status.st_uid, Status.st_gid,
Status.st_size);
perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
Status.st_ino, Status.st_atime, Status.st_mtime,
Status.st_uid, Status.st_gid, Status.st_size);
return std::error_code();
}
std::error_code status(const Twine &Path, file_status &Result) {
std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
struct stat Status;
int StatRet = ::lstat(P.begin(), &Status);
int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
return fillStatus(StatRet, Status, Result);
}
@@ -170,7 +169,8 @@ std::error_code status(int FD, file_status &Result) {
}
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
StringRef path){
StringRef path,
bool follow_symlinks) {
SmallString<128> path_null(path);
DIR *directory = ::opendir(path_null.c_str());
if (!directory)
@@ -179,7 +179,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
it.IterationHandle = reinterpret_cast<intptr_t>(directory);
// Add something for replace_filename to replace.
path::append(path_null, ".");
it.CurrentEntry = directory_entry(path_null.str());
it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks);
return directory_iterator_increment(it);
}
@@ -208,6 +208,13 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
return std::error_code();
}
ErrorOr<basic_file_status> directory_entry::status() const {
file_status s;
if (auto EC = fs::status(Path, s, FollowSymlinks))
return EC;
return s;
}
#if !defined(F_GETPATH)
static bool hasProcSelfFD() {
// If we have a /proc filesystem mounted, we can quickly establish the
@@ -260,6 +267,10 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
int OpenFlags = O_CREAT;
#ifdef O_CLOEXEC
OpenFlags |= O_CLOEXEC;
#endif
if (Flags & F_RW)
OpenFlags |= O_RDWR;
else
@@ -267,7 +278,7 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
if (Flags & F_Append)
OpenFlags |= O_APPEND;
else
else if (!(Flags & F_NoTrunc))
OpenFlags |= O_TRUNC;
if (Flags & F_Excl)

View File

@@ -26,6 +26,7 @@
// These two headers must be included last, and make sure shlobj is required
// after Windows.h to make sure it picks up our definition of _WIN32_WINNT
#include "WindowsSupport.h"
#include <shellapi.h>
#include <shlobj.h>
#undef max
@@ -38,6 +39,7 @@
using namespace wpi;
using wpi::sys::windows::UTF8ToUTF16;
using wpi::sys::windows::CurCPToUTF16;
using wpi::sys::windows::UTF16ToUTF8;
using wpi::sys::path::widenPath;
@@ -87,13 +89,16 @@ std::error_code widenPath(const Twine &Path8,
return EC;
FullPath.append(CurPath);
}
// Traverse the requested path, canonicalizing . and .. as we go (because
// the \\?\ prefix is documented to treat them as real components).
// The iterators don't report separators and append() always attaches
// preferred_separator so we don't need to call native() on the result.
// Traverse the requested path, canonicalizing . and .. (because the \\?\
// prefix is documented to treat them as real components). Ignore
// separators, which can be returned from the iterator if the path has a
// drive name. We don't need to call native() on the result since append()
// always attaches preferred_separator.
for (wpi::sys::path::const_iterator I = wpi::sys::path::begin(Path8Str),
E = wpi::sys::path::end(Path8Str);
I != E; ++I) {
if (I->size() == 1 && is_separator((*I)[0]))
continue;
if (I->size() == 1 && *I == ".")
continue;
if (I->size() == 2 && *I == "..")
@@ -214,6 +219,15 @@ static bool isReservedName(StringRef path) {
return false;
}
static file_type file_type_from_attrs(DWORD Attrs) {
return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file
: file_type::regular_file;
}
static perms perms_from_attrs(DWORD Attrs) {
return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all;
}
static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
if (FileHandle == INVALID_HANDLE_VALUE)
goto handle_status_error;
@@ -243,19 +257,14 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
if (!::GetFileInformationByHandle(FileHandle, &Info))
goto handle_status_error;
{
file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
? file_type::directory_file
: file_type::regular_file;
Result =
file_status(Type, Info.ftLastAccessTime.dwHighDateTime,
Info.ftLastAccessTime.dwLowDateTime,
Info.ftLastWriteTime.dwHighDateTime,
Info.ftLastWriteTime.dwLowDateTime,
Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
return std::error_code();
}
Result = file_status(
file_type_from_attrs(Info.dwFileAttributes),
perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks,
Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime,
Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime,
Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow,
Info.nFileIndexHigh, Info.nFileIndexLow);
return std::error_code();
handle_status_error:
DWORD LastError = ::GetLastError();
@@ -269,7 +278,7 @@ handle_status_error:
return mapWindowsError(LastError);
}
std::error_code status(const Twine &path, file_status &result) {
std::error_code status(const Twine &path, file_status &result, bool Follow) {
SmallString<128> path_storage;
SmallVector<wchar_t, 128> path_utf16;
@@ -286,28 +295,19 @@ std::error_code status(const Twine &path, file_status &result) {
if (attr == INVALID_FILE_ATTRIBUTES)
return getStatus(INVALID_HANDLE_VALUE, result);
DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS;
// Handle reparse points.
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
ScopedFileHandle h(
::CreateFileW(path_utf16.begin(),
0, // Attributes only.
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
0));
if (!h)
return getStatus(INVALID_HANDLE_VALUE, result);
}
if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT))
Flags |= FILE_FLAG_OPEN_REPARSE_POINT;
ScopedFileHandle h(
::CreateFileW(path_utf16.begin(), 0, // Attributes only.
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
if (!h)
return getStatus(INVALID_HANDLE_VALUE, result);
NULL, OPEN_EXISTING, Flags, 0));
if (!h)
return getStatus(INVALID_HANDLE_VALUE, result);
return getStatus(h, result);
return getStatus(h, result);
}
std::error_code status(int FD, file_status &Result) {
@@ -315,8 +315,19 @@ std::error_code status(int FD, file_status &Result) {
return getStatus(FileHandle, Result);
}
static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) {
return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes),
perms_from_attrs(FindData->dwFileAttributes),
FindData->ftLastAccessTime.dwHighDateTime,
FindData->ftLastAccessTime.dwLowDateTime,
FindData->ftLastWriteTime.dwHighDateTime,
FindData->ftLastWriteTime.dwLowDateTime,
FindData->nFileSizeHigh, FindData->nFileSizeLow);
}
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
StringRef path){
StringRef path,
bool follow_symlinks) {
SmallVector<wchar_t, 128> path_utf16;
if (std::error_code ec = widenPath(path, path_utf16))
@@ -334,7 +345,9 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
// Get the first directory entry.
WIN32_FIND_DATAW FirstFind;
ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
ScopedFindHandle FindHandle(::FindFirstFileExW(
c_str(path_utf16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch,
NULL, FIND_FIRST_EX_LARGE_FETCH));
if (!FindHandle)
return mapWindowsError(::GetLastError());
@@ -361,7 +374,8 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
it.IterationHandle = intptr_t(FindHandle.take());
SmallString<128> directory_entry_path(path);
path::append(directory_entry_path, directory_entry_name_utf8);
it.CurrentEntry = directory_entry(directory_entry_path);
it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks,
status_from_find_data(&FirstFind));
return std::error_code();
}
@@ -397,12 +411,18 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
directory_entry_path_utf8))
return ec;
it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8),
status_from_find_data(&FindData));
return std::error_code();
}
ErrorOr<basic_file_status> directory_entry::status() const {
return Status;
}
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
SmallVectorImpl<char> *RealPath) {
ResultFD = -1;
SmallVector<wchar_t, 128> PathUTF16;
if (std::error_code EC = widenPath(Name, PathUTF16))
@@ -425,8 +445,8 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
return EC;
}
int FD = ::_open_osfhandle(intptr_t(H), 0);
if (FD == -1) {
ResultFD = ::_open_osfhandle(intptr_t(H), 0);
if (ResultFD == -1) {
::CloseHandle(H);
return mapWindowsError(ERROR_INVALID_HANDLE);
}
@@ -447,7 +467,6 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
}
}
ResultFD = FD;
return std::error_code();
}
@@ -457,6 +476,7 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
assert((!(Flags & F_Excl) || !(Flags & F_Append)) &&
"Cannot specify both 'excl' and 'append' file creation flags!");
ResultFD = -1;
SmallVector<wchar_t, 128> PathUTF16;
if (std::error_code EC = widenPath(Name, PathUTF16))
@@ -465,18 +485,24 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
DWORD CreationDisposition;
if (Flags & F_Excl)
CreationDisposition = CREATE_NEW;
else if (Flags & F_Append)
else if ((Flags & F_Append) || (Flags & F_NoTrunc))
CreationDisposition = OPEN_ALWAYS;
else
CreationDisposition = CREATE_ALWAYS;
DWORD Access = GENERIC_WRITE;
DWORD Attributes = FILE_ATTRIBUTE_NORMAL;
if (Flags & F_RW)
Access |= GENERIC_READ;
if (Flags & F_Delete) {
Access |= DELETE;
Attributes |= FILE_FLAG_DELETE_ON_CLOSE;
}
HANDLE H = ::CreateFileW(PathUTF16.begin(), Access,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE H =
::CreateFileW(PathUTF16.data(), Access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, CreationDisposition, Attributes, NULL);
if (H == INVALID_HANDLE_VALUE) {
DWORD LastError = ::GetLastError();
@@ -498,13 +524,12 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
if (Flags & F_Text)
OpenFlags |= _O_TEXT;
int FD = ::_open_osfhandle(intptr_t(H), OpenFlags);
if (FD == -1) {
ResultFD = ::_open_osfhandle(intptr_t(H), OpenFlags);
if (ResultFD == -1) {
::CloseHandle(H);
return mapWindowsError(ERROR_INVALID_HANDLE);
}
ResultFD = FD;
return std::error_code();
}
@@ -577,23 +602,26 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
} // end namespace path
namespace windows {
std::error_code UTF8ToUTF16(wpi::StringRef utf8,
wpi::SmallVectorImpl<wchar_t> &utf16) {
if (!utf8.empty()) {
int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
utf8.size(), utf16.begin(), 0);
std::error_code CodePageToUTF16(unsigned codepage,
wpi::StringRef original,
wpi::SmallVectorImpl<wchar_t> &utf16) {
if (!original.empty()) {
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
original.size(), utf16.begin(), 0);
if (len == 0)
if (len == 0) {
return mapWindowsError(::GetLastError());
}
utf16.reserve(len + 1);
utf16.set_size(len);
len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
utf8.size(), utf16.begin(), utf16.size());
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
original.size(), utf16.begin(), utf16.size());
if (len == 0)
if (len == 0) {
return mapWindowsError(::GetLastError());
}
}
// Make utf16 null terminated.
@@ -603,32 +631,44 @@ std::error_code UTF8ToUTF16(wpi::StringRef utf8,
return std::error_code();
}
std::error_code UTF8ToUTF16(wpi::StringRef utf8,
wpi::SmallVectorImpl<wchar_t> &utf16) {
return CodePageToUTF16(CP_UTF8, utf8, utf16);
}
std::error_code CurCPToUTF16(wpi::StringRef curcp,
wpi::SmallVectorImpl<wchar_t> &utf16) {
return CodePageToUTF16(CP_ACP, curcp, utf16);
}
static
std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16,
size_t utf16_len,
wpi::SmallVectorImpl<char> &utf8) {
wpi::SmallVectorImpl<char> &converted) {
if (utf16_len) {
// Get length.
int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(),
int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(),
0, NULL, NULL);
if (len == 0)
if (len == 0) {
return mapWindowsError(::GetLastError());
}
utf8.reserve(len);
utf8.set_size(len);
converted.reserve(len);
converted.set_size(len);
// Now do the actual conversion.
len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(),
utf8.size(), NULL, NULL);
len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(),
converted.size(), NULL, NULL);
if (len == 0)
if (len == 0) {
return mapWindowsError(::GetLastError());
}
}
// Make utf8 null terminated.
utf8.push_back(0);
utf8.pop_back();
// Make the new string null terminated.
converted.push_back(0);
converted.pop_back();
return std::error_code();
}
@@ -639,8 +679,8 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
}
std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
wpi::SmallVectorImpl<char> &utf8) {
return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8);
wpi::SmallVectorImpl<char> &curcp) {
return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp);
}
} // end namespace windows

View File

@@ -39,10 +39,10 @@
#include "wpi/StringRef.h"
#include "wpi/Twine.h"
#include "wpi/Compiler.h"
#include <system_error>
#include <windows.h>
#include <cassert>
#include <string>
#include <system_error>
#include <windows.h>
/// Determines if the program is running on Windows 8 or newer. This
/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended
@@ -199,6 +199,8 @@ std::error_code widenPath(const Twine &Path8,
namespace windows {
std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
/// Convert to UTF16 from the current code page used in the system
std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
SmallVectorImpl<char> &utf8);
/// Convert from UTF16 to the current code page used in the system

View File

@@ -12,15 +12,21 @@
//===----------------------------------------------------------------------===//
#include "wpi/raw_ostream.h"
#include "wpi/STLExtras.h"
#include "wpi/SmallString.h"
#include "wpi/SmallVector.h"
#include "wpi/StringExtras.h"
#include "wpi/Compiler.h"
#include "wpi/FileSystem.h"
#include "wpi/Format.h"
#include "wpi/MathExtras.h"
#include "wpi/NativeFormatting.h"
#include "wpi/WindowsError.h"
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <cstdio>
#include <iterator>
#include <sys/stat.h>
#include <system_error>
@@ -49,7 +55,7 @@
#endif
#endif
#if defined(_WIN32)
#ifdef _WIN32
#include "Windows/WindowsSupport.h"
#endif
@@ -102,73 +108,28 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
}
raw_ostream &raw_ostream::operator<<(unsigned long N) {
// Zero is a special case.
if (N == 0)
return *this << '0';
char NumberBuffer[20];
char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
char *CurPtr = EndPtr;
while (N) {
*--CurPtr = '0' + char(N % 10);
N /= 10;
}
return write(CurPtr, EndPtr-CurPtr);
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
return *this;
}
raw_ostream &raw_ostream::operator<<(long N) {
if (N < 0) {
*this << '-';
// Avoid undefined behavior on LONG_MIN with a cast.
N = -(unsigned long)N;
}
return this->operator<<(static_cast<unsigned long>(N));
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
return *this;
}
raw_ostream &raw_ostream::operator<<(unsigned long long N) {
// Output using 32-bit div/mod when possible.
if (N == static_cast<unsigned long>(N))
return this->operator<<(static_cast<unsigned long>(N));
char NumberBuffer[20];
char *EndPtr = std::end(NumberBuffer);
char *CurPtr = EndPtr;
while (N) {
*--CurPtr = '0' + char(N % 10);
N /= 10;
}
return write(CurPtr, EndPtr-CurPtr);
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
return *this;
}
raw_ostream &raw_ostream::operator<<(long long N) {
if (N < 0) {
*this << '-';
// Avoid undefined behavior on INT64_MIN with a cast.
N = -(unsigned long long)N;
}
return this->operator<<(static_cast<unsigned 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) {
// Zero is a special case.
if (N == 0)
return *this << '0';
char NumberBuffer[16];
char *EndPtr = std::end(NumberBuffer);
char *CurPtr = EndPtr;
while (N) {
unsigned char x = static_cast<unsigned char>(N) % 16;
*--CurPtr = hexdigit(x, /*LowerCase*/true);
N /= 16;
}
return write(CurPtr, EndPtr-CurPtr);
wpi::write_hex(*this, N, HexPrintStyle::Lower);
return *this;
}
raw_ostream &raw_ostream::write_escaped(StringRef Str,
@@ -212,54 +173,15 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str,
}
raw_ostream &raw_ostream::operator<<(const void *P) {
*this << '0' << 'x';
return write_hex((uintptr_t) P);
wpi::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower);
return *this;
}
raw_ostream &raw_ostream::operator<<(double N) {
#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))
return *this << "-0.000000e+00";
#else
int fpcl = _fpclass(N);
// negative zero
if (fpcl == _FPCLASS_NZ)
return *this << "-0.000000e+00";
#endif
char buf[16];
unsigned len;
len = format("%e", N).snprint(buf, sizeof(buf));
if (len <= sizeof(buf) - 2) {
if (len >= 5 && 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;
}
}
}
return this->operator<<(buf);
}
#endif
return this->operator<<(format("%e", 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;
@@ -336,10 +258,10 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
// Handle short strings specially, memcpy isn't very good at very short
// strings.
switch (Size) {
case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH
case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH
case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH
case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH
case 4: OutBufCur[3] = Ptr[3]; LLVM_FALLTHROUGH;
case 3: OutBufCur[2] = Ptr[2]; LLVM_FALLTHROUGH;
case 2: OutBufCur[1] = Ptr[1]; LLVM_FALLTHROUGH;
case 1: OutBufCur[0] = Ptr[0]; LLVM_FALLTHROUGH;
case 0: break;
default:
memcpy(OutBufCur, Ptr, Size);
@@ -374,7 +296,7 @@ raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
// space. Iterate until we win.
SmallVector<char, 128> V;
while (1) {
while (true) {
V.resize(NextBufferSize);
// Try formatting into the SmallVector.
@@ -391,82 +313,160 @@ raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
}
raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
unsigned Len = FS.Str.size();
int PadAmount = FS.Width - Len;
if (FS.RightJustify && (PadAmount > 0))
this->indent(PadAmount);
this->operator<<(FS.Str);
if (!FS.RightJustify && (PadAmount > 0))
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:
assert(false && "Bad Justification");
}
return *this;
}
raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
if (FN.Hex) {
unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4;
unsigned PrefixChars = FN.HexPrefix ? 2 : 0;
unsigned Width = std::max(FN.Width, Nibbles + PrefixChars);
char NumberBuffer[20] = "0x0000000000000000";
if (!FN.HexPrefix)
NumberBuffer[1] = '0';
char *EndPtr = NumberBuffer+Width;
char *CurPtr = EndPtr;
unsigned long long N = FN.HexValue;
while (N) {
unsigned char x = static_cast<unsigned char>(N) % 16;
*--CurPtr = hexdigit(x, !FN.Upper);
N /= 16;
}
return write(NumberBuffer, Width);
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 {
// Zero is a special case.
if (FN.DecValue == 0) {
this->indent(FN.Width-1);
return *this << '0';
}
char NumberBuffer[32];
char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
char *CurPtr = EndPtr;
bool Neg = (FN.DecValue < 0);
uint64_t N = Neg ? -static_cast<uint64_t>(FN.DecValue) : FN.DecValue;
while (N) {
*--CurPtr = '0' + char(N % 10);
N /= 10;
}
int Len = EndPtr - CurPtr;
int Pad = FN.Width - Len;
if (Neg)
--Pad;
if (Pad > 0)
this->indent(Pad);
if (Neg)
*this << '-';
return write(CurPtr, Len);
}
}
/// indent - Insert 'NumSpaces' spaces.
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
static const char Spaces[] = " "
" "
" ";
// Usually the indentation is small, handle it with a fastpath.
if (NumSpaces < array_lengthof(Spaces))
return write(Spaces, NumSpaces);
while (NumSpaces) {
unsigned NumToWrite = std::min(NumSpaces,
(unsigned)array_lengthof(Spaces)-1);
write(Spaces, NumToWrite);
NumSpaces -= NumToWrite;
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.hasValue()) {
// 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.hasValue()) {
uint64_t Offset = FB.FirstByteOffset.getValue();
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,
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C};
// Usually the indentation is small, handle it with a fastpath.
if (NumChars < array_lengthof(Chars))
return OS.write(Chars, NumChars);
while (NumChars) {
unsigned NumToWrite = std::min(NumChars,
(unsigned)array_lengthof(Chars)-1);
OS.write(Chars, NumToWrite);
NumChars -= NumToWrite;
}
return OS;
}
/// indent - Insert 'NumSpaces' spaces.
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
return write_padding<' '>(*this, NumSpaces);
}
/// write_zeros - Insert 'NumZeros' nulls.
raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
return write_padding<'\0'>(*this, NumZeros);
}
void raw_ostream::anchor() {}
//===----------------------------------------------------------------------===//
// Formatted Output
@@ -483,8 +483,7 @@ void format_object_base::home() {
static int getFD(StringRef Filename, std::error_code &EC,
sys::fs::OpenFlags Flags) {
// Handle "-" as stdout. Note that when we do this, we consider ourself
// the owner of stdout. This means that we can do things like close the
// file descriptor when we're done and set the "binary" flag globally.
// the owner of stdout and may set the "binary" flag globally based on Flags.
if (Filename == "-") {
EC = std::error_code();
// If user requested binary then put stdout into binary mode if
@@ -498,12 +497,10 @@ static int getFD(StringRef Filename, std::error_code &EC,
}
int FD;
EC = sys::fs::openFileForWrite(Filename, FD, Flags);
if (EC)
return -1;
EC = std::error_code();
return FD;
}
@@ -514,13 +511,21 @@ raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
/// closes the file when the stream is destroyed.
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
: raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose),
Error(false) {
: raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) {
if (FD < 0 ) {
ShouldClose = false;
return;
}
// Do not attempt to close stdout or stderr. We used to try to maintain the
// property that tools that support writing file to stdout should not also
// write informational output to stdout, but in practice we were never able to
// maintain this invariant. Many features have been added to LLVM and clang
// (-fdump-record-layouts, optimization remarks, etc) that print to stdout, so
// users must simply be aware that mixed output and remarks is a possibility.
if (FD <= STDERR_FILENO)
ShouldClose = false;
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);
#ifdef _WIN32
@@ -539,7 +544,7 @@ raw_fd_ostream::~raw_fd_ostream() {
if (FD >= 0) {
flush();
if (ShouldClose && ::close(FD) < 0)
error_detected();
error_detected(std::error_code(errno, std::generic_category()));
}
#ifdef __MINGW32__
@@ -551,25 +556,29 @@ raw_fd_ostream::~raw_fd_ostream() {
#endif
}
void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
assert(FD >= 0 && "File already closed.");
pos += Size;
#ifndef _WIN32
bool ShouldWriteInChunks = false;
#else
// The maximum write size is limited to SSIZE_MAX because a write
// greater than SSIZE_MAX is implementation-defined in POSIX.
// Since SSIZE_MAX is not portable, we use SIZE_MAX >> 1 instead.
size_t MaxWriteSize = SIZE_MAX >> 1;
#if defined(__linux__)
// It is observed that Linux returns EINVAL for a very large write (>2G).
// Make it a reasonably small value.
MaxWriteSize = 1024 * 1024 * 1024;
#elif defined(_WIN32)
// Writing a large size of output to Windows console returns ENOMEM. It seems
// that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and
// the latter has a size limit (66000 bytes or less, depending on heap usage).
bool ShouldWriteInChunks = !!::_isatty(FD) && !RunningWindows8OrGreater();
if (::_isatty(FD) && !RunningWindows8OrGreater())
MaxWriteSize = 32767;
#endif
do {
size_t ChunkSize = Size;
if (ChunkSize > 32767 && ShouldWriteInChunks)
ChunkSize = 32767;
size_t ChunkSize = std::min(Size, MaxWriteSize);
#ifdef _WIN32
int ret = ::_write(FD, Ptr, ChunkSize);
#else
@@ -593,7 +602,7 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
continue;
// Otherwise it's a non-recoverable error. Note it and quit.
error_detected();
error_detected(std::error_code(errno, std::generic_category()));
break;
}
@@ -610,16 +619,20 @@ void raw_fd_ostream::close() {
ShouldClose = false;
flush();
if (::close(FD) < 0)
error_detected();
error_detected(std::error_code(errno, std::generic_category()));
FD = -1;
}
uint64_t raw_fd_ostream::seek(uint64_t off) {
assert(SupportsSeeking && "Stream does not support seeking!");
flush();
#ifdef _WIN32
pos = ::_lseeki64(FD, off, SEEK_SET);
#else
pos = ::lseek(FD, off, SEEK_SET);
#endif
if (pos == (uint64_t)-1)
error_detected();
error_detected(std::error_code(errno, std::generic_category()));
return pos;
}
@@ -651,6 +664,8 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
#endif
}
void raw_fd_ostream::anchor() {}
//===----------------------------------------------------------------------===//
// outs(), errs(), nulls()
//===----------------------------------------------------------------------===//
@@ -658,10 +673,7 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
/// outs() - This returns a reference to a raw_ostream for standard output.
/// Use it like: outs() << "foo" << "bar";
raw_ostream &wpi::outs() {
// Set buffer settings to model stdout behavior. Delete the file descriptor
// when the program exits, forcing error detection. This means that if you
// ever call outs(), you can't open another raw_fd_ostream on stdout, as we'll
// close stdout twice and print an error the second time.
// Set buffer settings to model stdout behavior.
std::error_code EC;
static raw_fd_ostream S("-", EC, sys::fs::F_None);
assert(!EC);
@@ -682,7 +694,6 @@ raw_ostream &wpi::nulls() {
return S;
}
//===----------------------------------------------------------------------===//
// raw_string_ostream
//===----------------------------------------------------------------------===//
@@ -778,3 +789,5 @@ uint64_t raw_null_ostream::current_pos() const {
void raw_null_ostream::pwrite_impl(const char * /*Ptr*/, size_t /*Size*/,
uint64_t /*Offset*/) {}
void raw_pwrite_stream::anchor() {}

View File

@@ -0,0 +1,43 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "wpi/memory.h"
#include <exception>
#include "wpi/raw_ostream.h"
namespace wpi {
void* CheckedCalloc(size_t num, size_t size) {
void* p = std::calloc(num, size);
if (!p) {
errs() << "FATAL: failed to allocate " << (num * size) << " bytes\n";
std::terminate();
}
return p;
}
void* CheckedMalloc(size_t size) {
void* p = std::malloc(size == 0 ? 1 : size);
if (!p) {
errs() << "FATAL: failed to allocate " << size << " bytes\n";
std::terminate();
}
return p;
}
void* CheckedRealloc(void* ptr, size_t size) {
void* p = std::realloc(ptr, size == 0 ? 1 : size);
if (!p) {
errs() << "FATAL: failed to allocate " << size << " bytes\n";
std::terminate();
}
return p;
}
} // namespace wpi

View File

@@ -100,8 +100,8 @@ static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w,
* Hash a single 512-bit block. This is the core of the algorithm.
*/
static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS],
uint64_t& transforms) {
static void do_transform(uint32_t digest[], uint32_t block[BLOCK_INTS],
uint64_t& transforms) {
/* Copy digest[] to working vars */
uint32_t a = digest[0];
uint32_t b = digest[1];
@@ -227,7 +227,7 @@ void SHA1::Update(raw_istream& is) {
}
uint32_t block[BLOCK_INTS];
buffer_to_block(buffer, block);
transform(digest, block, transforms);
do_transform(digest, block, transforms);
buf_size = 0;
}
}
@@ -251,7 +251,7 @@ static void finalize(uint32_t digest[], unsigned char* buffer, size_t& buf_size,
buffer_to_block(buffer, block);
if (buf_size > BLOCK_BYTES - 8) {
transform(digest, block, transforms);
do_transform(digest, block, transforms);
for (size_t i = 0; i < BLOCK_INTS - 2; i++) {
block[i] = 0;
}
@@ -260,7 +260,7 @@ static void finalize(uint32_t digest[], unsigned char* buffer, size_t& buf_size,
/* Append total_bits, split this uint64_t into two uint32_t */
block[BLOCK_INTS - 1] = total_bits;
block[BLOCK_INTS - 2] = (total_bits >> 32);
transform(digest, block, transforms);
do_transform(digest, block, transforms);
/* Hex string */
static const char* const LUT = "0123456789abcdef";

View File

@@ -7,110 +7,24 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines the AlignOf function that computes alignments for
// arbitrary types.
// This file defines the AlignedCharArray and AlignedCharArrayUnion classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_ALIGNOF_H
#define LLVM_SUPPORT_ALIGNOF_H
#ifndef WPIUTIL_WPI_ALIGNOF_H
#define WPIUTIL_WPI_ALIGNOF_H
#include "wpi/Compiler.h"
#include <cstddef>
#include <type_traits>
namespace wpi {
namespace detail {
// For everything other than an abstract class we can calulate alignment by
// building a class with a single character and a member of the given type.
template <typename T, bool = std::is_abstract<T>::value>
struct AlignmentCalcImpl {
char x;
#if defined(_MSC_VER)
// Disables "structure was padded due to __declspec(align())" warnings that are
// generated by any class using AlignOf<T> with a manually specified alignment.
// Although the warning is disabled in the LLVM project we need this pragma
// as AlignOf.h is a published support header that's available for use
// out-of-tree, and we would like that to compile cleanly at /W4.
#pragma warning(suppress : 4324)
#endif
T t;
private:
AlignmentCalcImpl() = delete;
};
// Abstract base class helper, this will have the minimal alignment and size
// for any abstract class. We don't even define its destructor because this
// type should never be used in a way that requires it.
struct AlignmentCalcImplBase {
virtual ~AlignmentCalcImplBase() = 0;
};
// When we have an abstract class type, specialize the alignment computation
// engine to create another abstract class that derives from both an empty
// abstract base class and the provided type. This has the same effect as the
// above except that it handles the fact that we can't actually create a member
// of type T.
template <typename T>
struct AlignmentCalcImpl<T, true> : AlignmentCalcImplBase, T {
~AlignmentCalcImpl() override = 0;
};
} // End detail namespace.
/// AlignOf - A templated class that contains an enum value representing
/// the alignment of the template argument. For example,
/// AlignOf<int>::Alignment represents the alignment of type "int". The
/// alignment calculated is the minimum alignment, and not necessarily
/// the "desired" alignment returned by GCC's __alignof__ (for example). Note
/// that because the alignment is an enum value, it can be used as a
/// compile-time constant (e.g., for template instantiation).
template <typename T>
struct AlignOf {
#ifndef _MSC_VER
// Avoid warnings from GCC like:
// comparison between 'enum wpi::AlignOf<X>::<anonymous>' and 'enum
// wpi::AlignOf<Y>::<anonymous>' [-Wenum-compare]
// by using constexpr instead of enum.
// (except on MSVC, since it doesn't support constexpr yet).
static constexpr unsigned Alignment = static_cast<unsigned int>(
sizeof(detail::AlignmentCalcImpl<T>) - sizeof(T));
#else
enum {
Alignment = static_cast<unsigned int>(
sizeof(::wpi::detail::AlignmentCalcImpl<T>) - sizeof(T))
};
#endif
enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };
enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 };
enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 };
enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 };
enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 };
enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };
};
#ifndef _MSC_VER
template <typename T> constexpr unsigned AlignOf<T>::Alignment;
#endif
/// alignOf - A templated function that returns the minimum alignment of
/// of a type. This provides no extra functionality beyond the AlignOf
/// class besides some cosmetic cleanliness. Example usage:
/// alignOf<int>() returns the alignment of an int.
template <typename T>
inline unsigned alignOf() { return AlignOf<T>::Alignment; }
/// \struct AlignedCharArray
/// \brief Helper for building an aligned character array type.
/// Helper for building an aligned character array type.
///
/// This template is used to explicitly build up a collection of aligned
/// character array types. We have to build these up using a macro and explicit
/// specialization to cope with old versions of MSVC and GCC where only an
/// specialization to cope with MSVC (at least till 2015) where only an
/// integer literal can be used to specify an alignment constraint. Once built
/// up here, we can then begin to indirect between these using normal C++
/// template parameters.
@@ -118,41 +32,14 @@ inline unsigned alignOf() { return AlignOf<T>::Alignment; }
// MSVC requires special handling here.
#ifndef _MSC_VER
#if __has_feature(cxx_alignas)
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray {
alignas(Alignment) char buffer[Size];
LLVM_ALIGNAS(Alignment) char buffer[Size];
};
#elif defined(__GNUC__) || defined(__IBM_ATTRIBUTES)
/// \brief Create a type with an aligned char buffer.
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray;
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
template<std::size_t Size> \
struct AlignedCharArray<x, Size> { \
__attribute__((aligned(x))) char buffer[Size]; \
};
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
#else
# error No supported align as directive.
#endif
#else // _MSC_VER
/// \brief Create a type with an aligned char buffer.
/// Create a type with an aligned char buffer.
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray;
@@ -237,7 +124,7 @@ union SizerImpl {
};
} // end namespace detail
/// \brief This union template exposes a suitably aligned and sized character
/// This union template exposes a suitably aligned and sized character
/// array member which can hold elements of any of up to ten types.
///
/// These types may be arrays, structs, or any other types. The goal is to
@@ -249,8 +136,8 @@ template <typename T1,
typename T5 = char, typename T6 = char, typename T7 = char,
typename T8 = char, typename T9 = char, typename T10 = char>
struct AlignedCharArrayUnion : wpi::AlignedCharArray<
AlignOf<wpi::detail::AlignerImpl<T1, T2, T3, T4, T5,
T6, T7, T8, T9, T10> >::Alignment,
alignof(wpi::detail::AlignerImpl<T1, T2, T3, T4, T5,
T6, T7, T8, T9, T10>),
sizeof(::wpi::detail::SizerImpl<T1, T2, T3, T4, T5,
T6, T7, T8, T9, T10>)> {
};

View File

@@ -1,4 +1,4 @@
//===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===//
//===- ArrayRef.h - Array Reference Wrapper ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,13 +7,22 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ARRAYREF_H
#define LLVM_ADT_ARRAYREF_H
#ifndef WPIUTIL_WPI_ARRAYREF_H
#define WPIUTIL_WPI_ARRAYREF_H
#include "wpi/Compiler.h"
#include "wpi/Hashing.h"
#include "wpi/None.h"
#include "wpi/SmallVector.h"
#include "wpi/STLExtras.h"
#include "wpi/Compiler.h"
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <memory>
#include <type_traits>
#include <vector>
namespace wpi {
@@ -29,31 +38,30 @@ namespace wpi {
/// This is intended to be trivially copyable, so it should be passed by
/// value.
template<typename T>
class ArrayRef {
class LLVM_NODISCARD ArrayRef {
public:
typedef const T *iterator;
typedef const T *const_iterator;
typedef size_t size_type;
typedef T value_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
using iterator = const T *;
using const_iterator = const T *;
using size_type = size_t;
using reverse_iterator = std::reverse_iterator<iterator>;
using value_type = T;
private:
/// The start of the array, in an external buffer.
const T *Data;
const T *Data = nullptr;
/// The number of elements.
size_type Length;
size_type Length = 0;
public:
/// @name Constructors
/// @{
/// Construct an empty ArrayRef.
/*implicit*/ ArrayRef() : Data(nullptr), Length(0) {}
/*implicit*/ ArrayRef() = default;
/// Construct an empty ArrayRef from None.
/*implicit*/ ArrayRef(NoneType) : Data(nullptr), Length(0) {}
/*implicit*/ ArrayRef(NoneType) {}
/// Construct an ArrayRef from a single element.
/*implicit*/ ArrayRef(const T &OneElt)
@@ -80,10 +88,14 @@ namespace wpi {
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
: Data(Vec.data()), Length(Vec.size()) {}
/// Construct an ArrayRef from a std::array
template <size_t N>
/*implicit*/ constexpr ArrayRef(const std::array<T, N> &Arr)
: Data(Arr.data()), Length(N) {}
/// Construct an ArrayRef from a C array.
template <size_t N>
/*implicit*/ LLVM_CONSTEXPR ArrayRef(const T (&Arr)[N])
: Data(Arr), Length(N) {}
/*implicit*/ constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {}
/// Construct an ArrayRef from a std::initializer_list.
/*implicit*/ ArrayRef(const std::initializer_list<T> &Vec)
@@ -162,12 +174,6 @@ namespace wpi {
return std::equal(begin(), end(), RHS.begin());
}
/// slice(n) - Chop off the first N elements of the array.
ArrayRef<T> slice(size_t N) const {
assert(N <= size() && "Invalid specifier");
return ArrayRef<T>(data()+N, size()-N);
}
/// slice(n, m) - Chop off the first N elements of the array, and keep M
/// elements in the array.
ArrayRef<T> slice(size_t N, size_t M) const {
@@ -175,18 +181,59 @@ namespace wpi {
return ArrayRef<T>(data()+N, M);
}
/// \brief Drop the first \p N elements of the array.
/// slice(n) - Chop off the first N elements of the array.
ArrayRef<T> slice(size_t N) const { return slice(N, size() - N); }
/// Drop the first \p N elements of the array.
ArrayRef<T> drop_front(size_t N = 1) const {
assert(size() >= N && "Dropping more elements than exist");
return slice(N, size() - N);
}
/// \brief Drop the last \p N elements of the array.
/// Drop the last \p N elements of the array.
ArrayRef<T> drop_back(size_t N = 1) const {
assert(size() >= N && "Dropping more elements than exist");
return slice(0, size() - N);
}
/// Return a copy of *this with the first N elements satisfying the
/// given predicate removed.
template <class PredicateT> ArrayRef<T> drop_while(PredicateT Pred) const {
return ArrayRef<T>(find_if_not(*this, Pred), end());
}
/// Return a copy of *this with the first N elements not satisfying
/// the given predicate removed.
template <class PredicateT> ArrayRef<T> drop_until(PredicateT Pred) const {
return ArrayRef<T>(find_if(*this, Pred), end());
}
/// Return a copy of *this with only the first \p N elements.
ArrayRef<T> take_front(size_t N = 1) const {
if (N >= size())
return *this;
return drop_back(size() - N);
}
/// Return a copy of *this with only the last \p N elements.
ArrayRef<T> take_back(size_t N = 1) const {
if (N >= size())
return *this;
return drop_front(size() - N);
}
/// Return the first N elements of this Array that satisfy the given
/// predicate.
template <class PredicateT> ArrayRef<T> take_while(PredicateT Pred) const {
return ArrayRef<T>(begin(), find_if_not(*this, Pred));
}
/// Return the first N elements of this Array that don't satisfy the
/// given predicate.
template <class PredicateT> ArrayRef<T> take_until(PredicateT Pred) const {
return ArrayRef<T>(begin(), find_if(*this, Pred));
}
/// @}
/// @name Operator Overloads
/// @{
@@ -195,6 +242,22 @@ namespace wpi {
return Data[Index];
}
/// Disallow accidental assignment from a temporary.
///
/// The declaration here is extra complicated so that "arrayRef = {}"
/// continues to select the move assignment operator.
template <typename U>
typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
operator=(U &&Temporary) = delete;
/// Disallow accidental assignment from a temporary.
///
/// The declaration here is extra complicated so that "arrayRef = {}"
/// continues to select the move assignment operator.
template <typename U>
typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
operator=(std::initializer_list<U>) = delete;
/// @}
/// @name Expensive Operations
/// @{
@@ -225,14 +288,13 @@ namespace wpi {
/// This is intended to be trivially copyable, so it should be passed by
/// value.
template<typename T>
class MutableArrayRef : public ArrayRef<T> {
class LLVM_NODISCARD MutableArrayRef : public ArrayRef<T> {
public:
typedef T *iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
using iterator = T *;
using reverse_iterator = std::reverse_iterator<iterator>;
/// Construct an empty MutableArrayRef.
/*implicit*/ MutableArrayRef() : ArrayRef<T>() {}
/*implicit*/ MutableArrayRef() = default;
/// Construct an empty MutableArrayRef from None.
/*implicit*/ MutableArrayRef(NoneType) : ArrayRef<T>() {}
@@ -255,10 +317,14 @@ namespace wpi {
/*implicit*/ MutableArrayRef(std::vector<T> &Vec)
: ArrayRef<T>(Vec) {}
/// Construct an ArrayRef from a std::array
template <size_t N>
/*implicit*/ constexpr MutableArrayRef(std::array<T, N> &Arr)
: ArrayRef<T>(Arr) {}
/// Construct an MutableArrayRef from a C array.
template <size_t N>
/*implicit*/ LLVM_CONSTEXPR MutableArrayRef(T (&Arr)[N])
: ArrayRef<T>(Arr) {}
/*implicit*/ constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef<T>(Arr) {}
T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
@@ -280,20 +346,19 @@ namespace wpi {
return data()[this->size()-1];
}
/// slice(n) - Chop off the first N elements of the array.
MutableArrayRef<T> slice(size_t N) const {
assert(N <= this->size() && "Invalid specifier");
return MutableArrayRef<T>(data()+N, this->size()-N);
}
/// slice(n, m) - Chop off the first N elements of the array, and keep M
/// elements in the array.
MutableArrayRef<T> slice(size_t N, size_t M) const {
assert(N+M <= this->size() && "Invalid specifier");
return MutableArrayRef<T>(data()+N, M);
assert(N + M <= this->size() && "Invalid specifier");
return MutableArrayRef<T>(this->data() + N, M);
}
/// \brief Drop the first \p N elements of the array.
/// slice(n) - Chop off the first N elements of the array.
MutableArrayRef<T> slice(size_t N) const {
return slice(N, this->size() - N);
}
/// Drop the first \p N elements of the array.
MutableArrayRef<T> drop_front(size_t N = 1) const {
assert(this->size() >= N && "Dropping more elements than exist");
return slice(N, this->size() - N);
@@ -304,6 +369,48 @@ namespace wpi {
return slice(0, this->size() - N);
}
/// Return a copy of *this with the first N elements satisfying the
/// given predicate removed.
template <class PredicateT>
MutableArrayRef<T> drop_while(PredicateT Pred) const {
return MutableArrayRef<T>(find_if_not(*this, Pred), end());
}
/// Return a copy of *this with the first N elements not satisfying
/// the given predicate removed.
template <class PredicateT>
MutableArrayRef<T> drop_until(PredicateT Pred) const {
return MutableArrayRef<T>(find_if(*this, Pred), end());
}
/// Return a copy of *this with only the first \p N elements.
MutableArrayRef<T> take_front(size_t N = 1) const {
if (N >= this->size())
return *this;
return drop_back(this->size() - N);
}
/// Return a copy of *this with only the last \p N elements.
MutableArrayRef<T> take_back(size_t N = 1) const {
if (N >= this->size())
return *this;
return drop_front(this->size() - N);
}
/// Return the first N elements of this Array that satisfy the given
/// predicate.
template <class PredicateT>
MutableArrayRef<T> take_while(PredicateT Pred) const {
return MutableArrayRef<T>(begin(), find_if_not(*this, Pred));
}
/// Return the first N elements of this Array that don't satisfy the
/// given predicate.
template <class PredicateT>
MutableArrayRef<T> take_until(PredicateT Pred) const {
return MutableArrayRef<T>(begin(), find_if(*this, Pred));
}
/// @}
/// @name Operator Overloads
/// @{
@@ -313,6 +420,29 @@ namespace wpi {
}
};
/// This is a MutableArrayRef that owns its array.
template <typename T> class OwningArrayRef : public MutableArrayRef<T> {
public:
OwningArrayRef() = default;
OwningArrayRef(size_t Size) : MutableArrayRef<T>(new T[Size], Size) {}
OwningArrayRef(ArrayRef<T> Data)
: MutableArrayRef<T>(new T[Data.size()], Data.size()) {
std::copy(Data.begin(), Data.end(), this->begin());
}
OwningArrayRef(OwningArrayRef &&Other) { *this = Other; }
OwningArrayRef &operator=(OwningArrayRef &&Other) {
delete[] this->data();
this->MutableArrayRef<T>::operator=(Other);
Other.MutableArrayRef<T>::operator=(MutableArrayRef<T>());
return *this;
}
~OwningArrayRef() { delete[] this->data(); }
};
/// @name ArrayRef Convenience constructors
/// @{
@@ -368,6 +498,18 @@ namespace wpi {
return ArrayRef<T>(Arr);
}
/// Construct a MutableArrayRef from a single element.
template<typename T>
MutableArrayRef<T> makeMutableArrayRef(T &OneElt) {
return OneElt;
}
/// Construct a MutableArrayRef from a pointer and length.
template<typename T>
MutableArrayRef<T> makeMutableArrayRef(T *data, size_t length) {
return MutableArrayRef<T>(data, length);
}
/// @}
/// @name ArrayRef Comparison Operators
/// @{
@@ -386,13 +528,14 @@ namespace wpi {
// ArrayRefs can be treated like a POD type.
template <typename T> struct isPodLike;
template <typename T> struct isPodLike<ArrayRef<T> > {
template <typename T> struct isPodLike<ArrayRef<T>> {
static const bool value = true;
};
template <typename T> hash_code hash_value(ArrayRef<T> S) {
return hash_combine_range(S.begin(), S.end());
}
} // end namespace wpi
#endif // LLVM_ADT_ARRAYREF_H

View File

@@ -12,8 +12,12 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_COMPILER_H
#define LLVM_SUPPORT_COMPILER_H
#ifndef WPIUTIL_WPI_COMPILER_H
#define WPIUTIL_WPI_COMPILER_H
#if defined(_MSC_VER)
#include <sal.h>
#endif
#ifndef __has_feature
# define __has_feature(x) 0
@@ -27,12 +31,16 @@
# define __has_attribute(x) 0
#endif
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
/// \macro LLVM_GNUC_PREREQ
/// \brief Extend the default __GNUC_PREREQ even if glibc's features.h isn't
/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
/// available.
#ifndef LLVM_GNUC_PREREQ
# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
@@ -47,39 +55,116 @@
# endif
#endif
#ifndef LLVM_CONSTEXPR
# ifdef _MSC_VER
# if _MSC_VER >= 1900
# define LLVM_CONSTEXPR constexpr
# else
# define LLVM_CONSTEXPR
# endif
# elif defined(__has_feature)
# if __has_feature(cxx_constexpr)
# define LLVM_CONSTEXPR constexpr
# else
# define LLVM_CONSTEXPR
# endif
# elif defined(__GXX_EXPERIMENTAL_CXX0X__)
# define LLVM_CONSTEXPR constexpr
# elif defined(__has_constexpr)
# define LLVM_CONSTEXPR constexpr
# else
# define LLVM_CONSTEXPR
# endif
/// \macro LLVM_MSC_PREREQ
/// Is the compiler MSVC of at least the specified version?
/// The common \param version values to check for are:
/// * 1900: Microsoft Visual Studio 2015 / 14.0
#ifndef LLVM_MSC_PREREQ
#ifdef _MSC_VER
#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
// We require at least MSVC 2015.
#if !LLVM_MSC_PREREQ(1900)
#error wpiutil requires at least MSVC 2015.
#endif
#ifndef LLVM_ATTRIBUTE_UNUSED_RESULT
#if __has_attribute(warn_unused_result) || LLVM_GNUC_PREREQ(3, 4, 0)
#define LLVM_ATTRIBUTE_UNUSED_RESULT __attribute__((__warn_unused_result__))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_UNUSED_RESULT _Check_return_
#else
#define LLVM_ATTRIBUTE_UNUSED_RESULT
#define LLVM_MSC_PREREQ(version) 0
#endif
#endif
#ifndef LLVM_UNLIKELY
/// Does the compiler support ref-qualifiers for *this?
///
/// Sadly, this is separate from just rvalue reference support because GCC
/// and MSVC implemented this later than everything else.
#ifndef LLVM_HAS_RVALUE_REFERENCE_THIS
#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1)
#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
#else
#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
#endif
#endif
/// Expands to '&' if ref-qualifiers for *this are supported.
///
/// This can be used to provide lvalue/rvalue overrides of member functions.
/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
#ifndef LLVM_LVALUE_FUNCTION
#if LLVM_HAS_RVALUE_REFERENCE_THIS
#define LLVM_LVALUE_FUNCTION &
#else
#define LLVM_LVALUE_FUNCTION
#endif
#endif
#ifndef LLVM_PREFETCH
#if defined(__GNUC__)
#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
#else
#define LLVM_PREFETCH(addr, rw, locality)
#endif
#endif
#ifndef LLVM_ATTRIBUTE_USED
#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
#else
#define LLVM_ATTRIBUTE_USED
#endif
#endif
/// LLVM_NODISCARD - Warn if a type or return value is discarded.
#ifndef LLVM_NODISCARD
#if __cplusplus > 201402L && __has_cpp_attribute(nodiscard)
#define LLVM_NODISCARD [[nodiscard]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define LLVM_NODISCARD
#elif __has_cpp_attribute(clang::warn_unused_result)
#define LLVM_NODISCARD [[clang::warn_unused_result]]
#else
#define LLVM_NODISCARD
#endif
#endif
// Some compilers warn about unused functions. When a function is sometimes
// used or not depending on build settings (e.g. a function only called from
// within "assert"), this attribute can be used to suppress such warnings.
//
// However, it shouldn't be used for unused *variables*, as those have a much
// more portable solution:
// (void)unused_var_name;
// Prefer cast-to-void wherever it is sufficient.
#ifndef LLVM_ATTRIBUTE_UNUSED
#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0)
#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
#else
#define LLVM_ATTRIBUTE_UNUSED
#endif
#endif
#ifndef LLVM_READNONE
// Prior to clang 3.2, clang did not accept any spelling of
// __has_attribute(const), so assume it is supported.
#if defined(__clang__) || defined(__GNUC__)
// aka 'CONST' but following LLVM Conventions.
#define LLVM_READNONE __attribute__((__const__))
#else
#define LLVM_READNONE
#endif
#endif
#ifndef LLVM_READONLY
#if __has_attribute(pure) || defined(__GNUC__)
// aka 'PURE' but following LLVM Conventions.
#define LLVM_READONLY __attribute__((__pure__))
#else
#define LLVM_READONLY
#endif
#endif
#ifndef LLVM_LIKELY
#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0)
#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
@@ -89,4 +174,253 @@
#endif
#endif
/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
/// mark a method "not for inlining".
#ifndef LLVM_ATTRIBUTE_NOINLINE
#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
#else
#define LLVM_ATTRIBUTE_NOINLINE
#endif
#endif
/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
/// so, mark a method "always inline" because it is performance sensitive. GCC
/// 3.4 supported this but is buggy in various cases and produces unimplemented
/// errors, just use it in GCC 4.0 and later.
#ifndef LLVM_ATTRIBUTE_ALWAYS_INLINE
#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
#else
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
#endif
#endif
#ifndef LLVM_ATTRIBUTE_NORETURN
#ifdef __GNUC__
#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
#else
#define LLVM_ATTRIBUTE_NORETURN
#endif
#endif
#ifndef LLVM_ATTRIBUTE_RETURNS_NONNULL
#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
#else
#define LLVM_ATTRIBUTE_RETURNS_NONNULL
#endif
#endif
/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
/// pointer that does not alias any other valid pointer.
#ifndef LLVM_ATTRIBUTE_RETURNS_NOALIAS
#ifdef __GNUC__
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
#else
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
#endif
#endif
/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
#ifndef LLVM_FALLTHROUGH
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#define LLVM_FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define LLVM_FALLTHROUGH
#elif __has_cpp_attribute(clang::fallthrough)
#define LLVM_FALLTHROUGH [[clang::fallthrough]]
#else
#define LLVM_FALLTHROUGH
#endif
#endif
/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
/// pedantic diagnostics.
#ifndef LLVM_EXTENSION
#ifdef __GNUC__
#define LLVM_EXTENSION __extension__
#else
#define LLVM_EXTENSION
#endif
#endif
// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
#ifndef LLVM_ATTRIBUTE_DEPRECATED
#if __has_feature(attribute_deprecated_with_message)
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
decl __attribute__((deprecated(message)))
#elif defined(__GNUC__)
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
decl __attribute__((deprecated))
#elif defined(_MSC_VER)
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
__declspec(deprecated(message)) decl
#else
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
decl
#endif
#endif
/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
/// to an expression which states that it is undefined behavior for the
/// compiler to reach this point. Otherwise is not defined.
#ifndef LLVM_BUILTIN_UNREACHABLE
#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
# define LLVM_BUILTIN_UNREACHABLE __assume(false)
#endif
#endif
/// \macro LLVM_ASSUME_ALIGNED
/// Returns a pointer with an assumed alignment.
#ifndef LLVM_ASSUME_ALIGNED
#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
#elif defined(LLVM_BUILTIN_UNREACHABLE)
// As of today, clang does not support __builtin_assume_aligned.
# define LLVM_ASSUME_ALIGNED(p, a) \
(((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
#else
# define LLVM_ASSUME_ALIGNED(p, a) (p)
#endif
#endif
/// \macro LLVM_ALIGNAS
/// Used to specify a minimum alignment for a structure or variable.
#ifndef LLVM_ALIGNAS
#if __GNUC__ && !__has_feature(cxx_alignas) && !LLVM_GNUC_PREREQ(4, 8, 1)
# define LLVM_ALIGNAS(x) __attribute__((aligned(x)))
#else
# define LLVM_ALIGNAS(x) alignas(x)
#endif
#endif
/// \macro LLVM_PACKED
/// Used to specify a packed structure.
/// LLVM_PACKED(
/// struct A {
/// int i;
/// int j;
/// int k;
/// long long l;
/// });
///
/// LLVM_PACKED_START
/// struct B {
/// int i;
/// int j;
/// int k;
/// long long l;
/// };
/// LLVM_PACKED_END
#ifndef LLVM_PACKED
#ifdef _MSC_VER
# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
# define LLVM_PACKED_START __pragma(pack(push, 1))
# define LLVM_PACKED_END __pragma(pack(pop))
#else
# define LLVM_PACKED(d) d __attribute__((packed))
# define LLVM_PACKED_START _Pragma("pack(push, 1)")
# define LLVM_PACKED_END _Pragma("pack(pop)")
#endif
#endif
/// \macro LLVM_PTR_SIZE
/// A constant integer equivalent to the value of sizeof(void*).
/// Generally used in combination with LLVM_ALIGNAS or when doing computation in
/// the preprocessor.
#ifndef LLVM_PTR_SIZE
#ifdef __SIZEOF_POINTER__
# define LLVM_PTR_SIZE __SIZEOF_POINTER__
#elif defined(_WIN64)
# define LLVM_PTR_SIZE 8
#elif defined(_WIN32)
# define LLVM_PTR_SIZE 4
#elif defined(_MSC_VER)
# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
#else
# define LLVM_PTR_SIZE sizeof(void *)
#endif
#endif
/// \macro LLVM_NO_SANITIZE
/// Disable a particular sanitizer for a function.
#ifndef LLVM_NO_SANITIZE
#if __has_attribute(no_sanitize)
#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
#else
#define LLVM_NO_SANITIZE(KIND)
#endif
#endif
/// Mark debug helper function definitions like dump() that should not be
/// stripped from debug builds.
/// Note that you should also surround dump() functions with
/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
/// get stripped in release builds.
// FIXME: Move this to a private config.h as it's not usable in public headers.
#ifndef LLVM_DUMP_METHOD
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
#else
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
#endif
#endif
/// \macro LLVM_PRETTY_FUNCTION
/// Gets a user-friendly looking function signature for the current scope
/// using the best available method on each platform. The exact format of the
/// resulting string is implementation specific and non-portable, so this should
/// only be used, for example, for logging or diagnostics.
#ifndef LLVM_PRETTY_FUNCTION
#if defined(_MSC_VER)
#define LLVM_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__GNUC__) || defined(__clang__)
#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define LLVM_PRETTY_FUNCTION __func__
#endif
#endif
/// \macro LLVM_THREAD_LOCAL
/// A thread-local storage specifier which can be used with globals,
/// extern globals, and static globals.
///
/// This is essentially an extremely restricted analog to C++11's thread_local
/// support, and uses that when available. However, it falls back on
/// platform-specific or vendor-provided extensions when necessary. These
/// extensions don't support many of the C++11 thread_local's features. You
/// should only use this for PODs that you can statically initialize to
/// some constant value. In almost all circumstances this is most appropriate
/// for use with a pointer, integer, or small aggregation of pointers and
/// integers.
#ifndef LLVM_THREAD_LOCAL
#if __has_feature(cxx_thread_local)
#define LLVM_THREAD_LOCAL thread_local
#elif defined(_MSC_VER)
// MSVC supports this with a __declspec.
#define LLVM_THREAD_LOCAL __declspec(thread)
#else
// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
// we only need the restricted functionality that provides.
#define LLVM_THREAD_LOCAL __thread
#endif
#endif
#endif

View File

@@ -90,6 +90,17 @@
#ifndef LLVM_SUPPORT_CONVERTUTF_H
#define LLVM_SUPPORT_CONVERTUTF_H
#include "wpi/ArrayRef.h"
#include "wpi/StringRef.h"
#include <cstddef>
#include <string>
// Wrap everything in namespace wpi so that programs can link with wpiutil and
// their own version of the unicode libraries.
namespace wpi {
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
@@ -127,11 +138,6 @@ typedef enum {
lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
#ifdef __cplusplus
extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
@@ -174,16 +180,9 @@ Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
unsigned getNumBytesForUTF8(UTF8 firstByte);
#ifdef __cplusplus
}
/*************************************************************************/
/* Below are LLVM-specific wrappers of the functions above. */
#include "wpi/ArrayRef.h"
#include "wpi/StringRef.h"
namespace wpi {
/**
* Convert an Unicode code point to UTF8 sequence.
@@ -249,7 +248,3 @@ bool convertUTF8ToUTF16String(StringRef SrcUTF8,
} /* end namespace wpi */
#endif
/* --------------------------------------------------------------------- */
#endif

View File

@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_DENSEMAP_H
#define LLVM_ADT_DENSEMAP_H
#ifndef WPIUTIL_WPI_DENSEMAP_H
#define WPIUTIL_WPI_DENSEMAP_H
#include "wpi/DenseMapInfo.h"
#include "wpi/EpochTracker.h"
@@ -23,16 +23,17 @@
#include "wpi/type_traits.h"
#include <algorithm>
#include <cassert>
#include <climits>
#include <cstddef>
#include <cstring>
#include <iterator>
#include <new>
#include <type_traits>
#include <utility>
namespace wpi {
namespace detail {
// We extend a pair to allow users to override the bucket type with their own
// implementation without requiring two members.
template <typename KeyT, typename ValueT>
@@ -42,7 +43,8 @@ struct DenseMapPair : public std::pair<KeyT, ValueT> {
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
};
}
} // end namespace detail
template <
typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo<KeyT>,
@@ -52,31 +54,39 @@ class DenseMapIterator;
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
typename BucketT>
class DenseMapBase : public DebugEpochBase {
public:
typedef unsigned size_type;
typedef KeyT key_type;
typedef ValueT mapped_type;
typedef BucketT value_type;
template <typename T>
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
public:
using size_type = unsigned;
using key_type = KeyT;
using mapped_type = ValueT;
using value_type = BucketT;
using iterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT>;
using const_iterator =
DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>;
typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT> iterator;
typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>
const_iterator;
inline iterator begin() {
// When the map is empty, avoid the overhead of AdvancePastEmptyBuckets().
return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this);
// When the map is empty, avoid the overhead of advancing/retreating past
// empty buckets.
if (empty())
return end();
return makeIterator(getBuckets(), getBucketsEnd(), *this);
}
inline iterator end() {
return iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
return makeIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
}
inline const_iterator begin() const {
return empty() ? end()
: const_iterator(getBuckets(), getBucketsEnd(), *this);
if (empty())
return end();
return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
}
inline const_iterator end() const {
return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
}
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
LLVM_NODISCARD bool empty() const {
return getNumEntries() == 0;
}
unsigned size() const { return getNumEntries(); }
@@ -102,37 +112,43 @@ public:
}
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
unsigned NumEntries = getNumEntries();
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
P->getSecond().~ValueT();
--NumEntries;
}
if (isPodLike<KeyT>::value && isPodLike<ValueT>::value) {
// Use a simpler loop when these are trivial types.
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
P->getFirst() = EmptyKey;
} else {
unsigned NumEntries = getNumEntries();
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
P->getSecond().~ValueT();
--NumEntries;
}
P->getFirst() = EmptyKey;
}
}
assert(NumEntries == 0 && "Node count imbalance!");
}
assert(NumEntries == 0 && "Node count imbalance!");
setNumEntries(0);
setNumTombstones(0);
}
/// Return 1 if the specified key is in the map, 0 otherwise.
size_type count(const KeyT &Val) const {
size_type count(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
return LookupBucketFor(Val, TheBucket) ? 1 : 0;
}
iterator find(const KeyT &Val) {
iterator find(const_arg_type_t<KeyT> Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return iterator(TheBucket, getBucketsEnd(), *this, true);
return makeIterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
const_iterator find(const KeyT &Val) const {
const_iterator find(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
@@ -145,20 +161,20 @@ public:
iterator find_as(const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return iterator(TheBucket, getBucketsEnd(), *this, true);
return makeIterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
template<class LookupKeyT>
const_iterator find_as(const LookupKeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
/// lookup - Return the entry for the specified key, or a default
/// constructed value if no such entry exists.
ValueT lookup(const KeyT &Val) const {
ValueT lookup(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return TheBucket->getSecond();
@@ -169,32 +185,51 @@ public:
// If the key is already in the map, it returns false and doesn't update the
// value.
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
BucketT *TheBucket;
if (LookupBucketFor(KV.first, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
return try_emplace(KV.first, KV.second);
}
// Inserts key,value pair into the map if the key isn't already in the map.
// If the key is already in the map, it returns false and doesn't update the
// value.
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
return try_emplace(std::move(KV.first), std::move(KV.second));
}
// Inserts key,value pair into the map if the key isn't already in the map.
// The value is constructed in-place if the key is not in the map, otherwise
// it is not moved.
template <typename... Ts>
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(KV.first, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(std::move(KV.first),
std::move(KV.second),
TheBucket);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
TheBucket =
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
}
// Inserts key,value pair into the map if the key isn't already in the map.
// The value is constructed in-place if the key is not in the map, otherwise
// it is not moved.
template <typename... Ts>
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
}
/// Alternate version of insert() which allows a different, and possibly
@@ -207,14 +242,16 @@ public:
const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(std::move(KV.first), std::move(KV.second), Val,
TheBucket);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
}
/// insert - Range insertion of pairs.
@@ -224,7 +261,6 @@ public:
insert(*I);
}
bool erase(const KeyT &Val) {
BucketT *TheBucket;
if (!LookupBucketFor(Val, TheBucket))
@@ -249,7 +285,7 @@ public:
if (LookupBucketFor(Key, TheBucket))
return *TheBucket;
return *InsertIntoBucket(Key, ValueT(), TheBucket);
return *InsertIntoBucket(TheBucket, Key);
}
ValueT &operator[](const KeyT &Key) {
@@ -261,7 +297,7 @@ public:
if (LookupBucketFor(Key, TheBucket))
return *TheBucket;
return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket);
return *InsertIntoBucket(TheBucket, std::move(Key));
}
ValueT &operator[](KeyT &&Key) {
@@ -369,54 +405,83 @@ protected:
static unsigned getHashValue(const KeyT &Val) {
return KeyInfoT::getHashValue(Val);
}
template<typename LookupKeyT>
static unsigned getHashValue(const LookupKeyT &Val) {
return KeyInfoT::getHashValue(Val);
}
static const KeyT getEmptyKey() {
static_assert(std::is_base_of<DenseMapBase, DerivedT>::value,
"Must pass the derived type to this template!");
return KeyInfoT::getEmptyKey();
}
static const KeyT getTombstoneKey() {
return KeyInfoT::getTombstoneKey();
}
private:
iterator makeIterator(BucketT *P, BucketT *E,
DebugEpochBase &Epoch,
bool NoAdvance=false) {
return iterator(P, E, Epoch, NoAdvance);
}
const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
const DebugEpochBase &Epoch,
const bool NoAdvance=false) const {
return const_iterator(P, E, Epoch, NoAdvance);
}
unsigned getNumEntries() const {
return static_cast<const DerivedT *>(this)->getNumEntries();
}
void setNumEntries(unsigned Num) {
static_cast<DerivedT *>(this)->setNumEntries(Num);
}
void incrementNumEntries() {
setNumEntries(getNumEntries() + 1);
}
void decrementNumEntries() {
setNumEntries(getNumEntries() - 1);
}
unsigned getNumTombstones() const {
return static_cast<const DerivedT *>(this)->getNumTombstones();
}
void setNumTombstones(unsigned Num) {
static_cast<DerivedT *>(this)->setNumTombstones(Num);
}
void incrementNumTombstones() {
setNumTombstones(getNumTombstones() + 1);
}
void decrementNumTombstones() {
setNumTombstones(getNumTombstones() - 1);
}
const BucketT *getBuckets() const {
return static_cast<const DerivedT *>(this)->getBuckets();
}
BucketT *getBuckets() {
return static_cast<DerivedT *>(this)->getBuckets();
}
unsigned getNumBuckets() const {
return static_cast<const DerivedT *>(this)->getNumBuckets();
}
BucketT *getBucketsEnd() {
return getBuckets() + getNumBuckets();
}
const BucketT *getBucketsEnd() const {
return getBuckets() + getNumBuckets();
}
@@ -429,36 +494,19 @@ private:
static_cast<DerivedT *>(this)->shrink_and_clear();
}
BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
BucketT *TheBucket) {
template <typename KeyArg, typename... ValueArgs>
BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
ValueArgs &&... Values) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
TheBucket->getFirst() = Key;
::new (&TheBucket->getSecond()) ValueT(Value);
return TheBucket;
}
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
TheBucket->getFirst() = Key;
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
return TheBucket;
}
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
TheBucket->getFirst() = std::move(Key);
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
TheBucket->getFirst() = std::forward<KeyArg>(Key);
::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
return TheBucket;
}
template <typename LookupKeyT>
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, LookupKeyT &Lookup,
BucketT *TheBucket) {
BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
ValueT &&Value, LookupKeyT &Lookup) {
TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
TheBucket->getFirst() = std::move(Key);
@@ -530,7 +578,7 @@ private:
unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);
unsigned ProbeAmt = 1;
while (1) {
while (true) {
const BucketT *ThisBucket = BucketsPtr + BucketNo;
// Found Val's bucket? If so, return it.
if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
@@ -584,10 +632,11 @@ template <typename KeyT, typename ValueT,
typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
KeyT, ValueT, KeyInfoT, BucketT> {
friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
// Lift some types from the dependent base class into this class for
// simplicity of referring to them.
typedef DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT> BaseT;
friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
BucketT *Buckets;
unsigned NumEntries;
@@ -702,6 +751,7 @@ private:
unsigned getNumEntries() const {
return NumEntries;
}
void setNumEntries(unsigned Num) {
NumEntries = Num;
}
@@ -709,6 +759,7 @@ private:
unsigned getNumTombstones() const {
return NumTombstones;
}
void setNumTombstones(unsigned Num) {
NumTombstones = Num;
}
@@ -740,10 +791,14 @@ class SmallDenseMap
: public DenseMapBase<
SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT>, KeyT,
ValueT, KeyInfoT, BucketT> {
friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
// Lift some types from the dependent base class into this class for
// simplicity of referring to them.
typedef DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT> BaseT;
friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
using BaseT = DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
static_assert(isPowerOf2_64(InlineBuckets),
"InlineBuckets must be a power of 2.");
unsigned Small : 1;
unsigned NumEntries : 31;
@@ -967,14 +1022,17 @@ private:
unsigned getNumEntries() const {
return NumEntries;
}
void setNumEntries(unsigned Num) {
assert(Num < INT_MAX && "Cannot support more than INT_MAX entries");
// NumEntries is hardcoded to be 31 bits wide.
assert(Num < (1U << 31) && "Cannot support more than 1<<31 entries");
NumEntries = Num;
}
unsigned getNumTombstones() const {
return NumTombstones;
}
void setNumTombstones(unsigned Num) {
NumTombstones = Num;
}
@@ -986,15 +1044,18 @@ private:
// 'storage.buffer' static type is 'char *'.
return reinterpret_cast<const BucketT *>(storage.buffer);
}
BucketT *getInlineBuckets() {
return const_cast<BucketT *>(
const_cast<const SmallDenseMap *>(this)->getInlineBuckets());
}
const LargeRep *getLargeRep() const {
assert(!Small);
// Note, same rule about aliasing as with getInlineBuckets.
return reinterpret_cast<const LargeRep *>(storage.buffer);
}
LargeRep *getLargeRep() {
return const_cast<LargeRep *>(
const_cast<const SmallDenseMap *>(this)->getLargeRep());
@@ -1003,10 +1064,12 @@ private:
const BucketT *getBuckets() const {
return Small ? getInlineBuckets() : getLargeRep()->Buckets;
}
BucketT *getBuckets() {
return const_cast<BucketT *>(
const_cast<const SmallDenseMap *>(this)->getBuckets());
}
unsigned getNumBuckets() const {
return Small ? InlineBuckets : getLargeRep()->NumBuckets;
}
@@ -1031,27 +1094,33 @@ private:
template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket,
bool IsConst>
class DenseMapIterator : DebugEpochBase::HandleBase {
typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true> ConstIterator;
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
using ConstIterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
public:
typedef ptrdiff_t difference_type;
typedef typename std::conditional<IsConst, const Bucket, Bucket>::type
value_type;
typedef value_type *pointer;
typedef value_type &reference;
typedef std::forward_iterator_tag iterator_category;
using difference_type = ptrdiff_t;
using value_type =
typename std::conditional<IsConst, const Bucket, Bucket>::type;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
private:
pointer Ptr, End;
pointer Ptr = nullptr;
pointer End = nullptr;
public:
DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
DenseMapIterator() = default;
DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch,
bool NoAdvance = false)
: DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
assert(isHandleInSync() && "invalid construction!");
if (!NoAdvance) AdvancePastEmptyBuckets();
if (NoAdvance) return;
AdvancePastEmptyBuckets();
}
// Converting ctor from non-const iterators to const iterators. SFINAE'd out
@@ -1100,6 +1169,7 @@ public:
private:
void AdvancePastEmptyBuckets() {
assert(Ptr <= End);
const KeyT Empty = KeyInfoT::getEmptyKey();
const KeyT Tombstone = KeyInfoT::getTombstoneKey();
@@ -1107,14 +1177,23 @@ private:
KeyInfoT::isEqual(Ptr->getFirst(), Tombstone)))
++Ptr;
}
void RetreatPastEmptyBuckets() {
assert(Ptr >= End);
const KeyT Empty = KeyInfoT::getEmptyKey();
const KeyT Tombstone = KeyInfoT::getTombstoneKey();
while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) ||
KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone)))
--Ptr;
}
};
template<typename KeyT, typename ValueT, typename KeyInfoT>
static inline size_t
capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
template <typename KeyT, typename ValueT, typename KeyInfoT>
inline size_t capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
return X.getMemorySize();
}
} // end namespace wpi
#endif
#endif // LLVM_ADT_DENSEMAP_H

View File

@@ -11,14 +11,17 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_DENSEMAPINFO_H
#define LLVM_ADT_DENSEMAPINFO_H
#ifndef WPIUTIL_WPI_DENSEMAPINFO_H
#define WPIUTIL_WPI_DENSEMAPINFO_H
#include "wpi/ArrayRef.h"
#include "wpi/Hashing.h"
#include "wpi/StringRef.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/type_traits.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <utility>
namespace wpi {
@@ -30,36 +33,6 @@ struct DenseMapInfo {
//static bool isEqual(const T &LHS, const T &RHS);
};
template <typename T> struct CachedHash {
CachedHash(T Val) : Val(std::move(Val)) {
Hash = DenseMapInfo<T>::getHashValue(Val);
}
CachedHash(T Val, unsigned Hash) : Val(std::move(Val)), Hash(Hash) {}
T Val;
unsigned Hash;
};
// Provide DenseMapInfo for all CachedHash<T>.
template <typename T> struct DenseMapInfo<CachedHash<T>> {
static CachedHash<T> getEmptyKey() {
T N = DenseMapInfo<T>::getEmptyKey();
return {N, 0};
}
static CachedHash<T> getTombstoneKey() {
T N = DenseMapInfo<T>::getTombstoneKey();
return {N, 0};
}
static unsigned getHashValue(CachedHash<T> Val) {
assert(!isEqual(Val, getEmptyKey()) && "Cannot hash the empty key!");
assert(!isEqual(Val, getTombstoneKey()) &&
"Cannot hash the tombstone key!");
return Val.Hash;
}
static bool isEqual(CachedHash<T> A, CachedHash<T> B) {
return DenseMapInfo<T>::isEqual(A.Val, B.Val);
}
};
// Provide DenseMapInfo for all pointers.
template<typename T>
struct DenseMapInfo<T*> {
@@ -68,15 +41,18 @@ struct DenseMapInfo<T*> {
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
return reinterpret_cast<T*>(Val);
}
static inline T* getTombstoneKey() {
uintptr_t Val = static_cast<uintptr_t>(-2);
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
return reinterpret_cast<T*>(Val);
}
static unsigned getHashValue(const T *PtrVal) {
return (unsigned((uintptr_t)PtrVal) >> 4) ^
(unsigned((uintptr_t)PtrVal) >> 9);
}
static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
};
@@ -85,16 +61,29 @@ template<> struct DenseMapInfo<char> {
static inline char getEmptyKey() { return ~0; }
static inline char getTombstoneKey() { return ~0 - 1; }
static unsigned getHashValue(const char& Val) { return Val * 37U; }
static bool isEqual(const char &LHS, const char &RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for unsigned shorts.
template <> struct DenseMapInfo<unsigned short> {
static inline unsigned short getEmptyKey() { return 0xFFFF; }
static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for unsigned ints.
template<> struct DenseMapInfo<unsigned> {
static inline unsigned getEmptyKey() { return ~0U; }
static inline unsigned getTombstoneKey() { return ~0U - 1; }
static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
return LHS == RHS;
}
@@ -104,9 +93,11 @@ template<> struct DenseMapInfo<unsigned> {
template<> struct DenseMapInfo<unsigned long> {
static inline unsigned long getEmptyKey() { return ~0UL; }
static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
static unsigned getHashValue(const unsigned long& Val) {
return (unsigned)(Val * 37UL);
}
static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
return LHS == RHS;
}
@@ -116,20 +107,31 @@ template<> struct DenseMapInfo<unsigned long> {
template<> struct DenseMapInfo<unsigned long long> {
static inline unsigned long long getEmptyKey() { return ~0ULL; }
static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
static unsigned getHashValue(const unsigned long long& Val) {
return (unsigned)(Val * 37ULL);
}
static bool isEqual(const unsigned long long& LHS,
const unsigned long long& RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for shorts.
template <> struct DenseMapInfo<short> {
static inline short getEmptyKey() { return 0x7FFF; }
static inline short getTombstoneKey() { return -0x7FFF - 1; }
static unsigned getHashValue(const short &Val) { return Val * 37U; }
static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
};
// Provide DenseMapInfo for ints.
template<> struct DenseMapInfo<int> {
static inline int getEmptyKey() { return 0x7fffffff; }
static inline int getTombstoneKey() { return -0x7fffffff - 1; }
static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
static bool isEqual(const int& LHS, const int& RHS) {
return LHS == RHS;
}
@@ -140,10 +142,13 @@ template<> struct DenseMapInfo<long> {
static inline long getEmptyKey() {
return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
}
static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
static unsigned getHashValue(const long& Val) {
return (unsigned)(Val * 37UL);
}
static bool isEqual(const long& LHS, const long& RHS) {
return LHS == RHS;
}
@@ -153,9 +158,11 @@ template<> struct DenseMapInfo<long> {
template<> struct DenseMapInfo<long long> {
static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
static unsigned getHashValue(const long long& Val) {
return (unsigned)(Val * 37ULL);
}
static bool isEqual(const long long& LHS,
const long long& RHS) {
return LHS == RHS;
@@ -164,19 +171,21 @@ template<> struct DenseMapInfo<long long> {
// Provide DenseMapInfo for all pairs whose members have info.
template<typename T, typename U>
struct DenseMapInfo<std::pair<T, U> > {
typedef std::pair<T, U> Pair;
typedef DenseMapInfo<T> FirstInfo;
typedef DenseMapInfo<U> SecondInfo;
struct DenseMapInfo<std::pair<T, U>> {
using Pair = std::pair<T, U>;
using FirstInfo = DenseMapInfo<T>;
using SecondInfo = DenseMapInfo<U>;
static inline Pair getEmptyKey() {
return std::make_pair(FirstInfo::getEmptyKey(),
SecondInfo::getEmptyKey());
}
static inline Pair getTombstoneKey() {
return std::make_pair(FirstInfo::getTombstoneKey(),
SecondInfo::getTombstoneKey());
}
static unsigned getHashValue(const Pair& PairVal) {
uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
| (uint64_t)SecondInfo::getHashValue(PairVal.second);
@@ -190,6 +199,7 @@ struct DenseMapInfo<std::pair<T, U> > {
key ^= (key >> 31);
return (unsigned)key;
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
return FirstInfo::isEqual(LHS.first, RHS.first) &&
SecondInfo::isEqual(LHS.second, RHS.second);
@@ -202,16 +212,19 @@ template <> struct DenseMapInfo<StringRef> {
return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
0);
}
static inline StringRef getTombstoneKey() {
return StringRef(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
0);
}
static unsigned getHashValue(StringRef Val) {
assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
assert(Val.data() != getTombstoneKey().data() &&
"Cannot hash the tombstone key!");
return (unsigned)(hash_value(Val));
}
static bool isEqual(StringRef LHS, StringRef RHS) {
if (RHS.data() == getEmptyKey().data())
return LHS.data() == getEmptyKey().data();
@@ -227,16 +240,19 @@ template <typename T> struct DenseMapInfo<ArrayRef<T>> {
return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(0)),
size_t(0));
}
static inline ArrayRef<T> getTombstoneKey() {
return ArrayRef<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(1)),
size_t(0));
}
static unsigned getHashValue(ArrayRef<T> Val) {
assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
assert(Val.data() != getTombstoneKey().data() &&
"Cannot hash the tombstone key!");
return (unsigned)(hash_value(Val));
}
static bool isEqual(ArrayRef<T> LHS, ArrayRef<T> RHS) {
if (RHS.data() == getEmptyKey().data())
return LHS.data() == getEmptyKey().data();
@@ -248,4 +264,4 @@ template <typename T> struct DenseMapInfo<ArrayRef<T>> {
} // end namespace wpi
#endif
#endif // LLVM_ADT_DENSEMAPINFO_H

View File

@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_EPOCH_TRACKER_H
#define LLVM_ADT_EPOCH_TRACKER_H
#ifndef WPIUTIL_WPI_EPOCH_TRACKER_H
#define WPIUTIL_WPI_EPOCH_TRACKER_H
#include <cstdint>
@@ -37,7 +37,7 @@ public:
#else
/// \brief A base class for data structure classes wishing to make iterators
/// A base class for data structure classes wishing to make iterators
/// ("handles") pointing into themselves fail-fast. When building without
/// asserts, this class is empty and does nothing.
///
@@ -52,15 +52,15 @@ class DebugEpochBase {
public:
DebugEpochBase() : Epoch(0) {}
/// \brief Calling incrementEpoch invalidates all handles pointing into the
/// Calling incrementEpoch invalidates all handles pointing into the
/// calling instance.
void incrementEpoch() { ++Epoch; }
/// \brief The destructor calls incrementEpoch to make use-after-free bugs
/// The destructor calls incrementEpoch to make use-after-free bugs
/// more likely to crash deterministically.
~DebugEpochBase() { incrementEpoch(); }
/// \brief A base class for iterator classes ("handles") that wish to poll for
/// A base class for iterator classes ("handles") that wish to poll for
/// iterator invalidating modifications in the underlying data structure.
/// When LLVM is built without asserts, this class is empty and does nothing.
///
@@ -78,12 +78,12 @@ public:
explicit HandleBase(const DebugEpochBase *Parent)
: EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
/// \brief Returns true if the DebugEpochBase this Handle is linked to has
/// Returns true if the DebugEpochBase this Handle is linked to has
/// not called incrementEpoch on itself since the creation of this
/// HandleBase instance.
bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
/// \brief Returns a pointer to the epoch word stored in the data structure
/// Returns a pointer to the epoch word stored in the data structure
/// this handle points into. Can be used to check if two iterators point
/// into the same data structure.
const void *getEpochAddress() const { return EpochAddress; }

View File

@@ -0,0 +1,291 @@
//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Provides ErrorOr<T> smart pointer.
///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_ERROROR_H
#define WPIUTIL_WPI_ERROROR_H
#include "wpi/AlignOf.h"
#include <cassert>
#include <system_error>
#include <type_traits>
#include <utility>
namespace wpi {
/// Stores a reference that can be changed.
template <typename T>
class ReferenceStorage {
T *Storage;
public:
ReferenceStorage(T &Ref) : Storage(&Ref) {}
operator T &() const { return *Storage; }
T &get() const { return *Storage; }
};
/// Represents either an error or a value T.
///
/// ErrorOr<T> is a pointer-like class that represents the result of an
/// operation. The result is either an error, or a value of type T. This is
/// designed to emulate the usage of returning a pointer where nullptr indicates
/// failure. However instead of just knowing that the operation failed, we also
/// have an error_code and optional user data that describes why it failed.
///
/// It is used like the following.
/// \code
/// ErrorOr<Buffer> getBuffer();
///
/// auto buffer = getBuffer();
/// if (error_code ec = buffer.getError())
/// return ec;
/// buffer->write("adena");
/// \endcode
///
///
/// Implicit conversion to bool returns true if there is a usable value. The
/// unary * and -> operators provide pointer like access to the value. Accessing
/// the value when there is an error has undefined behavior.
///
/// When T is a reference type the behavior is slightly different. The reference
/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
/// there is special handling to make operator -> work as if T was not a
/// reference.
///
/// T cannot be a rvalue reference.
template<class T>
class ErrorOr {
template <class OtherT> friend class ErrorOr;
static const bool isRef = std::is_reference<T>::value;
using wrap = ReferenceStorage<typename std::remove_reference<T>::type>;
public:
using storage_type = typename std::conditional<isRef, wrap, T>::type;
private:
using reference = typename std::remove_reference<T>::type &;
using const_reference = const typename std::remove_reference<T>::type &;
using pointer = typename std::remove_reference<T>::type *;
using const_pointer = const typename std::remove_reference<T>::type *;
public:
template <class E>
ErrorOr(E ErrorCode,
typename std::enable_if<std::is_error_code_enum<E>::value ||
std::is_error_condition_enum<E>::value,
void *>::type = nullptr)
: HasError(true) {
new (getErrorStorage()) std::error_code(make_error_code(ErrorCode));
}
ErrorOr(std::error_code EC) : HasError(true) {
new (getErrorStorage()) std::error_code(EC);
}
template <class OtherT>
ErrorOr(OtherT &&Val,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
* = nullptr)
: HasError(false) {
new (getStorage()) storage_type(std::forward<OtherT>(Val));
}
ErrorOr(const ErrorOr &Other) {
copyConstruct(Other);
}
template <class OtherT>
ErrorOr(
const ErrorOr<OtherT> &Other,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
nullptr) {
copyConstruct(Other);
}
template <class OtherT>
explicit ErrorOr(
const ErrorOr<OtherT> &Other,
typename std::enable_if<
!std::is_convertible<OtherT, const T &>::value>::type * = nullptr) {
copyConstruct(Other);
}
ErrorOr(ErrorOr &&Other) {
moveConstruct(std::move(Other));
}
template <class OtherT>
ErrorOr(
ErrorOr<OtherT> &&Other,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
nullptr) {
moveConstruct(std::move(Other));
}
// This might eventually need SFINAE but it's more complex than is_convertible
// & I'm too lazy to write it right now.
template <class OtherT>
explicit ErrorOr(
ErrorOr<OtherT> &&Other,
typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
nullptr) {
moveConstruct(std::move(Other));
}
ErrorOr &operator=(const ErrorOr &Other) {
copyAssign(Other);
return *this;
}
ErrorOr &operator=(ErrorOr &&Other) {
moveAssign(std::move(Other));
return *this;
}
~ErrorOr() {
if (!HasError)
getStorage()->~storage_type();
}
/// Return false if there is an error.
explicit operator bool() const {
return !HasError;
}
reference get() { return *getStorage(); }
const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
std::error_code getError() const {
return HasError ? *getErrorStorage() : std::error_code();
}
pointer operator ->() {
return toPointer(getStorage());
}
const_pointer operator->() const { return toPointer(getStorage()); }
reference operator *() {
return *getStorage();
}
const_reference operator*() const { return *getStorage(); }
private:
template <class OtherT>
void copyConstruct(const ErrorOr<OtherT> &Other) {
if (!Other.HasError) {
// Get the other value.
HasError = false;
new (getStorage()) storage_type(*Other.getStorage());
} else {
// Get other's error.
HasError = true;
new (getErrorStorage()) std::error_code(Other.getError());
}
}
template <class T1>
static bool compareThisIfSameType(const T1 &a, const T1 &b) {
return &a == &b;
}
template <class T1, class T2>
static bool compareThisIfSameType(const T1 &a, const T2 &b) {
return false;
}
template <class OtherT>
void copyAssign(const ErrorOr<OtherT> &Other) {
if (compareThisIfSameType(*this, Other))
return;
this->~ErrorOr();
new (this) ErrorOr(Other);
}
template <class OtherT>
void moveConstruct(ErrorOr<OtherT> &&Other) {
if (!Other.HasError) {
// Get the other value.
HasError = false;
new (getStorage()) storage_type(std::move(*Other.getStorage()));
} else {
// Get other's error.
HasError = true;
new (getErrorStorage()) std::error_code(Other.getError());
}
}
template <class OtherT>
void moveAssign(ErrorOr<OtherT> &&Other) {
if (compareThisIfSameType(*this, Other))
return;
this->~ErrorOr();
new (this) ErrorOr(std::move(Other));
}
pointer toPointer(pointer Val) {
return Val;
}
const_pointer toPointer(const_pointer Val) const { return Val; }
pointer toPointer(wrap *Val) {
return &Val->get();
}
const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
storage_type *getStorage() {
assert(!HasError && "Cannot get value when an error exists!");
return reinterpret_cast<storage_type*>(TStorage.buffer);
}
const storage_type *getStorage() const {
assert(!HasError && "Cannot get value when an error exists!");
return reinterpret_cast<const storage_type*>(TStorage.buffer);
}
std::error_code *getErrorStorage() {
assert(HasError && "Cannot get error when a value exists!");
return reinterpret_cast<std::error_code *>(ErrorStorage.buffer);
}
const std::error_code *getErrorStorage() const {
return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
}
union {
AlignedCharArrayUnion<storage_type> TStorage;
AlignedCharArrayUnion<std::error_code> ErrorStorage;
};
bool HasError : 1;
};
template <class T, class E>
typename std::enable_if<std::is_error_code_enum<E>::value ||
std::is_error_condition_enum<E>::value,
bool>::type
operator==(const ErrorOr<T> &Err, E Code) {
return Err.getError() == Code;
}
} // end namespace wpi
#endif // LLVM_SUPPORT_ERROROR_H

View File

@@ -24,21 +24,25 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_FILESYSTEM_H
#define LLVM_SUPPORT_FILESYSTEM_H
#ifndef WPIUTIL_WPI_FILESYSTEM_H
#define WPIUTIL_WPI_FILESYSTEM_H
#include "wpi/IntrusiveRefCntPtr.h"
#include "wpi/SmallString.h"
#include "wpi/StringRef.h"
#include "wpi/Twine.h"
#include <sys/stat.h>
#include "wpi/ErrorOr.h"
#include <cassert>
#include <cstdint>
#include <ctime>
#include <memory>
#include <stack>
#include <string>
#include <system_error>
#include <tuple>
#include <vector>
#include <sys/stat.h>
namespace wpi {
namespace sys {
namespace fs {
@@ -78,6 +82,7 @@ enum perms {
set_uid_on_exe = 04000,
set_gid_on_exe = 02000,
sticky_bit = 01000,
all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
perms_not_known = 0xFFFF
};
@@ -99,8 +104,9 @@ inline perms &operator&=(perms &l, perms r) {
return l;
}
inline perms operator~(perms x) {
// Avoid UB by explicitly truncating the (unsigned) ~ result.
return static_cast<perms>(
static_cast<unsigned short>(~static_cast<unsigned short>(x)));
static_cast<unsigned short>(~static_cast<unsigned short>(x)));
}
class UniqueID {
@@ -110,6 +116,7 @@ class UniqueID {
public:
UniqueID() = default;
UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {}
bool operator==(const UniqueID &Other) const {
return Device == Other.Device && File == Other.File;
}
@@ -117,99 +124,75 @@ public:
bool operator<(const UniqueID &Other) const {
return std::tie(Device, File) < std::tie(Other.Device, Other.File);
}
uint64_t getDevice() const { return Device; }
uint64_t getFile() const { return File; }
};
/// file_status - Represents the result of a call to stat and friends. It has
/// a platform-specific member to store the result.
class file_status
{
#ifdef _WIN32
uint32_t LastAccessedTimeHigh;
uint32_t LastAccessedTimeLow;
uint32_t LastWriteTimeHigh;
uint32_t LastWriteTimeLow;
uint32_t VolumeSerialNumber;
uint32_t FileSizeHigh;
uint32_t FileSizeLow;
uint32_t FileIndexHigh;
uint32_t FileIndexLow;
/// Represents the result of a call to directory_iterator::status(). This is a
/// subset of the information returned by a regular sys::fs::status() call, and
/// represents the information provided by Windows FileFirstFile/FindNextFile.
class basic_file_status {
protected:
#ifndef _WIN32
time_t fs_st_atime = 0;
time_t fs_st_mtime = 0;
uid_t fs_st_uid = 0;
gid_t fs_st_gid = 0;
off_t fs_st_size = 0;
#else
dev_t fs_st_dev;
ino_t fs_st_ino;
time_t fs_st_atime;
time_t fs_st_mtime;
uid_t fs_st_uid;
gid_t fs_st_gid;
off_t fs_st_size;
uint32_t LastAccessedTimeHigh = 0;
uint32_t LastAccessedTimeLow = 0;
uint32_t LastWriteTimeHigh = 0;
uint32_t LastWriteTimeLow = 0;
uint32_t FileSizeHigh = 0;
uint32_t FileSizeLow = 0;
#endif
friend bool equivalent(file_status A, file_status B);
file_type Type;
perms Perms;
file_type Type = file_type::status_error;
perms Perms = perms_not_known;
public:
#ifdef _WIN32
file_status()
: LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0),
Type(file_type::status_error), Perms(perms_not_known) {}
basic_file_status() = default;
file_status(file_type Type)
: LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), Type(Type),
Perms(perms_not_known) {}
explicit basic_file_status(file_type Type) : Type(Type) {}
file_status(file_type Type, uint32_t LastAccessTimeHigh,
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
uint32_t FileSizeHigh, uint32_t FileSizeLow,
uint32_t FileIndexHigh, uint32_t FileIndexLow)
: LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow),
LastWriteTimeHigh(LastWriteTimeHigh),
LastWriteTimeLow(LastWriteTimeLow),
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {}
#ifndef _WIN32
basic_file_status(file_type Type, perms Perms, time_t ATime, time_t MTime,
uid_t UID, gid_t GID, off_t Size)
: fs_st_atime(ATime), fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID),
fs_st_size(Size), Type(Type), Perms(Perms) {}
#else
file_status()
: fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
fs_st_uid(0), fs_st_gid(0), fs_st_size(0),
Type(file_type::status_error), Perms(perms_not_known) {}
file_status(file_type Type)
: fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type),
Perms(perms_not_known) {}
file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t ATime,
time_t MTime, uid_t UID, gid_t GID, off_t Size)
: fs_st_dev(Dev), fs_st_ino(Ino), fs_st_atime(ATime), fs_st_mtime(MTime),
fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size), Type(Type),
Perms(Perms) {}
basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
uint32_t LastWriteTimeLow, uint32_t FileSizeHigh,
uint32_t FileSizeLow)
: LastAccessedTimeHigh(LastAccessTimeHigh),
LastAccessedTimeLow(LastAccessTimeLow),
LastWriteTimeHigh(LastWriteTimeHigh),
LastWriteTimeLow(LastWriteTimeLow), FileSizeHigh(FileSizeHigh),
FileSizeLow(FileSizeLow), Type(Type), Perms(Perms) {}
#endif
// getters
file_type type() const { return Type; }
perms permissions() const { return Perms; }
UniqueID getUniqueID() const;
#ifdef _WIN32
uint32_t getUser() const {
return 9999; // Not applicable to Windows, so...
}
uint32_t getGroup() const {
return 9999; // Not applicable to Windows, so...
}
uint64_t getSize() const {
return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
}
#else
#ifndef _WIN32
uint32_t getUser() const { return fs_st_uid; }
uint32_t getGroup() const { return fs_st_gid; }
uint64_t getSize() const { return fs_st_size; }
#else
uint32_t getUser() const {
return 9999; // Not applicable to Windows, so...
}
uint32_t getGroup() const {
return 9999; // Not applicable to Windows, so...
}
uint64_t getSize() const {
return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
}
#endif
// setters
@@ -217,11 +200,54 @@ public:
void permissions(perms p) { Perms = p; }
};
/// Represents the result of a call to sys::fs::status().
class file_status : public basic_file_status {
friend bool equivalent(file_status A, file_status B);
#ifndef _WIN32
dev_t fs_st_dev = 0;
nlink_t fs_st_nlinks = 0;
ino_t fs_st_ino = 0;
#else
uint32_t NumLinks = 0;
uint32_t VolumeSerialNumber = 0;
uint32_t FileIndexHigh = 0;
uint32_t FileIndexLow = 0;
#endif
public:
file_status() = default;
explicit file_status(file_type Type) : basic_file_status(Type) {}
#ifndef _WIN32
file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino,
time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size)
: basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size),
fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}
#else
file_status(file_type Type, perms Perms, uint32_t LinkCount,
uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
uint32_t VolumeSerialNumber, uint32_t FileSizeHigh,
uint32_t FileSizeLow, uint32_t FileIndexHigh,
uint32_t FileIndexLow)
: basic_file_status(Type, Perms, LastAccessTimeHigh, LastAccessTimeLow,
LastWriteTimeHigh, LastWriteTimeLow, FileSizeHigh,
FileSizeLow),
NumLinks(LinkCount), VolumeSerialNumber(VolumeSerialNumber),
FileIndexHigh(FileIndexHigh), FileIndexLow(FileIndexLow) {}
#endif
UniqueID getUniqueID() const;
uint32_t getLinkCount() const;
};
/// @}
/// @name Physical Operators
/// @{
/// @brief Make \a path an absolute path.
/// Make \a path an absolute path.
///
/// Makes \a path absolute using the \a current_directory if it is not already.
/// An empty \a path will result in the \a current_directory.
@@ -235,7 +261,7 @@ public:
std::error_code make_absolute(const Twine &current_directory,
SmallVectorImpl<char> &path);
/// @brief Make \a path an absolute path.
/// Make \a path an absolute path.
///
/// Makes \a path absolute using the current directory if it is not already. An
/// empty \a path will result in the current directory.
@@ -248,7 +274,7 @@ std::error_code make_absolute(const Twine &current_directory,
/// platform-specific error_code.
std::error_code make_absolute(SmallVectorImpl<char> &path);
/// @brief Get the current path.
/// Get the current path.
///
/// @param result Holds the current path on return.
/// @returns errc::success if the current path has been stored in result,
@@ -259,23 +285,23 @@ std::error_code current_path(SmallVectorImpl<char> &result);
/// @name Physical Observers
/// @{
/// @brief Does file exist?
/// Does file exist?
///
/// @param status A file_status previously returned from stat.
/// @param status A basic_file_status previously returned from stat.
/// @returns True if the file represented by status exists, false if it does
/// not.
bool exists(file_status status);
bool exists(const basic_file_status &status);
enum class AccessMode { Exist, Write, Execute };
/// @brief Can the file be accessed?
/// Can the file be accessed?
///
/// @param Path Input path.
/// @returns errc::success if the path can be accessed, otherwise a
/// platform-specific error_code.
std::error_code access(const Twine &Path, AccessMode Mode);
/// @brief Does file exist?
/// Does file exist?
///
/// @param Path Input path.
/// @returns True if it exists, false otherwise.
@@ -283,7 +309,7 @@ inline bool exists(const Twine &Path) {
return !access(Path, AccessMode::Exist);
}
/// @brief Can we write this file?
/// Can we write this file?
///
/// @param Path Input path.
/// @returns True if we can write to it, false otherwise.
@@ -291,7 +317,7 @@ inline bool can_write(const Twine &Path) {
return !access(Path, AccessMode::Write);
}
/// @brief Do file_status's represent the same thing?
/// Do file_status's represent the same thing?
///
/// @param A Input file_status.
/// @param B Input file_status.
@@ -302,7 +328,7 @@ inline bool can_write(const Twine &Path) {
/// otherwise.
bool equivalent(file_status A, file_status B);
/// @brief Do paths represent the same thing?
/// Do paths represent the same thing?
///
/// assert(status_known(A) || status_known(B));
///
@@ -314,51 +340,51 @@ bool equivalent(file_status A, file_status B);
/// platform-specific error_code.
std::error_code equivalent(const Twine &A, const Twine &B, bool &result);
/// @brief Simpler version of equivalent for clients that don't need to
/// Simpler version of equivalent for clients that don't need to
/// differentiate between an error and false.
inline bool equivalent(const Twine &A, const Twine &B) {
bool result;
return !equivalent(A, B, result) && result;
}
/// @brief Does status represent a directory?
/// Does status represent a directory?
///
/// @param status A file_status previously returned from status.
/// @param status A basic_file_status previously returned from status.
/// @returns status.type() == file_type::directory_file.
bool is_directory(file_status status);
bool is_directory(const basic_file_status &status);
/// @brief Is path a directory?
/// Is path a directory?
///
/// @param path Input path.
/// @param result Set to true if \a path is a directory, false if it is not.
/// Undefined otherwise.
/// @param result Set to true if \a path is a directory (after following
/// symlinks, false if it is not. Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code is_directory(const Twine &path, bool &result);
/// @brief Simpler version of is_directory for clients that don't need to
/// Simpler version of is_directory for clients that don't need to
/// differentiate between an error and false.
inline bool is_directory(const Twine &Path) {
bool Result;
return !is_directory(Path, Result) && Result;
}
/// @brief Does status represent a regular file?
/// Does status represent a regular file?
///
/// @param status A file_status previously returned from status.
/// @param status A basic_file_status previously returned from status.
/// @returns status_known(status) && status.type() == file_type::regular_file.
bool is_regular_file(file_status status);
bool is_regular_file(const basic_file_status &status);
/// @brief Is path a regular file?
/// Is path a regular file?
///
/// @param path Input path.
/// @param result Set to true if \a path is a regular file, false if it is not.
/// Undefined otherwise.
/// @param result Set to true if \a path is a regular file (after following
/// symlinks), false if it is not. Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code is_regular_file(const Twine &path, bool &result);
/// @brief Simpler version of is_regular_file for clients that don't need to
/// Simpler version of is_regular_file for clients that don't need to
/// differentiate between an error and false.
inline bool is_regular_file(const Twine &Path) {
bool Result;
@@ -367,14 +393,38 @@ inline bool is_regular_file(const Twine &Path) {
return Result;
}
/// @brief Does this status represent something that exists but is not a
/// directory, regular file, or symlink?
/// Does status represent a symlink file?
///
/// @param status A file_status previously returned from status.
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
bool is_other(file_status status);
/// @param status A basic_file_status previously returned from status.
/// @returns status_known(status) && status.type() == file_type::symlink_file.
bool is_symlink_file(const basic_file_status &status);
/// @brief Is path something that exists but is not a directory,
/// Is path a symlink file?
///
/// @param path Input path.
/// @param result Set to true if \a path is a symlink file, false if it is not.
/// Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code is_symlink_file(const Twine &path, bool &result);
/// Simpler version of is_symlink_file for clients that don't need to
/// differentiate between an error and false.
inline bool is_symlink_file(const Twine &Path) {
bool Result;
if (is_symlink_file(Path, Result))
return false;
return Result;
}
/// Does this status represent something that exists but is not a
/// directory or regular file?
///
/// @param status A basic_file_status previously returned from status.
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
bool is_other(const basic_file_status &status);
/// Is path something that exists but is not a directory,
/// regular file, or symlink?
///
/// @param path Input path.
@@ -384,24 +434,27 @@ bool is_other(file_status status);
/// platform-specific error_code.
std::error_code is_other(const Twine &path, bool &result);
/// @brief Get file status as if by POSIX stat().
/// Get file status as if by POSIX stat().
///
/// @param path Input path.
/// @param result Set to the file status.
/// @param follow When true, follows symlinks. Otherwise, the symlink itself is
/// statted.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code status(const Twine &path, file_status &result);
std::error_code status(const Twine &path, file_status &result,
bool follow = true);
/// @brief A version for when a file descriptor is already available.
/// A version for when a file descriptor is already available.
std::error_code status(int FD, file_status &Result);
/// @brief Is status available?
/// Is status available?
///
/// @param s Input file status.
/// @returns True if status() != status_error.
bool status_known(file_status s);
bool status_known(const basic_file_status &s);
/// @brief Is status available?
/// Is status available?
///
/// @param path Input path.
/// @param result Set to true if status() != status_error.
@@ -421,12 +474,20 @@ enum OpenFlags : unsigned {
/// with F_Excl.
F_Append = 2,
/// F_NoTrunc - When opening a file, if it already exists don't truncate
/// the file contents. F_Append implies F_NoTrunc, but F_Append seeks to
/// the end of the file, which F_NoTrunc doesn't.
F_NoTrunc = 4,
/// The file should be opened in text mode on platforms that make this
/// distinction.
F_Text = 4,
F_Text = 8,
/// Open the file for read and write.
F_RW = 8
F_RW = 16,
/// Delete the file on close. Only makes a difference on windows.
F_Delete = 32
};
inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
@@ -438,11 +499,41 @@ inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
return A;
}
/// @brief Opens the file with the given name in a write-only or read-write
/// mode, returning its open file descriptor. If the file does not exist, it
/// is created.
///
/// The caller is responsible for closing the file descriptor once they are
/// finished with it.
///
/// @param Name The path of the file to open, relative or absolute.
/// @param ResultFD If the file could be opened successfully, its descriptor
/// is stored in this location. Otherwise, this is set to -1.
/// @param Flags Additional flags used to determine whether the file should be
/// opened in, for example, read-write or in write-only mode.
/// @param Mode The access permissions of the file, represented in octal.
/// @returns errc::success if \a Name has been opened, otherwise a
/// platform-specific error_code.
std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
OpenFlags Flags, unsigned Mode = 0666);
/// @brief Opens the file with the given name in a read-only mode, returning
/// its open file descriptor.
///
/// The caller is responsible for closing the file descriptor once they are
/// finished with it.
///
/// @param Name The path of the file to open, relative or absolute.
/// @param ResultFD If the file could be opened successfully, its descriptor
/// is stored in this location. Otherwise, this is set to -1.
/// @param RealPath If nonnull, extra work is done to determine the real path
/// of the opened file, and that path is stored in this
/// location.
/// @returns errc::success if \a Name has been opened, otherwise a
/// platform-specific error_code.
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
SmallVectorImpl<char> *RealPath = nullptr);
std::error_code getUniqueID(const Twine Path, UniqueID &Result);
/// @}
@@ -454,24 +545,26 @@ std::error_code getUniqueID(const Twine Path, UniqueID &Result);
/// called.
class directory_entry {
std::string Path;
mutable file_status Status;
bool FollowSymlinks;
basic_file_status Status;
public:
explicit directory_entry(const Twine &path, file_status st = file_status())
: Path(path.str())
, Status(st) {}
explicit directory_entry(const Twine &path, bool follow_symlinks = true,
basic_file_status st = basic_file_status())
: Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {}
directory_entry() {}
directory_entry() = default;
void assign(const Twine &path, file_status st = file_status()) {
void assign(const Twine &path, basic_file_status st = basic_file_status()) {
Path = path.str();
Status = st;
}
void replace_filename(const Twine &filename, file_status st = file_status());
void replace_filename(const Twine &filename,
basic_file_status st = basic_file_status());
const std::string &path() const { return Path; }
std::error_code status(file_status &result) const;
ErrorOr<basic_file_status> status() const;
bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; }
bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); }
@@ -482,52 +575,59 @@ public:
};
namespace detail {
struct DirIterState;
std::error_code directory_iterator_construct(DirIterState &, StringRef);
std::error_code directory_iterator_construct(DirIterState &, StringRef, bool);
std::error_code directory_iterator_increment(DirIterState &);
std::error_code directory_iterator_destruct(DirIterState &);
/// DirIterState - Keeps state for the directory_iterator. It is reference
/// counted in order to preserve InputIterator semantics on copy.
struct DirIterState : public RefCountedBase<DirIterState> {
DirIterState()
: IterationHandle(0) {}
/// Keeps state for the directory_iterator.
struct DirIterState {
~DirIterState() {
directory_iterator_destruct(*this);
}
intptr_t IterationHandle;
intptr_t IterationHandle = 0;
directory_entry CurrentEntry;
};
} // end namespace detail
/// directory_iterator - Iterates through the entries in path. There is no
/// operator++ because we need an error_code. If it's really needed we can make
/// it call report_fatal_error on error.
class directory_iterator {
IntrusiveRefCntPtr<detail::DirIterState> State;
std::shared_ptr<detail::DirIterState> State;
bool FollowSymlinks = true;
public:
explicit directory_iterator(const Twine &path, std::error_code &ec) {
State = new detail::DirIterState;
explicit directory_iterator(const Twine &path, std::error_code &ec,
bool follow_symlinks = true)
: FollowSymlinks(follow_symlinks) {
State = std::make_shared<detail::DirIterState>();
SmallString<128> path_storage;
ec = detail::directory_iterator_construct(*State,
path.toStringRef(path_storage));
ec = detail::directory_iterator_construct(
*State, path.toStringRef(path_storage), FollowSymlinks);
update_error_code_for_current_entry(ec);
}
explicit directory_iterator(const directory_entry &de, std::error_code &ec) {
State = new detail::DirIterState;
ec = detail::directory_iterator_construct(*State, de.path());
explicit directory_iterator(const directory_entry &de, std::error_code &ec,
bool follow_symlinks = true)
: FollowSymlinks(follow_symlinks) {
State = std::make_shared<detail::DirIterState>();
ec = detail::directory_iterator_construct(
*State, de.path(), FollowSymlinks);
update_error_code_for_current_entry(ec);
}
/// Construct end iterator.
directory_iterator() : State(nullptr) {}
directory_iterator() = default;
// No operator++ because we need error_code.
directory_iterator &increment(std::error_code &ec) {
ec = directory_iterator_increment(*State);
update_error_code_for_current_entry(ec);
return *this;
}
@@ -549,47 +649,64 @@ public:
}
// Other members as required by
// C++ Std, 24.1.1 Input iterators [input.iterators]
private:
// Checks if current entry is valid and populates error code. For example,
// current entry may not exist due to broken symbol links.
void update_error_code_for_current_entry(std::error_code &ec) {
// Bail out if error has already occured earlier to avoid overwriting it.
if (ec)
return;
// Empty directory entry is used to mark the end of an interation, it's not
// an error.
if (State->CurrentEntry == directory_entry())
return;
ErrorOr<basic_file_status> status = State->CurrentEntry.status();
if (!status)
ec = status.getError();
}
};
namespace detail {
/// RecDirIterState - Keeps state for the recursive_directory_iterator. It is
/// reference counted in order to preserve InputIterator semantics on copy.
struct RecDirIterState : public RefCountedBase<RecDirIterState> {
RecDirIterState()
: Level(0)
, HasNoPushRequest(false) {}
std::stack<directory_iterator, std::vector<directory_iterator> > Stack;
uint16_t Level;
bool HasNoPushRequest;
/// Keeps state for the recursive_directory_iterator.
struct RecDirIterState {
std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
uint16_t Level = 0;
bool HasNoPushRequest = false;
};
} // end namespace detail
/// recursive_directory_iterator - Same as directory_iterator except for it
/// recurses down into child directories.
class recursive_directory_iterator {
IntrusiveRefCntPtr<detail::RecDirIterState> State;
std::shared_ptr<detail::RecDirIterState> State;
bool Follow;
public:
recursive_directory_iterator() {}
explicit recursive_directory_iterator(const Twine &path, std::error_code &ec)
: State(new detail::RecDirIterState) {
State->Stack.push(directory_iterator(path, ec));
recursive_directory_iterator() = default;
explicit recursive_directory_iterator(const Twine &path, std::error_code &ec,
bool follow_symlinks = true)
: State(std::make_shared<detail::RecDirIterState>()),
Follow(follow_symlinks) {
State->Stack.push(directory_iterator(path, ec, Follow));
if (State->Stack.top() == directory_iterator())
State.reset();
}
// No operator++ because we need error_code.
recursive_directory_iterator &increment(std::error_code &ec) {
const directory_iterator end_itr;
const directory_iterator end_itr = {};
if (State->HasNoPushRequest)
State->HasNoPushRequest = false;
else {
file_status st;
if ((ec = State->Stack.top()->status(st))) return *this;
if (is_directory(st)) {
State->Stack.push(directory_iterator(*State->Stack.top(), ec));
if (ec) return *this;
ErrorOr<basic_file_status> status = State->Stack.top()->status();
if (status && is_directory(*status)) {
State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
if (State->Stack.top() != end_itr) {
++State->Level;
return *this;
@@ -627,7 +744,7 @@ public:
assert(State && "Cannot pop an end iterator!");
assert(State->Level > 0 && "Cannot pop an iterator with level < 1");
const directory_iterator end_itr;
const directory_iterator end_itr = {};
std::error_code ec;
do {
if (ec) {

View File

@@ -20,9 +20,10 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_FORMAT_H
#define LLVM_SUPPORT_FORMAT_H
#ifndef WPIUTIL_WPI_FORMAT_H
#define WPIUTIL_WPI_FORMAT_H
#include "wpi/ArrayRef.h"
#include "wpi/STLExtras.h"
#include "wpi/StringRef.h"
#include <cassert>
@@ -71,10 +72,20 @@ public:
};
/// These are templated helper classes used by the format function that
/// capture the object to be formated and the format string. When actually
/// capture the object to be formatted and the format string. When actually
/// printed, this synthesizes the string into a temporary buffer provided and
/// returns whether or not it is big enough.
// Helper to validate that format() parameters are scalars or pointers.
template <typename... Args> struct validate_format_parameters;
template <typename Arg, typename... Args>
struct validate_format_parameters<Arg, Args...> {
static_assert(std::is_scalar<Arg>::value,
"format can't be used with non fundamental / non pointer type");
validate_format_parameters() { validate_format_parameters<Args...>(); }
};
template <> struct validate_format_parameters<> {};
template <typename... Ts>
class format_object final : public format_object_base {
std::tuple<Ts...> Vals;
@@ -98,7 +109,9 @@ class format_object final : public format_object_base {
public:
format_object(const char *fmt, const Ts &... vals)
: format_object_base(fmt), Vals(vals...) {}
: format_object_base(fmt), Vals(vals...) {
validate_format_parameters<Ts...>();
}
int snprint(char *Buffer, unsigned BufferSize) const override {
return snprint_tuple(Buffer, BufferSize, index_sequence_for<Ts...>());
@@ -119,30 +132,39 @@ inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) {
return format_object<Ts...>(Fmt, Vals...);
}
/// This is a helper class used for left_justify() and right_justify().
/// This is a helper class for left_justify, right_justify, and center_justify.
class FormattedString {
public:
enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter };
FormattedString(StringRef S, unsigned W, Justification J)
: Str(S), Width(W), Justify(J) {}
private:
StringRef Str;
unsigned Width;
bool RightJustify;
Justification Justify;
friend class raw_ostream;
public:
FormattedString(StringRef S, unsigned W, bool R)
: Str(S), Width(W), RightJustify(R) { }
};
/// left_justify - append spaces after string so total output is
/// \p Width characters. If \p Str is larger that \p Width, full string
/// is written with no padding.
inline FormattedString left_justify(StringRef Str, unsigned Width) {
return FormattedString(Str, Width, false);
return FormattedString(Str, Width, FormattedString::JustifyLeft);
}
/// right_justify - add spaces before string so total output is
/// \p Width characters. If \p Str is larger that \p Width, full string
/// is written with no padding.
inline FormattedString right_justify(StringRef Str, unsigned Width) {
return FormattedString(Str, Width, true);
return FormattedString(Str, Width, FormattedString::JustifyRight);
}
/// center_justify - add spaces before and after string so total output is
/// \p Width characters. If \p Str is larger that \p Width, full string
/// is written with no padding.
inline FormattedString center_justify(StringRef Str, unsigned Width) {
return FormattedString(Str, Width, FormattedString::JustifyCenter);
}
/// This is a helper class used for format_hex() and format_decimal().
@@ -197,6 +219,46 @@ inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
return FormattedNumber(0, N, Width, false, false, false);
}
class FormattedBytes {
ArrayRef<uint8_t> Bytes;
// If not None, display offsets for each line relative to starting value.
Optional<uint64_t> FirstByteOffset;
uint32_t IndentLevel; // Number of characters to indent each line.
uint32_t NumPerLine; // Number of bytes to show per line.
uint8_t ByteGroupSize; // How many hex bytes are grouped without spaces
bool Upper; // Show offset and hex bytes as upper case.
bool ASCII; // Show the ASCII bytes for the hex bytes to the right.
friend class raw_ostream;
public:
FormattedBytes(ArrayRef<uint8_t> B, uint32_t IL, Optional<uint64_t> O,
uint32_t NPL, uint8_t BGS, bool U, bool A)
: Bytes(B), FirstByteOffset(O), IndentLevel(IL), NumPerLine(NPL),
ByteGroupSize(BGS), Upper(U), ASCII(A) {
if (ByteGroupSize > NumPerLine)
ByteGroupSize = NumPerLine;
}
};
inline FormattedBytes
format_bytes(ArrayRef<uint8_t> Bytes, Optional<uint64_t> FirstByteOffset = None,
uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
uint32_t IndentLevel = 0, bool Upper = false) {
return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
ByteGroupSize, Upper, false);
}
inline FormattedBytes
format_bytes_with_ascii(ArrayRef<uint8_t> Bytes,
Optional<uint64_t> FirstByteOffset = None,
uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
uint32_t IndentLevel = 0, bool Upper = false) {
return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
ByteGroupSize, Upper, true);
}
} // end namespace wpi
#endif

View File

@@ -42,8 +42,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_HASHING_H
#define LLVM_ADT_HASHING_H
#ifndef WPIUTIL_WPI_HASHING_H
#define WPIUTIL_WPI_HASHING_H
#include "wpi/type_traits.h"
#include <algorithm>
@@ -55,7 +55,7 @@
namespace wpi {
/// \brief An opaque object representing a hash code.
/// An opaque object representing a hash code.
///
/// This object represents the result of hashing some entity. It is intended to
/// be used to implement hashtables or other hashing-based data structures.
@@ -71,14 +71,14 @@ class hash_code {
size_t value;
public:
/// \brief Default construct a hash_code.
/// Default construct a hash_code.
/// Note that this leaves the value uninitialized.
hash_code() = default;
/// \brief Form a hash code directly from a numerical value.
/// Form a hash code directly from a numerical value.
hash_code(size_t value) : value(value) {}
/// \brief Convert the hash code to its numerical value for use.
/// Convert the hash code to its numerical value for use.
/*explicit*/ operator size_t() const { return value; }
friend bool operator==(const hash_code &lhs, const hash_code &rhs) {
@@ -88,11 +88,11 @@ public:
return lhs.value != rhs.value;
}
/// \brief Allow a hash_code to be directly run through hash_value.
/// Allow a hash_code to be directly run through hash_value.
friend size_t hash_value(const hash_code &code) { return code.value; }
};
/// \brief Compute a hash_code for any integer value.
/// Compute a hash_code for any integer value.
///
/// Note that this function is intended to compute the same hash_code for
/// a particular value without regard to the pre-promotion type. This is in
@@ -103,21 +103,21 @@ template <typename T>
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
hash_value(T value);
/// \brief Compute a hash_code for a pointer's address.
/// Compute a hash_code for a pointer's address.
///
/// N.B.: This hashes the *address*. Not the value and not the type.
template <typename T> hash_code hash_value(const T *ptr);
/// \brief Compute a hash_code for a pair of objects.
/// Compute a hash_code for a pair of objects.
template <typename T, typename U>
hash_code hash_value(const std::pair<T, U> &arg);
/// \brief Compute a hash_code for a standard string.
/// Compute a hash_code for a standard string.
template <typename T>
hash_code hash_value(const std::basic_string<T> &arg);
/// \brief Override the execution seed with a fixed value.
/// Override the execution seed with a fixed value.
///
/// This hashing library uses a per-execution seed designed to change on each
/// run with high probability in order to ensure that the hash codes are not
@@ -162,7 +162,7 @@ static const uint64_t k1 = 0xb492b66fbe98f273ULL;
static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
static const uint64_t k3 = 0xc949d7c7509e6557ULL;
/// \brief Bitwise right rotate.
/// Bitwise right rotate.
/// Normally this will compile to a single instruction, especially if the
/// shift is a manifest constant.
inline uint64_t rotate(uint64_t val, size_t shift) {
@@ -252,13 +252,13 @@ inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
return k2 ^ seed;
}
/// \brief The intermediate state used during hashing.
/// The intermediate state used during hashing.
/// Currently, the algorithm for computing hash codes is based on CityHash and
/// keeps 56 bytes of arbitrary state.
struct hash_state {
uint64_t h0, h1, h2, h3, h4, h5, h6;
/// \brief Create a new hash_state structure and initialize it based on the
/// Create a new hash_state structure and initialize it based on the
/// seed and the first 64-byte chunk.
/// This effectively performs the initial mix.
static hash_state create(const char *s, uint64_t seed) {
@@ -270,7 +270,7 @@ struct hash_state {
return state;
}
/// \brief Mix 32-bytes from the input sequence into the 16-bytes of 'a'
/// Mix 32-bytes from the input sequence into the 16-bytes of 'a'
/// and 'b', including whatever is already in 'a' and 'b'.
static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
a += fetch64(s);
@@ -282,7 +282,7 @@ struct hash_state {
a += c;
}
/// \brief Mix in a 64-byte buffer of data.
/// Mix in a 64-byte buffer of data.
/// We mix all 64 bytes even when the chunk length is smaller, but we
/// record the actual length.
void mix(const char *s) {
@@ -300,7 +300,7 @@ struct hash_state {
std::swap(h2, h0);
}
/// \brief Compute the final 64-bit hash code value based on the current
/// Compute the final 64-bit hash code value based on the current
/// state and the length of bytes hashed.
uint64_t finalize(size_t length) {
return hash_16_bytes(hash_16_bytes(h3, h5) + shift_mix(h1) * k1 + h2,
@@ -309,7 +309,7 @@ struct hash_state {
};
/// \brief A global, fixed seed-override variable.
/// A global, fixed seed-override variable.
///
/// This variable can be set using the \see wpi::set_fixed_execution_seed
/// function. See that function for details. Do not, under any circumstances,
@@ -330,7 +330,7 @@ inline size_t get_execution_seed() {
}
/// \brief Trait to indicate whether a type's bits can be hashed directly.
/// Trait to indicate whether a type's bits can be hashed directly.
///
/// A type trait which is true if we want to combine values for hashing by
/// reading the underlying data. It is false if values of this type must
@@ -357,14 +357,14 @@ template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
(sizeof(T) + sizeof(U)) ==
sizeof(std::pair<T, U>))> {};
/// \brief Helper to get the hashable data representation for a type.
/// Helper to get the hashable data representation for a type.
/// This variant is enabled when the type itself can be used.
template <typename T>
typename std::enable_if<is_hashable_data<T>::value, T>::type
get_hashable_data(const T &value) {
return value;
}
/// \brief Helper to get the hashable data representation for a type.
/// Helper to get the hashable data representation for a type.
/// This variant is enabled when we must first call hash_value and use the
/// result as our data.
template <typename T>
@@ -374,7 +374,7 @@ get_hashable_data(const T &value) {
return hash_value(value);
}
/// \brief Helper to store data from a value into a buffer and advance the
/// Helper to store data from a value into a buffer and advance the
/// pointer into that buffer.
///
/// This routine first checks whether there is enough space in the provided
@@ -393,7 +393,7 @@ bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
return true;
}
/// \brief Implement the combining of integral values into a hash_code.
/// Implement the combining of integral values into a hash_code.
///
/// This overload is selected when the value type of the iterator is
/// integral. Rather than computing a hash_code for each object and then
@@ -433,7 +433,7 @@ hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
return state.finalize(length);
}
/// \brief Implement the combining of integral values into a hash_code.
/// Implement the combining of integral values into a hash_code.
///
/// This overload is selected when the value type of the iterator is integral
/// and when the input iterator is actually a pointer. Rather than computing
@@ -468,7 +468,7 @@ hash_combine_range_impl(ValueT *first, ValueT *last) {
} // namespace hashing
/// \brief Compute a hash_code for a sequence of values.
/// Compute a hash_code for a sequence of values.
///
/// This hashes a sequence of values. It produces the same hash_code as
/// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences
@@ -484,7 +484,7 @@ hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
namespace hashing {
namespace detail {
/// \brief Helper class to manage the recursive combining of hash_combine
/// Helper class to manage the recursive combining of hash_combine
/// arguments.
///
/// This class exists to manage the state and various calls involved in the
@@ -497,14 +497,14 @@ struct hash_combine_recursive_helper {
const size_t seed;
public:
/// \brief Construct a recursive hash combining helper.
/// Construct a recursive hash combining helper.
///
/// This sets up the state for a recursive hash combine, including getting
/// the seed and buffer setup.
hash_combine_recursive_helper()
: seed(get_execution_seed()) {}
/// \brief Combine one chunk of data into the current in-flight hash.
/// Combine one chunk of data into the current in-flight hash.
///
/// This merges one chunk of data into the hash. First it tries to buffer
/// the data. If the buffer is full, it hashes the buffer into its
@@ -545,7 +545,7 @@ public:
return buffer_ptr;
}
/// \brief Recursive, variadic combining method.
/// Recursive, variadic combining method.
///
/// This function recurses through each argument, combining that argument
/// into a single hash.
@@ -558,7 +558,7 @@ public:
return combine(length, buffer_ptr, buffer_end, args...);
}
/// \brief Base case for recursive, variadic combining.
/// Base case for recursive, variadic combining.
///
/// The base case when combining arguments recursively is reached when all
/// arguments have been handled. It flushes the remaining buffer and
@@ -586,7 +586,7 @@ public:
} // namespace detail
} // namespace hashing
/// \brief Combine values into a single hash_code.
/// Combine values into a single hash_code.
///
/// This routine accepts a varying number of arguments of any type. It will
/// attempt to combine them into a single hash_code. For user-defined types it
@@ -608,7 +608,7 @@ template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
namespace hashing {
namespace detail {
/// \brief Helper to hash the value of a single integer.
/// Helper to hash the value of a single integer.
///
/// Overloads for smaller integer types are not provided to ensure consistent
/// behavior in the presence of integral promotions. Essentially,

View File

@@ -1,4 +1,4 @@
//== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- C++ -*-==//
//==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -7,19 +7,54 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines IntrusiveRefCntPtr, a template class that
// implements a "smart" pointer for objects that maintain their own
// internal reference count, and RefCountedBase/RefCountedBaseVPTR, two
// generic base classes for objects that wish to have their lifetimes
// managed using reference counting.
// This file defines the RefCountedBase, ThreadSafeRefCountedBase, and
// IntrusiveRefCntPtr classes.
//
// IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added
// LLVM-style casting.
// IntrusiveRefCntPtr is a smart pointer to an object which maintains a
// reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a
// refcount member variable and methods for updating the refcount. An object
// that inherits from (ThreadSafe)RefCountedBase deletes itself when its
// refcount hits zero.
//
// For example:
//
// class MyClass : public RefCountedBase<MyClass> {};
//
// void foo() {
// // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by
// // 1 (from 0 in this case).
// IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass());
//
// // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1.
// IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1);
//
// // Constructing an IntrusiveRefCntPtr has no effect on the object's
// // refcount. After a move, the moved-from pointer is null.
// IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1));
// assert(Ptr1 == nullptr);
//
// // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1.
// Ptr2.reset();
//
// // The object deletes itself when we return from the function, because
// // Ptr3's destructor decrements its refcount to 0.
// }
//
// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.:
//
// IntrusiveRefCntPtr<MyClass> Ptr(new MyClass());
// OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required
//
// IntrusiveRefCntPtr works with any class that
//
// - inherits from (ThreadSafe)RefCountedBase,
// - has Retain() and Release() methods, or
// - specializes IntrusiveRefCntPtrInfo.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
#define LLVM_ADT_INTRUSIVEREFCNTPTR_H
#ifndef WPIUTIL_WPI_INTRUSIVEREFCNTPTR_H
#define WPIUTIL_WPI_INTRUSIVEREFCNTPTR_H
#include <atomic>
#include <cassert>
@@ -27,261 +62,208 @@
namespace wpi {
template <class T>
class IntrusiveRefCntPtr;
//===----------------------------------------------------------------------===//
/// RefCountedBase - A generic base class for objects that wish to
/// have their lifetimes managed using reference counts. Classes
/// subclass RefCountedBase to obtain such functionality, and are
/// typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
/// which automatically handle the management of reference counts.
/// Objects that subclass RefCountedBase should not be allocated on
/// the stack, as invoking "delete" (which is called when the
/// reference count hits 0) on such objects is an error.
//===----------------------------------------------------------------------===//
template <class Derived>
class RefCountedBase {
mutable unsigned ref_cnt;
public:
RefCountedBase() : ref_cnt(0) {}
RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
void Retain() const { ++ref_cnt; }
void Release() const {
assert (ref_cnt > 0 && "Reference count is already zero.");
if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
}
};
//===----------------------------------------------------------------------===//
/// RefCountedBaseVPTR - A class that has the same function as
/// RefCountedBase, but with a virtual destructor. Should be used
/// instead of RefCountedBase for classes that already have virtual
/// methods to enforce dynamic allocation via 'new'. Classes that
/// inherit from RefCountedBaseVPTR can't be allocated on stack -
/// attempting to do this will produce a compile error.
//===----------------------------------------------------------------------===//
class RefCountedBaseVPTR {
mutable unsigned ref_cnt;
virtual void anchor();
protected:
RefCountedBaseVPTR() : ref_cnt(0) {}
RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
virtual ~RefCountedBaseVPTR() {}
void Retain() const { ++ref_cnt; }
void Release() const {
assert (ref_cnt > 0 && "Reference count is already zero.");
if (--ref_cnt == 0) delete this;
}
template <typename T>
friend struct IntrusiveRefCntPtrInfo;
};
template <typename T> struct IntrusiveRefCntPtrInfo {
static void retain(T *obj) { obj->Retain(); }
static void release(T *obj) { obj->Release(); }
};
/// \brief A thread-safe version of \c wpi::RefCountedBase.
/// A CRTP mixin class that adds reference counting to a type.
///
/// A generic base class for objects that wish to have their lifetimes managed
/// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
/// obtain such functionality, and are typically handled with
/// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
/// management of reference counts.
template <class Derived>
class ThreadSafeRefCountedBase {
/// The lifetime of an object which inherits from RefCountedBase is managed by
/// calls to Release() and Retain(), which increment and decrement the object's
/// refcount, respectively. When a Release() call decrements the refcount to 0,
/// the object deletes itself.
template <class Derived> class RefCountedBase {
mutable unsigned RefCount = 0;
public:
RefCountedBase() = default;
RefCountedBase(const RefCountedBase &) {}
void Retain() const { ++RefCount; }
void Release() const {
assert(RefCount > 0 && "Reference count is already zero.");
if (--RefCount == 0)
delete static_cast<const Derived *>(this);
}
};
/// A thread-safe version of \c RefCountedBase.
template <class Derived> class ThreadSafeRefCountedBase {
mutable std::atomic<int> RefCount;
protected:
ThreadSafeRefCountedBase() : RefCount(0) {}
public:
void Retain() const { ++RefCount; }
void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
void Release() const {
int NewRefCount = --RefCount;
int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
assert(NewRefCount >= 0 && "Reference count was already zero.");
if (NewRefCount == 0)
delete static_cast<const Derived*>(this);
delete static_cast<const Derived *>(this);
}
};
//===----------------------------------------------------------------------===//
/// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
/// that assumes the wrapped object has a reference count associated
/// with it that can be managed via calls to
/// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers
/// manage reference counts via the RAII idiom: upon creation of
/// smart pointer the reference count of the wrapped object is
/// incremented and upon destruction of the smart pointer the
/// reference count is decremented. This class also safely handles
/// wrapping NULL pointers.
/// Class you can specialize to provide custom retain/release functionality for
/// a type.
///
/// Reference counting is implemented via calls to
/// Obj->Retain()/Obj->Release(). Release() is required to destroy
/// the object when the reference count reaches zero. Inheriting from
/// RefCountedBase/RefCountedBaseVPTR takes care of this
/// automatically.
//===----------------------------------------------------------------------===//
template <typename T>
class IntrusiveRefCntPtr {
T* Obj;
/// Usually specializing this class is not necessary, as IntrusiveRefCntPtr
/// works with any type which defines Retain() and Release() functions -- you
/// can define those functions yourself if RefCountedBase doesn't work for you.
///
/// One case when you might want to specialize this type is if you have
/// - Foo.h defines type Foo and includes Bar.h, and
/// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions.
///
/// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in
/// the declaration of Foo. Without the declaration of Foo, normally Bar.h
/// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call
/// T::Retain and T::Release.
///
/// To resolve this, Bar.h could include a third header, FooFwd.h, which
/// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then
/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
/// functions on Foo itself, because Foo would be an incomplete type.
template <typename T> struct IntrusiveRefCntPtrInfo {
static void retain(T *obj) { obj->Retain(); }
static void release(T *obj) { obj->Release(); }
};
public:
typedef T element_type;
/// A smart pointer to a reference-counted object that inherits from
/// RefCountedBase or ThreadSafeRefCountedBase.
///
/// This class increments its pointee's reference count when it is created, and
/// decrements its refcount when it's destroyed (or is changed to point to a
/// different object).
template <typename T> class IntrusiveRefCntPtr {
T *Obj = nullptr;
explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
public:
using element_type = T;
IntrusiveRefCntPtr(T* obj) : Obj(obj) {
retain();
}
explicit IntrusiveRefCntPtr() = default;
IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); }
IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); }
IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; }
IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
retain();
}
IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
S.Obj = nullptr;
}
template <class X>
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
S.Obj = nullptr;
}
template <class X>
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
: Obj(S.get()) {
retain();
}
IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
swap(S);
return *this;
}
~IntrusiveRefCntPtr() { release(); }
T& operator*() const { return *Obj; }
T* operator->() const { return Obj; }
T* get() const { return Obj; }
explicit operator bool() const { return Obj; }
void swap(IntrusiveRefCntPtr& other) {
T* tmp = other.Obj;
other.Obj = Obj;
Obj = tmp;
}
void reset() {
release();
Obj = nullptr;
}
void resetWithoutRelease() {
Obj = nullptr;
}
private:
void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
template <typename X>
friend class IntrusiveRefCntPtr;
};
template<class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
const IntrusiveRefCntPtr<U>& B)
{
return A.get() == B.get();
template <class X>
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) {
S.Obj = nullptr;
}
template<class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
const IntrusiveRefCntPtr<U>& B)
{
return A.get() != B.get();
template <class X>
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) {
retain();
}
template<class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
U* B)
{
return A.get() == B;
~IntrusiveRefCntPtr() { release(); }
IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) {
swap(S);
return *this;
}
template<class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
U* B)
{
return A.get() != B;
T &operator*() const { return *Obj; }
T *operator->() const { return Obj; }
T *get() const { return Obj; }
explicit operator bool() const { return Obj; }
void swap(IntrusiveRefCntPtr &other) {
T *tmp = other.Obj;
other.Obj = Obj;
Obj = tmp;
}
template<class T, class U>
inline bool operator==(T* A,
const IntrusiveRefCntPtr<U>& B)
{
return A == B.get();
void reset() {
release();
Obj = nullptr;
}
template<class T, class U>
inline bool operator!=(T* A,
const IntrusiveRefCntPtr<U>& B)
{
return A != B.get();
void resetWithoutRelease() { Obj = nullptr; }
private:
void retain() {
if (Obj)
IntrusiveRefCntPtrInfo<T>::retain(Obj);
}
template <class T>
bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !B;
void release() {
if (Obj)
IntrusiveRefCntPtrInfo<T>::release(Obj);
}
template <class T>
bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return B == A;
template <typename X> friend class IntrusiveRefCntPtr;
};
template <class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T> &A,
const IntrusiveRefCntPtr<U> &B) {
return A.get() == B.get();
}
template <class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T> &A,
const IntrusiveRefCntPtr<U> &B) {
return A.get() != B.get();
}
template <class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) {
return A.get() == B;
}
template <class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) {
return A.get() != B;
}
template <class T, class U>
inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) {
return A == B.get();
}
template <class T, class U>
inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) {
return A != B.get();
}
template <class T>
bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !B;
}
template <class T>
bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return B == A;
}
template <class T>
bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !(A == B);
}
template <class T>
bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return !(A == B);
}
// Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from
// Casting.h.
template <typename From> struct simplify_type;
template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
using SimpleType = T *;
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) {
return Val.get();
}
};
template <class T>
bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !(A == B);
template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
using SimpleType = /*const*/ T *;
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) {
return Val.get();
}
template <class T>
bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return !(A == B);
}
//===----------------------------------------------------------------------===//
// LLVM-style downcasting support for IntrusiveRefCntPtr objects
//===----------------------------------------------------------------------===//
template <typename From> struct simplify_type;
template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
typedef T* SimpleType;
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
return Val.get();
}
};
template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
typedef /*const*/ T* SimpleType;
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
return Val.get();
}
};
};
} // end namespace wpi

View File

@@ -11,33 +11,108 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_MATHEXTRAS_H
#define LLVM_SUPPORT_MATHEXTRAS_H
#ifndef WPIUTIL_WPI_MATHEXTRAS_H
#define WPIUTIL_WPI_MATHEXTRAS_H
#include "wpi/Compiler.h"
#include <cstdint>
#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstring>
#include <type_traits>
#include <limits>
#include <type_traits>
#ifdef _MSC_VER
#include <intrin.h>
#endif
namespace wpi {
/// \brief The behavior an operation has on an input of 0.
/// The behavior an operation has on an input of 0.
enum ZeroBehavior {
/// \brief The returned value is undefined.
/// The returned value is undefined.
ZB_Undefined,
/// \brief The returned value is numeric_limits<T>::max()
/// The returned value is numeric_limits<T>::max()
ZB_Max,
/// \brief The returned value is numeric_limits<T>::digits
/// The returned value is numeric_limits<T>::digits
ZB_Width
};
namespace detail {
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
if (Val & 0x1)
return 0;
// Bisection method.
std::size_t ZeroBits = 0;
T Shift = std::numeric_limits<T>::digits >> 1;
T Mask = std::numeric_limits<T>::max() >> Shift;
while (Shift) {
if ((Val & Mask) == 0) {
Val >>= Shift;
ZeroBits |= Shift;
}
Shift >>= 1;
Mask >>= Shift;
}
return ZeroBits;
}
};
#if __GNUC__ >= 4 || defined(_MSC_VER)
template <typename T> struct TrailingZerosCounter<T, 4> {
static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
#if __has_builtin(__builtin_ctz) || LLVM_GNUC_PREREQ(4, 0, 0)
return __builtin_ctz(Val);
#elif defined(_MSC_VER)
unsigned long Index;
_BitScanForward(&Index, Val);
return Index;
#endif
}
};
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct TrailingZerosCounter<T, 8> {
static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
#if __has_builtin(__builtin_ctzll) || LLVM_GNUC_PREREQ(4, 0, 0)
return __builtin_ctzll(Val);
#elif defined(_MSC_VER)
unsigned long Index;
_BitScanForward64(&Index, Val);
return Index;
#endif
}
};
#endif
#endif
} // namespace detail
/// Count number of 0's from the least significant bit to the most
/// stopping at the first 1.
///
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
return wpi::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
}
namespace detail {
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) {
@@ -92,7 +167,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
#endif
} // namespace detail
/// \brief Count number of 0's from the most significant bit to the least
/// Count number of 0's from the most significant bit to the least
/// stopping at the first 1.
///
/// Only unsigned integral types are allowed.
@@ -104,10 +179,51 @@ std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
return wpi::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
}
/// \brief Get the index of the last set bit starting from the least
/// Get the index of the first set bit starting from the least
/// significant bit.
///
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
/// valid arguments.
template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
if (ZB == ZB_Max && Val == 0)
return std::numeric_limits<T>::max();
return countTrailingZeros(Val, ZB_Undefined);
}
/// Create a bitmask with the N right-most bits set to 1, and all other
/// bits set to 0. Only unsigned types are allowed.
template <typename T> T maskTrailingOnes(unsigned N) {
static_assert(std::is_unsigned<T>::value, "Invalid type!");
const unsigned Bits = CHAR_BIT * sizeof(T);
assert(N <= Bits && "Invalid bit index");
return N == 0 ? 0 : (T(-1) >> (Bits - N));
}
/// Create a bitmask with the N left-most bits set to 1, and all other
/// bits set to 0. Only unsigned types are allowed.
template <typename T> T maskLeadingOnes(unsigned N) {
return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
}
/// Create a bitmask with the N right-most bits set to 0, and all other
/// bits set to 1. Only unsigned types are allowed.
template <typename T> T maskTrailingZeros(unsigned N) {
return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
}
/// Create a bitmask with the N left-most bits set to 0, and all other
/// bits set to 1. Only unsigned types are allowed.
template <typename T> T maskLeadingZeros(unsigned N) {
return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
}
/// Get the index of the last set bit starting from the least
/// significant bit.
///
/// Only unsigned integral types are allowed.
@@ -124,7 +240,7 @@ template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
(std::numeric_limits<T>::digits - 1);
}
/// \brief Macro compressed bit reversal table for 256 bits.
/// Macro compressed bit reversal table for 256 bits.
///
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
static const unsigned char BitReverseTable256[256] = {
@@ -137,7 +253,7 @@ static const unsigned char BitReverseTable256[256] = {
#undef R6
};
/// \brief Reverse the bits in \p Val.
/// Reverse the bits in \p Val.
template <typename T>
T reverseBits(T Val) {
unsigned char in[sizeof(Val)];
@@ -153,150 +269,165 @@ T reverseBits(T Val) {
// type overloading so that signed and unsigned integers can be used without
// ambiguity.
/// Hi_32 - This function returns the high 32 bits of a 64 bit value.
inline uint32_t Hi_32(uint64_t Value) {
/// Return the high 32 bits of a 64 bit value.
constexpr inline uint32_t Hi_32(uint64_t Value) {
return static_cast<uint32_t>(Value >> 32);
}
/// Lo_32 - This function returns the low 32 bits of a 64 bit value.
inline uint32_t Lo_32(uint64_t Value) {
/// Return the low 32 bits of a 64 bit value.
constexpr inline uint32_t Lo_32(uint64_t Value) {
return static_cast<uint32_t>(Value);
}
/// Make_64 - This functions makes a 64-bit integer from a high / low pair of
/// 32-bit integers.
inline uint64_t Make_64(uint32_t High, uint32_t Low) {
/// Make a 64-bit integer from a high / low pair of 32-bit integers.
constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
return ((uint64_t)High << 32) | (uint64_t)Low;
}
/// isInt - Checks if an integer fits into the given bit width.
template<unsigned N>
inline bool isInt(int64_t x) {
/// Checks if an integer fits into the given bit width.
template <unsigned N> constexpr inline bool isInt(int64_t x) {
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
}
// Template specializations to get better code for common cases.
template<>
inline bool isInt<8>(int64_t x) {
template <> constexpr inline bool isInt<8>(int64_t x) {
return static_cast<int8_t>(x) == x;
}
template<>
inline bool isInt<16>(int64_t x) {
template <> constexpr inline bool isInt<16>(int64_t x) {
return static_cast<int16_t>(x) == x;
}
template<>
inline bool isInt<32>(int64_t x) {
template <> constexpr inline bool isInt<32>(int64_t x) {
return static_cast<int32_t>(x) == x;
}
/// isShiftedInt<N,S> - Checks if a signed integer is an N bit number shifted
/// left by S.
template<unsigned N, unsigned S>
inline bool isShiftedInt(int64_t x) {
return isInt<N+S>(x) && (x % (1<<S) == 0);
/// Checks if a signed integer is an N bit number shifted left by S.
template <unsigned N, unsigned S>
constexpr inline bool isShiftedInt(int64_t x) {
static_assert(
N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
}
/// isUInt - Checks if an unsigned integer fits into the given bit width.
template<unsigned N>
inline bool isUInt(uint64_t x) {
return N >= 64 || x < (UINT64_C(1)<<(N));
/// Checks if an unsigned integer fits into the given bit width.
///
/// This is written as two functions rather than as simply
///
/// return N >= 64 || X < (UINT64_C(1) << N);
///
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
/// left too many places.
template <unsigned N>
constexpr inline typename std::enable_if<(N < 64), bool>::type
isUInt(uint64_t X) {
static_assert(N > 0, "isUInt<0> doesn't make sense");
return X < (UINT64_C(1) << (N));
}
template <unsigned N>
constexpr inline typename std::enable_if<N >= 64, bool>::type
isUInt(uint64_t X) {
return true;
}
// Template specializations to get better code for common cases.
template<>
inline bool isUInt<8>(uint64_t x) {
template <> constexpr inline bool isUInt<8>(uint64_t x) {
return static_cast<uint8_t>(x) == x;
}
template<>
inline bool isUInt<16>(uint64_t x) {
template <> constexpr inline bool isUInt<16>(uint64_t x) {
return static_cast<uint16_t>(x) == x;
}
template<>
inline bool isUInt<32>(uint64_t x) {
template <> constexpr inline bool isUInt<32>(uint64_t x) {
return static_cast<uint32_t>(x) == x;
}
/// isShiftedUInt<N,S> - Checks if a unsigned integer is an N bit number shifted
/// left by S.
template<unsigned N, unsigned S>
inline bool isShiftedUInt(uint64_t x) {
return isUInt<N+S>(x) && (x % (1<<S) == 0);
/// Checks if a unsigned integer is an N bit number shifted left by S.
template <unsigned N, unsigned S>
constexpr inline bool isShiftedUInt(uint64_t x) {
static_assert(
N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
static_assert(N + S <= 64,
"isShiftedUInt<N, S> with N + S > 64 is too wide.");
// Per the two static_asserts above, S must be strictly less than 64. So
// 1 << S is not undefined behavior.
return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
}
/// Gets the maximum value for a N-bit unsigned integer.
inline uint64_t maxUIntN(uint64_t N) {
assert(N > 0 && N <= 64 && "integer width out of range");
return (UINT64_C(1) << N) - 1;
// uint64_t(1) << 64 is undefined behavior, so we can't do
// (uint64_t(1) << N) - 1
// without checking first that N != 64. But this works and doesn't have a
// branch.
return UINT64_MAX >> (64 - N);
}
/// Gets the minimum value for a N-bit signed integer.
inline int64_t minIntN(int64_t N) {
assert(N > 0 && N <= 64 && "integer width out of range");
return -(INT64_C(1)<<(N-1));
return -(UINT64_C(1)<<(N-1));
}
/// Gets the maximum value for a N-bit signed integer.
inline int64_t maxIntN(int64_t N) {
assert(N > 0 && N <= 64 && "integer width out of range");
return (INT64_C(1)<<(N-1)) - 1;
// This relies on two's complement wraparound when N == 64, so we convert to
// int64_t only at the very end to avoid UB.
return (UINT64_C(1) << (N - 1)) - 1;
}
/// isUIntN - Checks if an unsigned integer fits into the given (dynamic)
/// bit width.
/// Checks if an unsigned integer fits into the given (dynamic) bit width.
inline bool isUIntN(unsigned N, uint64_t x) {
return N >= 64 || x <= maxUIntN(N);
}
/// isIntN - Checks if an signed integer fits into the given (dynamic)
/// bit width.
/// Checks if an signed integer fits into the given (dynamic) bit width.
inline bool isIntN(unsigned N, int64_t x) {
return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
}
/// isMask_32 - This function returns true if the argument is a non-empty
/// sequence of ones starting at the least significant bit with the remainder
/// zero (32 bit version). Ex. isMask_32(0x0000FFFFU) == true.
inline bool isMask_32(uint32_t Value) {
/// Return true if the argument is a non-empty sequence of ones starting at the
/// least significant bit with the remainder zero (32 bit version).
/// Ex. isMask_32(0x0000FFFFU) == true.
constexpr inline bool isMask_32(uint32_t Value) {
return Value && ((Value + 1) & Value) == 0;
}
/// isMask_64 - This function returns true if the argument is a non-empty
/// sequence of ones starting at the least significant bit with the remainder
/// zero (64 bit version).
inline bool isMask_64(uint64_t Value) {
/// Return true if the argument is a non-empty sequence of ones starting at the
/// least significant bit with the remainder zero (64 bit version).
constexpr inline bool isMask_64(uint64_t Value) {
return Value && ((Value + 1) & Value) == 0;
}
/// isShiftedMask_32 - This function returns true if the argument contains a
/// non-empty sequence of ones with the remainder zero (32 bit version.)
/// Ex. isShiftedMask_32(0x0000FF00U) == true.
inline bool isShiftedMask_32(uint32_t Value) {
/// Return true if the argument contains a non-empty sequence of ones with the
/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
constexpr inline bool isShiftedMask_32(uint32_t Value) {
return Value && isMask_32((Value - 1) | Value);
}
/// isShiftedMask_64 - This function returns true if the argument contains a
/// non-empty sequence of ones with the remainder zero (64 bit version.)
inline bool isShiftedMask_64(uint64_t Value) {
/// Return true if the argument contains a non-empty sequence of ones with the
/// remainder zero (64 bit version.)
constexpr inline bool isShiftedMask_64(uint64_t Value) {
return Value && isMask_64((Value - 1) | Value);
}
/// isPowerOf2_32 - This function returns true if the argument is a power of
/// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
inline bool isPowerOf2_32(uint32_t Value) {
/// Return true if the argument is a power of two > 0.
/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
constexpr inline bool isPowerOf2_32(uint32_t Value) {
return Value && !(Value & (Value - 1));
}
/// isPowerOf2_64 - This function returns true if the argument is a power of two
/// > 0 (64 bit edition.)
inline bool isPowerOf2_64(uint64_t Value) {
return Value && !(Value & (Value - int64_t(1L)));
/// Return true if the argument is a power of two > 0 (64 bit edition.)
constexpr inline bool isPowerOf2_64(uint64_t Value) {
return Value && !(Value & (Value - 1));
}
/// \brief Count the number of ones from the most significant bit to the first
/// Count the number of ones from the most significant bit to the first
/// zero bit.
///
/// Ex. CountLeadingOnes(0xFF0FFF00) == 8.
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
@@ -306,7 +437,23 @@ std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
return countLeadingZeros(~Value, ZB);
return countLeadingZeros<T>(~Value, ZB);
}
/// Count the number of ones from the least significant bit to the first
/// zero bit.
///
/// Ex. countTrailingOnes(0x00FF00FF) == 8.
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
return countTrailingZeros<T>(~Value, ZB);
}
namespace detail {
@@ -340,7 +487,7 @@ template <typename T> struct PopulationCounter<T, 8> {
};
} // namespace detail
/// \brief Count the number of set bits in a value.
/// Count the number of set bits in a value.
/// Ex. countPopulation(0xF000F000) = 8
/// Returns 0 if the word is zero.
template <typename T>
@@ -351,7 +498,7 @@ inline unsigned countPopulation(T Value) {
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
}
/// Log2 - This function returns the log base 2 of the specified value
/// Return the log base 2 of the specified value.
inline double Log2(double Value) {
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
return __builtin_log(Value) / __builtin_log(2.0);
@@ -360,34 +507,33 @@ inline double Log2(double Value) {
#endif
}
/// Log2_32 - This function returns the floor log base 2 of the specified value,
/// -1 if the value is zero. (32 bit edition.)
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
/// (32 bit edition.)
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
inline unsigned Log2_32(uint32_t Value) {
return 31 - countLeadingZeros(Value);
}
/// Log2_64 - This function returns the floor log base 2 of the specified value,
/// -1 if the value is zero. (64 bit edition.)
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
/// (64 bit edition.)
inline unsigned Log2_64(uint64_t Value) {
return 63 - countLeadingZeros(Value);
}
/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified
/// value, 32 if the value is zero. (32 bit edition).
/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
/// (32 bit edition).
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
inline unsigned Log2_32_Ceil(uint32_t Value) {
return 32 - countLeadingZeros(Value - 1);
}
/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified
/// value, 64 if the value is zero. (64 bit edition.)
/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
/// (64 bit edition.)
inline unsigned Log2_64_Ceil(uint64_t Value) {
return 64 - countLeadingZeros(Value - 1);
}
/// GreatestCommonDivisor64 - Return the greatest common divisor of the two
/// values using Euclid's algorithm.
/// Return the greatest common divisor of the values using Euclid's algorithm.
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
while (B) {
uint64_t T = B;
@@ -397,57 +543,45 @@ inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
return A;
}
/// BitsToDouble - This function takes a 64-bit integer and returns the bit
/// equivalent double.
/// This function takes a 64-bit integer and returns the bit equivalent double.
inline double BitsToDouble(uint64_t Bits) {
union {
uint64_t L;
double D;
} T;
T.L = Bits;
return T.D;
double D;
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
memcpy(&D, &Bits, sizeof(Bits));
return D;
}
/// BitsToFloat - This function takes a 32-bit integer and returns the bit
/// equivalent float.
/// This function takes a 32-bit integer and returns the bit equivalent float.
inline float BitsToFloat(uint32_t Bits) {
union {
uint32_t I;
float F;
} T;
T.I = Bits;
return T.F;
float F;
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
memcpy(&F, &Bits, sizeof(Bits));
return F;
}
/// DoubleToBits - This function takes a double and returns the bit
/// equivalent 64-bit integer. Note that copying doubles around
/// changes the bits of NaNs on some hosts, notably x86, so this
/// routine cannot be used if these bits are needed.
/// This function takes a double and returns the bit equivalent 64-bit integer.
/// Note that copying doubles around changes the bits of NaNs on some hosts,
/// notably x86, so this routine cannot be used if these bits are needed.
inline uint64_t DoubleToBits(double Double) {
union {
uint64_t L;
double D;
} T;
T.D = Double;
return T.L;
uint64_t Bits;
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
memcpy(&Bits, &Double, sizeof(Double));
return Bits;
}
/// FloatToBits - This function takes a float and returns the bit
/// equivalent 32-bit integer. Note that copying floats around
/// changes the bits of NaNs on some hosts, notably x86, so this
/// routine cannot be used if these bits are needed.
/// This function takes a float and returns the bit equivalent 32-bit integer.
/// Note that copying floats around changes the bits of NaNs on some hosts,
/// notably x86, so this routine cannot be used if these bits are needed.
inline uint32_t FloatToBits(float Float) {
union {
uint32_t I;
float F;
} T;
T.F = Float;
return T.I;
uint32_t Bits;
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
memcpy(&Bits, &Float, sizeof(Float));
return Bits;
}
/// MinAlign - A and B are either alignments or offsets. Return the minimum
/// alignment that may be assumed after adding the two together.
inline uint64_t MinAlign(uint64_t A, uint64_t B) {
/// A and B are either alignments or offsets. Return the minimum alignment that
/// may be assumed after adding the two together.
constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
// The largest power of 2 that divides both A and B.
//
// Replace "-Value" by "1+~Value" in the following commented code to avoid
@@ -456,7 +590,7 @@ inline uint64_t MinAlign(uint64_t A, uint64_t B) {
return (A | B) & (1 + ~(A | B));
}
/// \brief Aligns \c Addr to \c Alignment bytes, rounding up.
/// Aligns \c Addr to \c Alignment bytes, rounding up.
///
/// Alignment should be a power of two. This method rounds up, so
/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
@@ -469,14 +603,14 @@ inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
}
/// \brief Returns the necessary adjustment for aligning \c Ptr to \c Alignment
/// Returns the necessary adjustment for aligning \c Ptr to \c Alignment
/// bytes, rounding up.
inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) {
return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
}
/// NextPowerOf2 - Returns the next power of two (in 64-bits)
/// that is strictly greater than A. Returns zero on overflow.
/// Returns the next power of two (in 64-bits) that is strictly greater than A.
/// Returns zero on overflow.
inline uint64_t NextPowerOf2(uint64_t A) {
A |= (A >> 1);
A |= (A >> 2);
@@ -494,6 +628,14 @@ inline uint64_t PowerOf2Floor(uint64_t A) {
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
}
/// Returns the power of two which is greater than or equal to the given value.
/// Essentially, it is a ceil operation across the domain of powers of two.
inline uint64_t PowerOf2Ceil(uint64_t A) {
if (!A)
return 0;
return NextPowerOf2(A - 1);
}
/// Returns the next integer (mod 2**64) that is greater than or equal to
/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
///
@@ -515,13 +657,40 @@ inline uint64_t PowerOf2Floor(uint64_t A) {
/// alignTo(321, 255, 42) = 552
/// \endcode
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
assert(Align != 0u && "Align can't be 0.");
Skew %= Align;
return (Value + Align - 1 - Skew) / Align * Align + Skew;
}
/// Returns the next integer (mod 2**64) that is greater than or equal to
/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
static_assert(Align != 0u, "Align must be non-zero");
return (Value + Align - 1) / Align * Align;
}
/// Returns the integer ceil(Numerator / Denominator).
inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
return alignTo(Numerator, Denominator) / Denominator;
}
/// \c alignTo for contexts where a constant expression is required.
/// \sa alignTo
///
/// \todo FIXME: remove when \c constexpr becomes really \c constexpr
template <uint64_t Align>
struct AlignTo {
static_assert(Align != 0u, "Align must be non-zero");
template <uint64_t Value>
struct from_value {
static const uint64_t value = (Value + Align - 1) / Align * Align;
};
};
/// Returns the largest uint64_t less than or equal to \p Value and is
/// \p Skew mod \p Align. \p Align must be non-zero
inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
assert(Align != 0u && "Align can't be 0.");
Skew %= Align;
return (Value - Skew) / Align * Align + Skew;
}
@@ -533,42 +702,49 @@ inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
return alignTo(Value, Align) - Value;
}
/// SignExtend32 - Sign extend B-bit number x to 32-bit int.
/// Usage int32_t r = SignExtend32<5>(x);
template <unsigned B> inline int32_t SignExtend32(uint32_t x) {
return int32_t(x << (32 - B)) >> (32 - B);
}
/// \brief Sign extend number in the bottom B bits of X to a 32-bit int.
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires 0 < B <= 32.
inline int32_t SignExtend32(uint32_t X, unsigned B) {
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
static_assert(B > 0, "Bit width can't be 0.");
static_assert(B <= 32, "Bit width out of range.");
return int32_t(X << (32 - B)) >> (32 - B);
}
/// SignExtend64 - Sign extend B-bit number x to 64-bit int.
/// Usage int64_t r = SignExtend64<5>(x);
template <unsigned B> inline int64_t SignExtend64(uint64_t x) {
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires 0 < B < 32.
inline int32_t SignExtend32(uint32_t X, unsigned B) {
assert(B > 0 && "Bit width can't be 0.");
assert(B <= 32 && "Bit width out of range.");
return int32_t(X << (32 - B)) >> (32 - B);
}
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires 0 < B < 64.
template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
static_assert(B > 0, "Bit width can't be 0.");
static_assert(B <= 64, "Bit width out of range.");
return int64_t(x << (64 - B)) >> (64 - B);
}
/// \brief Sign extend number in the bottom B bits of X to a 64-bit int.
/// Requires 0 < B <= 64.
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires 0 < B < 64.
inline int64_t SignExtend64(uint64_t X, unsigned B) {
assert(B > 0 && "Bit width can't be 0.");
assert(B <= 64 && "Bit width out of range.");
return int64_t(X << (64 - B)) >> (64 - B);
}
/// \brief Subtract two unsigned integers, X and Y, of type T and return their
/// absolute value.
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
/// value of the result.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
AbsoluteDifference(T X, T Y) {
return std::max(X, Y) - std::min(X, Y);
}
/// \brief Add two unsigned integers, X and Y, of type T.
/// Clamp the result to the maximum representable value of T on overflow.
/// ResultOverflowed indicates if the result is larger than the maximum
/// representable value of type T.
/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
/// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
@@ -583,10 +759,9 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
return Z;
}
/// \brief Multiply two unsigned integers, X and Y, of type T.
/// Clamp the result to the maximum representable value of T on overflow.
/// ResultOverflowed indicates if the result is larger than the maximum
/// representable value of type T.
/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
/// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
@@ -629,12 +804,10 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
return Z;
}
/// \brief Multiply two unsigned integers, X and Y, and add the unsigned
/// integer, A to the product. Clamp the result to the maximum representable
/// value of T on overflow. ResultOverflowed indicates if the result is larger
/// than the maximum representable value of type T.
/// Note that this is purely a convenience function as there is no distinction
/// where overflow occurred in a 'fused' multiply-add for unsigned numbers.
/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
/// the product. Clamp the result to the maximum representable value of T on
/// overflow. ResultOverflowed indicates if the result is larger than the
/// maximum representable value of type T.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {

View File

@@ -0,0 +1,49 @@
//===- NativeFormatting.h - Low level formatting helpers ---------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_NATIVE_FORMATTING_H
#define WPIUTIL_WPI_NATIVE_FORMATTING_H
#include "wpi/Optional.h"
#include "wpi/raw_ostream.h"
#include <cstdint>
namespace wpi {
enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent };
enum class IntegerStyle {
Integer,
Number,
};
enum class HexPrintStyle { Upper, Lower, PrefixUpper, PrefixLower };
size_t getDefaultPrecision(FloatStyle Style);
bool isPrefixedHexStyle(HexPrintStyle S);
void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
IntegerStyle Style);
void write_integer(raw_ostream &S, int N, size_t MinDigits, IntegerStyle Style);
void write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
IntegerStyle Style);
void write_integer(raw_ostream &S, long N, size_t MinDigits,
IntegerStyle Style);
void write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
IntegerStyle Style);
void write_integer(raw_ostream &S, long long N, size_t MinDigits,
IntegerStyle Style);
void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
Optional<size_t> Width = None);
void write_double(raw_ostream &S, double D, FloatStyle Style,
Optional<size_t> Precision = None);
}
#endif

View File

@@ -13,14 +13,15 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_NONE_H
#define LLVM_ADT_NONE_H
#ifndef WPIUTIL_WPI_NONE_H
#define WPIUTIL_WPI_NONE_H
namespace wpi {
/// \brief A simple null object to allow implicit construction of Optional<T>
/// A simple null object to allow implicit construction of Optional<T>
/// and similar types without having to spell out the specialization's name.
enum class NoneType { None };
const NoneType None = None;
// (constant value 1 in an attempt to workaround MSVC build issue... )
enum class NoneType { None = 1 };
const NoneType None = NoneType::None;
}
#endif

View File

@@ -1,4 +1,4 @@
//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=//
//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -13,129 +13,187 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_OPTIONAL_H
#define LLVM_ADT_OPTIONAL_H
#ifndef WPIUTIL_WPI_OPTIONAL_H
#define WPIUTIL_WPI_OPTIONAL_H
#include "wpi/None.h"
#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <cassert>
#include <new>
#include <utility>
namespace wpi {
template<typename T>
class Optional {
namespace optional_detail {
/// Storage for any type.
template <typename T, bool IsPodLike> struct OptionalStorage {
AlignedCharArrayUnion<T> storage;
bool hasVal;
public:
typedef T value_type;
bool hasVal = false;
Optional(NoneType) : hasVal(false) {}
explicit Optional() : hasVal(false) {}
Optional(const T &y) : hasVal(true) {
new (storage.buffer) T(y);
}
Optional(const Optional &O) : hasVal(O.hasVal) {
OptionalStorage() = default;
OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) {
if (hasVal)
new (storage.buffer) T(*O);
new (storage.buffer) T(*O.getPointer());
}
Optional(T &&y) : hasVal(true) {
OptionalStorage(T &&y) : hasVal(true) {
new (storage.buffer) T(std::forward<T>(y));
}
Optional(Optional<T> &&O) : hasVal(O) {
if (O) {
new (storage.buffer) T(std::move(*O));
O.reset();
OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) {
if (O.hasVal) {
new (storage.buffer) T(std::move(*O.getPointer()));
}
}
Optional &operator=(T &&y) {
OptionalStorage &operator=(T &&y) {
if (hasVal)
**this = std::move(y);
*getPointer() = std::move(y);
else {
new (storage.buffer) T(std::move(y));
hasVal = true;
}
return *this;
}
Optional &operator=(Optional &&O) {
if (!O)
OptionalStorage &operator=(OptionalStorage &&O) {
if (!O.hasVal)
reset();
else {
*this = std::move(*O);
O.reset();
*this = std::move(*O.getPointer());
}
return *this;
}
/// Create a new object by constructing it in place with the given arguments.
template<typename ...ArgTypes>
void emplace(ArgTypes &&...Args) {
reset();
hasVal = true;
new (storage.buffer) T(std::forward<ArgTypes>(Args)...);
}
static inline Optional create(const T* y) {
return y ? Optional(*y) : Optional();
}
// FIXME: these assignments (& the equivalent const T&/const Optional& ctors)
// could be made more efficient by passing by value, possibly unifying them
// with the rvalue versions above - but this could place a different set of
// requirements (notably: the existence of a default ctor) when implemented
// in that way. Careful SFINAE to avoid such pitfalls would be required.
Optional &operator=(const T &y) {
OptionalStorage &operator=(const T &y) {
if (hasVal)
**this = y;
*getPointer() = y;
else {
new (storage.buffer) T(y);
hasVal = true;
}
return *this;
}
Optional &operator=(const Optional &O) {
if (!O)
OptionalStorage &operator=(const OptionalStorage &O) {
if (!O.hasVal)
reset();
else
*this = *O;
*this = *O.getPointer();
return *this;
}
~OptionalStorage() { reset(); }
void reset() {
if (hasVal) {
(**this).~T();
(*getPointer()).~T();
hasVal = false;
}
}
~Optional() {
reset();
T *getPointer() {
assert(hasVal);
return reinterpret_cast<T *>(storage.buffer);
}
const T *getPointer() const {
assert(hasVal);
return reinterpret_cast<const T *>(storage.buffer);
}
};
#if !defined(__GNUC__) || defined(__clang__) // GCC up to GCC7 miscompiles this.
/// Storage for trivially copyable types only.
template <typename T> struct OptionalStorage<T, true> {
AlignedCharArrayUnion<T> storage;
bool hasVal = false;
OptionalStorage() = default;
OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
OptionalStorage &operator=(const T &y) {
*reinterpret_cast<T *>(storage.buffer) = y;
hasVal = true;
return *this;
}
const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); }
T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); }
const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
void reset() { hasVal = false; }
};
#endif
} // namespace optional_detail
explicit operator bool() const { return hasVal; }
bool hasValue() const { return hasVal; }
const T* operator->() const { return getPointer(); }
T* operator->() { return getPointer(); }
const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
template <typename T> class Optional {
optional_detail::OptionalStorage<T, isPodLike<T>::value> Storage;
public:
using value_type = T;
constexpr Optional() {}
constexpr Optional(NoneType) {}
Optional(const T &y) : Storage(y) {}
Optional(const Optional &O) = default;
Optional(T &&y) : Storage(std::forward<T>(y)) {}
Optional(Optional &&O) = default;
Optional &operator=(T &&y) {
Storage = std::move(y);
return *this;
}
Optional &operator=(Optional &&O) = default;
/// Create a new object by constructing it in place with the given arguments.
template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
reset();
Storage.hasVal = true;
new (getPointer()) T(std::forward<ArgTypes>(Args)...);
}
static inline Optional create(const T *y) {
return y ? Optional(*y) : Optional();
}
Optional &operator=(const T &y) {
Storage = y;
return *this;
}
Optional &operator=(const Optional &O) = default;
void reset() { Storage.reset(); }
const T *getPointer() const {
assert(Storage.hasVal);
return reinterpret_cast<const T *>(Storage.storage.buffer);
}
T *getPointer() {
assert(Storage.hasVal);
return reinterpret_cast<T *>(Storage.storage.buffer);
}
const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }
explicit operator bool() const { return Storage.hasVal; }
bool hasValue() const { return Storage.hasVal; }
const T *operator->() const { return getPointer(); }
T *operator->() { return getPointer(); }
const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); }
template <typename U>
LLVM_CONSTEXPR T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
return hasValue() ? getValue() : std::forward<U>(value);
}
#if LLVM_HAS_RVALUE_REFERENCE_THIS
T&& getValue() && { assert(hasVal); return std::move(*getPointer()); }
T&& operator*() && { assert(hasVal); return std::move(*getPointer()); }
T &&getValue() && { return std::move(*getPointer()); }
T &&operator*() && { return std::move(*getPointer()); }
template <typename U>
T getValueOr(U &&value) && {
@@ -144,24 +202,48 @@ public:
#endif
};
template <typename T> struct isPodLike;
template <typename T> struct isPodLike<Optional<T> > {
template <typename T> struct isPodLike<Optional<T>> {
// An Optional<T> is pod-like if T is.
static const bool value = isPodLike<T>::value;
};
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator==(const Optional<T> &X, const Optional<U> &Y);
template <typename T, typename U>
bool operator==(const Optional<T> &X, const Optional<U> &Y) {
if (X && Y)
return *X == *Y;
return X.hasValue() == Y.hasValue();
}
template <typename T, typename U>
bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
return !(X == Y);
}
template <typename T, typename U>
bool operator<(const Optional<T> &X, const Optional<U> &Y) {
if (X && Y)
return *X < *Y;
return X.hasValue() < Y.hasValue();
}
template <typename T, typename U>
bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
return !(Y < X);
}
template <typename T, typename U>
bool operator>(const Optional<T> &X, const Optional<U> &Y) {
return Y < X;
}
template <typename T, typename U>
bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
return !(X < Y);
}
template<typename T>
bool operator==(const Optional<T> &X, NoneType) {
return !X.hasValue();
return !X;
}
template<typename T>
@@ -178,50 +260,86 @@ template<typename T>
bool operator!=(NoneType, const Optional<T> &X) {
return X != None;
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator!=(const Optional<T> &X, const Optional<U> &Y);
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator<(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<(const Optional<T> &X, NoneType) {
return false;
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator<=(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<(NoneType, const Optional<T> &X) {
return X.hasValue();
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator>=(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
return !(None < X);
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator>(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
return !(X < None);
}
template <typename T> bool operator>(const Optional<T> &X, NoneType) {
return None < X;
}
template <typename T> bool operator>(NoneType, const Optional<T> &X) {
return X < None;
}
template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
return None <= X;
}
template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
return X <= None;
}
template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
return X && *X == Y;
}
template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
return Y && X == *Y;
}
template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
return !(X == Y);
}
template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
return !(X == Y);
}
template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
return !X || *X < Y;
}
template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
return Y && X < *Y;
}
template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
return !(Y < X);
}
template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
return !(Y < X);
}
template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
return Y < X;
}
template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
return Y < X;
}
template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
return !(X < Y);
}
template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
return !(X < Y);
}
} // end wpi namespace

View File

@@ -16,20 +16,21 @@
#ifndef WPIUTIL_WPI_PATH_H_
#define WPIUTIL_WPI_PATH_H_
#include <stdint.h>
#include <iterator>
#include "wpi/Twine.h"
#include "wpi/iterator.h"
#include <cstdint>
#include <iterator>
namespace wpi {
namespace sys {
namespace path {
enum class Style { windows, posix, native };
/// @name Lexical Component Iterator
/// @{
/// @brief Path iterator.
/// Path iterator.
///
/// This is an input iterator that iterates over the individual components in
/// \a path. The traversal order is as follows:
@@ -49,67 +50,67 @@ namespace path {
/// C:\foo\bar => C:,/,foo,bar
/// @endcode
class const_iterator
: public std::iterator<std::input_iterator_tag, const StringRef> {
: public iterator_facade_base<const_iterator, std::input_iterator_tag,
const StringRef> {
StringRef Path; ///< The entire path.
StringRef Component; ///< The current component. Not necessarily in Path.
size_t Position; ///< The iterators current position within Path.
size_t Position; ///< The iterators current position within Path.
Style S; ///< The path style to use.
// An end iterator has Position = Path.size() + 1.
friend const_iterator begin(StringRef path);
friend const_iterator begin(StringRef path, Style style);
friend const_iterator end(StringRef path);
public:
reference operator*() const { return Component; }
pointer operator->() const { return &Component; }
const_iterator& operator++(); // preincrement
const_iterator &operator++(); // preincrement
bool operator==(const const_iterator &RHS) const;
bool operator!=(const const_iterator &RHS) const { return !(*this == RHS); }
/// @brief Difference in bytes between this and RHS.
/// Difference in bytes between this and RHS.
ptrdiff_t operator-(const const_iterator &RHS) const;
};
/// @brief Reverse path iterator.
/// Reverse path iterator.
///
/// This is an input iterator that iterates over the individual components in
/// \a path in reverse order. The traversal order is exactly reversed from that
/// of \a const_iterator
class reverse_iterator
: public std::iterator<std::input_iterator_tag, const StringRef> {
: public iterator_facade_base<reverse_iterator, std::input_iterator_tag,
const StringRef> {
StringRef Path; ///< The entire path.
StringRef Component; ///< The current component. Not necessarily in Path.
size_t Position; ///< The iterators current position within Path.
size_t Position; ///< The iterators current position within Path.
Style S; ///< The path style to use.
friend reverse_iterator rbegin(StringRef path);
friend reverse_iterator rbegin(StringRef path, Style style);
friend reverse_iterator rend(StringRef path);
public:
reference operator*() const { return Component; }
pointer operator->() const { return &Component; }
reverse_iterator& operator++(); // preincrement
reverse_iterator &operator++(); // preincrement
bool operator==(const reverse_iterator &RHS) const;
bool operator!=(const reverse_iterator &RHS) const { return !(*this == RHS); }
/// @brief Difference in bytes between this and RHS.
/// Difference in bytes between this and RHS.
ptrdiff_t operator-(const reverse_iterator &RHS) const;
};
/// @brief Get begin iterator over \a path.
/// Get begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first component of \a path.
const_iterator begin(StringRef path);
const_iterator begin(StringRef path, Style style = Style::native);
/// @brief Get end iterator over \a path.
/// Get end iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized to the end of \a path.
const_iterator end(StringRef path);
/// @brief Get reverse begin iterator over \a path.
/// Get reverse begin iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized with the first reverse component of \a path.
reverse_iterator rbegin(StringRef path);
reverse_iterator rbegin(StringRef path, Style style = Style::native);
/// @brief Get reverse end iterator over \a path.
/// Get reverse end iterator over \a path.
/// @param path Input path.
/// @returns Iterator initialized to the reverse end of \a path.
reverse_iterator rend(StringRef path);
@@ -118,7 +119,7 @@ reverse_iterator rend(StringRef path);
/// @name Lexical Modifiers
/// @{
/// @brief Remove the last component from \a path unless it is the root dir.
/// Remove the last component from \a path unless it is the root dir.
///
/// @code
/// directory/filename.cpp => directory/
@@ -128,9 +129,9 @@ reverse_iterator rend(StringRef path);
/// @endcode
///
/// @param path A path that is modified to not have a file component.
void remove_filename(SmallVectorImpl<char> &path);
void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
/// @brief Replace the file extension of \a path with \a extension.
/// Replace the file extension of \a path with \a extension.
///
/// @code
/// ./filename.cpp => ./filename.extension
@@ -142,9 +143,10 @@ void remove_filename(SmallVectorImpl<char> &path);
/// @param extension The extension to be added. It may be empty. It may also
/// optionally start with a '.', if it does not, one will be
/// prepended.
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension);
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
Style style = Style::native);
/// @brief Replace matching path prefix with another path.
/// Replace matching path prefix with another path.
///
/// @code
/// /foo, /old, /new => /foo
@@ -158,10 +160,10 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension);
/// @param OldPrefix The path prefix to strip from \a Path.
/// @param NewPrefix The path prefix to replace \a NewPrefix with.
void replace_path_prefix(SmallVectorImpl<char> &Path,
const StringRef &OldPrefix,
const StringRef &NewPrefix);
const StringRef &OldPrefix, const StringRef &NewPrefix,
Style style = Style::native);
/// @brief Append to path.
/// Append to path.
///
/// @code
/// /foo + bar/f => /foo/bar/f
@@ -176,7 +178,10 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
const Twine &c = "",
const Twine &d = "");
/// @brief Append to path.
void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
const Twine &b = "", const Twine &c = "", const Twine &d = "");
/// Append to path.
///
/// @code
/// /foo + [bar,f] => /foo/bar/f
@@ -187,8 +192,8 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
/// @param path Set to \a path + [\a begin, \a end).
/// @param begin Start of components to append.
/// @param end One past the end of components to append.
void append(SmallVectorImpl<char> &path,
const_iterator begin, const_iterator end);
void append(SmallVectorImpl<char> &path, const_iterator begin,
const_iterator end, Style style = Style::native);
/// @}
/// @name Transforms (or some other better name)
@@ -200,20 +205,29 @@ void append(SmallVectorImpl<char> &path,
///
/// @param path A path that is transformed to native format.
/// @param result Holds the result of the transformation.
void native(const Twine &path, SmallVectorImpl<char> &result);
void native(const Twine &path, SmallVectorImpl<char> &result,
Style style = Style::native);
/// Convert path to the native form in place. This is used to give paths to
/// users and operating system calls in the platform's normal way. For example,
/// on Windows all '/' are converted to '\'.
///
/// @param path A path that is transformed to native format.
void native(SmallVectorImpl<char> &path);
void native(SmallVectorImpl<char> &path, Style style = Style::native);
/// Replaces backslashes with slashes if Windows.
///
/// @param path processed path
/// @result The result of replacing backslashes with forward slashes if Windows.
/// On Unix, this function is a no-op because backslashes are valid path
/// chracters.
std::string convert_to_slash(StringRef path, Style style = Style::native);
/// @}
/// @name Lexical Observers
/// @{
/// @brief Get root name.
/// Get root name.
///
/// @code
/// //net/hello => //net
@@ -223,9 +237,9 @@ void native(SmallVectorImpl<char> &path);
///
/// @param path Input path.
/// @result The root name of \a path if it has one, otherwise "".
StringRef root_name(StringRef path);
StringRef root_name(StringRef path, Style style = Style::native);
/// @brief Get root directory.
/// Get root directory.
///
/// @code
/// /goo/hello => /
@@ -236,17 +250,17 @@ StringRef root_name(StringRef path);
/// @param path Input path.
/// @result The root directory of \a path if it has one, otherwise
/// "".
StringRef root_directory(StringRef path);
StringRef root_directory(StringRef path, Style style = Style::native);
/// @brief Get root path.
/// Get root path.
///
/// Equivalent to root_name + root_directory.
///
/// @param path Input path.
/// @result The root path of \a path if it has one, otherwise "".
StringRef root_path(StringRef path);
StringRef root_path(StringRef path, Style style = Style::native);
/// @brief Get relative path.
/// Get relative path.
///
/// @code
/// C:\hello\world => hello\world
@@ -256,9 +270,9 @@ StringRef root_path(StringRef path);
///
/// @param path Input path.
/// @result The path starting after root_path if one exists, otherwise "".
StringRef relative_path(StringRef path);
StringRef relative_path(StringRef path, Style style = Style::native);
/// @brief Get parent path.
/// Get parent path.
///
/// @code
/// / => <empty>
@@ -268,9 +282,9 @@ StringRef relative_path(StringRef path);
///
/// @param path Input path.
/// @result The parent path of \a path if one exists, otherwise "".
StringRef parent_path(StringRef path);
StringRef parent_path(StringRef path, Style style = Style::native);
/// @brief Get filename.
/// Get filename.
///
/// @code
/// /foo.txt => foo.txt
@@ -282,9 +296,9 @@ StringRef parent_path(StringRef path);
/// @param path Input path.
/// @result The filename part of \a path. This is defined as the last component
/// of \a path.
StringRef filename(StringRef path);
StringRef filename(StringRef path, Style style = Style::native);
/// @brief Get stem.
/// Get stem.
///
/// If filename contains a dot but not solely one or two dots, result is the
/// substring of filename ending at (but not including) the last dot. Otherwise
@@ -300,9 +314,9 @@ StringRef filename(StringRef path);
///
/// @param path Input path.
/// @result The stem of \a path.
StringRef stem(StringRef path);
StringRef stem(StringRef path, Style style = Style::native);
/// @brief Get extension.
/// Get extension.
///
/// If filename contains a dot but not solely one or two dots, result is the
/// substring of filename starting at (and including) the last dot, and ending
@@ -316,20 +330,20 @@ StringRef stem(StringRef path);
///
/// @param path Input path.
/// @result The extension of \a path.
StringRef extension(StringRef path);
StringRef extension(StringRef path, Style style = Style::native);
/// @brief Check whether the given char is a path separator on the host OS.
/// Check whether the given char is a path separator on the host OS.
///
/// @param value a character
/// @result true if \a value is a path separator character on the host OS
bool is_separator(char value);
bool is_separator(char value, Style style = Style::native);
/// @brief Return the preferred separator for this platform.
/// Return the preferred separator for this platform.
///
/// @result StringRef of the preferred separator, null-terminated.
StringRef get_separator();
StringRef get_separator(Style style = Style::native);
/// @brief Get the typical temporary directory for the system, e.g.,
/// Get the typical temporary directory for the system, e.g.,
/// "/var/tmp" or "C:/TEMP"
///
/// @param erasedOnReboot Whether to favor a path that is erased on reboot
@@ -340,13 +354,13 @@ StringRef get_separator();
/// @param result Holds the resulting path name.
void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result);
/// @brief Get the user's home directory.
/// Get the user's home directory.
///
/// @param result Holds the resulting path name.
/// @result True if a home directory is set, false otherwise.
bool home_directory(SmallVectorImpl<char> &result);
/// @brief Get the user's cache directory.
/// Get the user's cache directory.
///
/// Expect the resulting path to be a directory shared with other
/// applications/services used by the user. Params \p Path1 to \p Path3 can be
@@ -362,97 +376,99 @@ bool home_directory(SmallVectorImpl<char> &result);
bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1,
const Twine &Path2 = "", const Twine &Path3 = "");
/// @brief Has root name?
/// Has root name?
///
/// root_name != ""
///
/// @param path Input path.
/// @result True if the path has a root name, false otherwise.
bool has_root_name(const Twine &path);
bool has_root_name(const Twine &path, Style style = Style::native);
/// @brief Has root directory?
/// Has root directory?
///
/// root_directory != ""
///
/// @param path Input path.
/// @result True if the path has a root directory, false otherwise.
bool has_root_directory(const Twine &path);
bool has_root_directory(const Twine &path, Style style = Style::native);
/// @brief Has root path?
/// Has root path?
///
/// root_path != ""
///
/// @param path Input path.
/// @result True if the path has a root path, false otherwise.
bool has_root_path(const Twine &path);
bool has_root_path(const Twine &path, Style style = Style::native);
/// @brief Has relative path?
/// Has relative path?
///
/// relative_path != ""
///
/// @param path Input path.
/// @result True if the path has a relative path, false otherwise.
bool has_relative_path(const Twine &path);
bool has_relative_path(const Twine &path, Style style = Style::native);
/// @brief Has parent path?
/// Has parent path?
///
/// parent_path != ""
///
/// @param path Input path.
/// @result True if the path has a parent path, false otherwise.
bool has_parent_path(const Twine &path);
bool has_parent_path(const Twine &path, Style style = Style::native);
/// @brief Has filename?
/// Has filename?
///
/// filename != ""
///
/// @param path Input path.
/// @result True if the path has a filename, false otherwise.
bool has_filename(const Twine &path);
bool has_filename(const Twine &path, Style style = Style::native);
/// @brief Has stem?
/// Has stem?
///
/// stem != ""
///
/// @param path Input path.
/// @result True if the path has a stem, false otherwise.
bool has_stem(const Twine &path);
bool has_stem(const Twine &path, Style style = Style::native);
/// @brief Has extension?
/// Has extension?
///
/// extension != ""
///
/// @param path Input path.
/// @result True if the path has a extension, false otherwise.
bool has_extension(const Twine &path);
bool has_extension(const Twine &path, Style style = Style::native);
/// @brief Is path absolute?
/// Is path absolute?
///
/// @param path Input path.
/// @result True if the path is absolute, false if it is not.
bool is_absolute(const Twine &path);
bool is_absolute(const Twine &path, Style style = Style::native);
/// @brief Is path relative?
/// Is path relative?
///
/// @param path Input path.
/// @result True if the path is relative, false if it is not.
bool is_relative(const Twine &path);
bool is_relative(const Twine &path, Style style = Style::native);
/// @brief Remove redundant leading "./" pieces and consecutive separators.
/// Remove redundant leading "./" pieces and consecutive separators.
///
/// @param path Input path.
/// @result The cleaned-up \a path.
StringRef remove_leading_dotslash(StringRef path);
StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
/// @brief In-place remove any './' and optionally '../' components from a path.
/// In-place remove any './' and optionally '../' components from a path.
///
/// @param path processed path
/// @param remove_dot_dot specify if '../' should be removed
/// @param remove_dot_dot specify if '../' (except for leading "../") should be
/// removed
/// @result True if path was changed
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false);
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false,
Style style = Style::native);
} // namespace path
} // namespace sys
} // namespace wpi
} // end namespace path
} // end namespace sys
} // end namespace wpi
#endif // WPIUTIL_WPI_PATH_H_
#endif

View File

@@ -12,21 +12,18 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
#ifndef WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
#define WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
#include "wpi/AlignOf.h"
#include <cstdint>
#include <cstdlib>
#include <type_traits>
namespace wpi {
/// A traits type that is used to handle pointer types and things that are just
/// wrappers for pointers as a uniform entity.
template <typename T> class PointerLikeTypeTraits {
// getAsVoidPointer
// getFromVoidPointer
// getNumLowBitsAvailable
};
template <typename T> struct PointerLikeTypeTraits;
namespace detail {
/// A tiny meta function to compute the log2 of a compile time constant.
@@ -34,21 +31,36 @@ template <size_t N>
struct ConstantLog2
: std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
}
// Provide a trait to check if T is pointer-like.
template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
static const bool value = false;
};
// sizeof(T) is valid only for a complete T.
template <typename T> struct HasPointerLikeTypeTraits<
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
static const bool value = true;
};
template <typename T> struct IsPointerLike {
static const bool value = HasPointerLikeTypeTraits<T>::value;
};
template <typename T> struct IsPointerLike<T *> {
static const bool value = true;
};
} // namespace detail
// Provide PointerLikeTypeTraits for non-cvr pointers.
template <typename T> class PointerLikeTypeTraits<T *> {
public:
template <typename T> struct PointerLikeTypeTraits<T *> {
static inline void *getAsVoidPointer(T *P) { return P; }
static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
enum {
NumLowBitsAvailable = detail::ConstantLog2<AlignOf<T>::Alignment>::value
};
enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value };
};
template <> class PointerLikeTypeTraits<void *> {
public:
template <> struct PointerLikeTypeTraits<void *> {
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
@@ -62,11 +74,23 @@ public:
enum { NumLowBitsAvailable = 2 };
};
// Provide PointerLikeTypeTraits for const things.
template <typename T> struct PointerLikeTypeTraits<const T> {
typedef PointerLikeTypeTraits<T> NonConst;
static inline const void *getAsVoidPointer(const T P) {
return NonConst::getAsVoidPointer(P);
}
static inline const T getFromVoidPointer(const void *P) {
return NonConst::getFromVoidPointer(const_cast<void *>(P));
}
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
};
// Provide PointerLikeTypeTraits for const pointers.
template <typename T> class PointerLikeTypeTraits<const T *> {
template <typename T> struct PointerLikeTypeTraits<const T *> {
typedef PointerLikeTypeTraits<T *> NonConst;
public:
static inline const void *getAsVoidPointer(const T *P) {
return NonConst::getAsVoidPointer(const_cast<T *>(P));
}
@@ -77,8 +101,7 @@ public:
};
// Provide PointerLikeTypeTraits for uintptr_t.
template <> class PointerLikeTypeTraits<uintptr_t> {
public:
template <> struct PointerLikeTypeTraits<uintptr_t> {
static inline void *getAsVoidPointer(uintptr_t P) {
return reinterpret_cast<void *>(P);
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,23 +12,23 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SMALLPTRSET_H
#define LLVM_ADT_SMALLPTRSET_H
#ifndef WPIUTIL_WPI_SMALLPTRSET_H
#define WPIUTIL_WPI_SMALLPTRSET_H
#include "wpi/Compiler.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/type_traits.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <utility>
namespace wpi {
class SmallPtrSetIteratorImpl;
/// SmallPtrSetImplBase - This is the common code shared among all the
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
/// for small and one for large sets.
@@ -71,20 +71,25 @@ protected:
const SmallPtrSetImplBase &that);
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
SmallPtrSetImplBase &&that);
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
: SmallArray(SmallStorage), CurArray(SmallStorage),
CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
"Initial size must be a power of two!");
}
~SmallPtrSetImplBase() {
if (!isSmall())
free(CurArray);
}
public:
typedef unsigned size_type;
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
using size_type = unsigned;
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
LLVM_NODISCARD bool empty() const { return size() == 0; }
size_type size() const { return NumNonEmpty - NumTombstones; }
void clear() {
@@ -103,6 +108,7 @@ public:
protected:
static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
static void *getEmptyMarker() {
// Note that -1 is chosen to make clear() efficiently implementable with
// memset and because it's not a valid pointer value.
@@ -150,20 +156,36 @@ protected:
/// return true, otherwise return false. This is hidden from the client so
/// that the derived class can check that the right type of pointer is passed
/// in.
bool erase_imp(const void * Ptr);
bool erase_imp(const void * Ptr) {
const void *const *P = find_imp(Ptr);
if (P == EndPointer())
return false;
bool count_imp(const void * Ptr) const {
const void **Loc = const_cast<const void **>(P);
assert(*Loc == Ptr && "broken find!");
*Loc = getTombstoneMarker();
NumTombstones++;
return true;
}
/// Returns the raw pointer needed to construct an iterator. If element not
/// found, this will be EndPointer. Otherwise, it will be a pointer to the
/// slot which stores Ptr;
const void *const * find_imp(const void * Ptr) const {
if (isSmall()) {
// Linear search for the item.
for (const void *const *APtr = SmallArray,
*const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
if (*APtr == Ptr)
return true;
return false;
return APtr;
return EndPointer();
}
// Big set case.
return *FindBucketFor(Ptr) == Ptr;
auto *Bucket = FindBucketFor(Ptr);
if (*Bucket == Ptr)
return Bucket;
return EndPointer();
}
private:
@@ -177,8 +199,6 @@ private:
/// Grow - Allocate a larger backing store for the buckets and move it over.
void Grow(unsigned NewSize);
void operator=(const SmallPtrSetImplBase &RHS) = delete;
protected:
/// swap - Swaps the elements of two sets.
/// Note: This method assumes that both sets have the same small size.
@@ -225,22 +245,30 @@ protected:
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
++Bucket;
}
void RetreatIfNotValid() {
assert(Bucket >= End);
while (Bucket != End &&
(Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
--Bucket;
}
}
};
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
template<typename PtrTy>
template <typename PtrTy>
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
typedef PointerLikeTypeTraits<PtrTy> PtrTraits;
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
public:
typedef PtrTy value_type;
typedef PtrTy reference;
typedef PtrTy pointer;
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
using value_type = PtrTy;
using reference = PtrTy;
using pointer = PtrTy;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
: SmallPtrSetIteratorImpl(BP, E) {}
: SmallPtrSetIteratorImpl(BP, E) {}
// Most methods provided by baseclass.
@@ -256,7 +284,9 @@ public:
}
SmallPtrSetIterator operator++(int) { // Postincrement
SmallPtrSetIterator tmp = *this; ++*this; return tmp;
SmallPtrSetIterator tmp = *this;
++*this;
return tmp;
}
};
@@ -285,16 +315,16 @@ struct RoundUpToPowerOfTwo {
enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
};
/// \brief A templated base class for \c SmallPtrSet which provides the
/// A templated base class for \c SmallPtrSet which provides the
/// typesafe interface that is common across all small sizes.
///
/// This is particularly useful for passing around between interface boundaries
/// to avoid encoding a particular small size in the interface boundary.
template <typename PtrType>
class SmallPtrSetImpl : public SmallPtrSetImplBase {
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
using PtrTraits = PointerLikeTypeTraits<PtrType>;
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
protected:
// Constructors that forward to the base.
@@ -307,8 +337,12 @@ protected:
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
public:
typedef SmallPtrSetIterator<PtrType> iterator;
typedef SmallPtrSetIterator<PtrType> const_iterator;
using iterator = SmallPtrSetIterator<PtrType>;
using const_iterator = SmallPtrSetIterator<PtrType>;
using key_type = ConstPtrType;
using value_type = PtrType;
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
/// Inserts Ptr if and only if there is no element in the container equal to
/// Ptr. The bool component of the returned pair is true if and only if the
@@ -316,7 +350,7 @@ public:
/// the element equal to Ptr.
std::pair<iterator, bool> insert(PtrType Ptr) {
auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
return std::make_pair(iterator(p.first, EndPointer()), p.second);
return std::make_pair(makeIterator(p.first), p.second);
}
/// erase - If the set contains the specified pointer, remove it and return
@@ -326,8 +360,9 @@ public:
}
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
size_type count(PtrType Ptr) const {
return count_imp(PtrTraits::getAsVoidPointer(Ptr)) ? 1 : 0;
size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; }
iterator find(ConstPtrType Ptr) const {
return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
}
template <typename IterT>
@@ -336,12 +371,19 @@ public:
insert(*I);
}
inline iterator begin() const {
return iterator(CurArray, EndPointer());
void insert(std::initializer_list<PtrType> IL) {
insert(IL.begin(), IL.end());
}
inline iterator end() const {
const void *const *End = EndPointer();
return iterator(End, End);
iterator begin() const {
return makeIterator(CurArray);
}
iterator end() const { return makeIterator(EndPointer()); }
private:
/// Create an iterator that dereferences to same place as the given pointer.
iterator makeIterator(const void *const *P) const {
return iterator(P, EndPointer(), *this);
}
};
@@ -356,7 +398,7 @@ class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
// DenseSet<> instead if you expect many elements in the set.
static_assert(SmallSize <= 32, "SmallSize should be small");
typedef SmallPtrSetImpl<PtrType> BaseT;
using BaseT = SmallPtrSetImpl<PtrType>;
// Make sure that SmallSize is a power of two, round up if not.
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
@@ -374,6 +416,11 @@ public:
this->insert(I, E);
}
SmallPtrSet(std::initializer_list<PtrType> IL)
: BaseT(SmallStorage, SmallSizePowTwo) {
this->insert(IL.begin(), IL.end());
}
SmallPtrSet<PtrType, SmallSize> &
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
if (&RHS != this)
@@ -381,26 +428,36 @@ public:
return *this;
}
SmallPtrSet<PtrType, SmallSize>&
SmallPtrSet<PtrType, SmallSize> &
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
if (&RHS != this)
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
return *this;
}
SmallPtrSet<PtrType, SmallSize> &
operator=(std::initializer_list<PtrType> IL) {
this->clear();
this->insert(IL.begin(), IL.end());
return *this;
}
/// swap - Swaps the elements of two sets.
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
SmallPtrSetImplBase::swap(RHS);
}
};
}
} // end namespace wpi
namespace std {
/// Implement std::swap in terms of SmallPtrSet swap.
template<class T, unsigned N>
inline void swap(wpi::SmallPtrSet<T, N> &LHS, wpi::SmallPtrSet<T, N> &RHS) {
LHS.swap(RHS);
}
}
#endif
} // end namespace std
#endif // LLVM_ADT_SMALLPTRSET_H

View File

@@ -11,13 +11,17 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SMALLSET_H
#define LLVM_ADT_SMALLSET_H
#ifndef WPIUTIL_WPI_SMALLSET_H
#define WPIUTIL_WPI_SMALLSET_H
#include "wpi/None.h"
#include "wpi/SmallPtrSet.h"
#include "wpi/SmallVector.h"
#include "wpi/Compiler.h"
#include <cstddef>
#include <functional>
#include <set>
#include <utility>
namespace wpi {
@@ -28,15 +32,16 @@ namespace wpi {
///
/// Note that this set does not provide a way to iterate over members in the
/// set.
template <typename T, unsigned N, typename C = std::less<T> >
template <typename T, unsigned N, typename C = std::less<T>>
class SmallSet {
/// Use a SmallVector to hold the elements here (even though it will never
/// reach its 'large' stage) to avoid calling the default ctors of elements
/// we will never use.
SmallVector<T, N> Vector;
std::set<T, C> Set;
typedef typename SmallVector<T, N>::const_iterator VIterator;
typedef typename SmallVector<T, N>::iterator mutable_iterator;
using VIterator = typename SmallVector<T, N>::const_iterator;
using mutable_iterator = typename SmallVector<T, N>::iterator;
// In small mode SmallPtrSet uses linear search for the elements, so it is
// not a good idea to choose this value too high. You may consider using a
@@ -44,10 +49,11 @@ class SmallSet {
static_assert(N <= 32, "N should be small");
public:
typedef size_t size_type;
SmallSet() {}
using size_type = size_t;
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
SmallSet() = default;
LLVM_NODISCARD bool empty() const {
return Vector.empty() && Set.empty();
}
@@ -133,4 +139,4 @@ class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
} // end namespace wpi
#endif
#endif // LLVM_ADT_SMALLSET_H

View File

@@ -11,11 +11,12 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SMALLSTRING_H
#define LLVM_ADT_SMALLSTRING_H
#ifndef WPIUTIL_WPI_SMALLSTRING_H
#define WPIUTIL_WPI_SMALLSTRING_H
#include "wpi/SmallVector.h"
#include "wpi/StringRef.h"
#include <cstddef>
namespace wpi {
@@ -25,7 +26,7 @@ template<unsigned InternalLen>
class SmallString : public SmallVector<char, InternalLen> {
public:
/// Default ctor - Initialize to empty.
SmallString() {}
SmallString() = default;
/// Initialize from a StringRef.
SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
@@ -79,7 +80,6 @@ public:
SmallVectorImpl<char>::append(NumInputs, Elt);
}
/// Append from a StringRef.
void append(StringRef RHS) {
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
@@ -292,6 +292,6 @@ public:
}
};
}
} // end namespace wpi
#endif
#endif // LLVM_ADT_SMALLSTRING_H

View File

@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SMALLVECTOR_H
#define LLVM_ADT_SMALLVECTOR_H
#ifndef WPIUTIL_WPI_SMALLVECTOR_H
#define WPIUTIL_WPI_SMALLVECTOR_H
// This file uses std::memcpy() to copy std::pair<unsigned int, unsigned int>.
// That type is POD, but the standard doesn't guarantee that. GCC doesn't treat
@@ -26,6 +26,7 @@
#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
#include "wpi/memory.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <cassert>
@@ -35,6 +36,9 @@
#include <initializer_list>
#include <iterator>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
namespace wpi {
@@ -62,11 +66,9 @@ public:
return size_t((char*)CapacityX - (char*)BeginX);
}
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return BeginX == EndX; }
LLVM_NODISCARD bool empty() const { return BeginX == EndX; }
};
template <typename T, unsigned N> struct SmallVectorStorage;
/// This is the part of SmallVectorTemplateBase which does not depend on whether
/// the type T is a POD. The extra dummy template argument is used by ArrayRef
/// to avoid unnecessarily requiring T to be complete.
@@ -78,7 +80,7 @@ private:
// Allocate raw space for N elements of type T. If T has a ctor or dtor, we
// don't want it to be automatically run, so we need to represent the space as
// something else. Use an array of char of sufficient alignment.
typedef wpi::AlignedCharArrayUnion<T> U;
using U = AlignedCharArrayUnion<T>;
U FirstEl;
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.
@@ -101,37 +103,44 @@ protected:
}
void setEnd(T *P) { this->EndX = P; }
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T *iterator;
typedef const T *const_iterator;
using size_type = size_t;
using difference_type = ptrdiff_t;
using value_type = T;
using iterator = T *;
using const_iterator = const T *;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = std::reverse_iterator<iterator>;
typedef T &reference;
typedef const T &const_reference;
typedef T *pointer;
typedef const T *const_pointer;
using reference = T &;
using const_reference = const T &;
using pointer = T *;
using const_pointer = const T *;
// forward iterator creation methods.
LLVM_ATTRIBUTE_ALWAYS_INLINE
iterator begin() { return (iterator)this->BeginX; }
LLVM_ATTRIBUTE_ALWAYS_INLINE
const_iterator begin() const { return (const_iterator)this->BeginX; }
LLVM_ATTRIBUTE_ALWAYS_INLINE
iterator end() { return (iterator)this->EndX; }
LLVM_ATTRIBUTE_ALWAYS_INLINE
const_iterator end() const { return (const_iterator)this->EndX; }
protected:
iterator capacity_ptr() { return (iterator)this->CapacityX; }
const_iterator capacity_ptr() const { return (const_iterator)this->CapacityX;}
public:
public:
// reverse iterator creation methods.
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_type size() const { return end()-begin(); }
size_type max_size() const { return size_type(-1) / sizeof(T); }
@@ -143,10 +152,12 @@ public:
/// Return a pointer to the vector's buffer, even if empty().
const_pointer data() const { return const_pointer(begin()); }
LLVM_ATTRIBUTE_ALWAYS_INLINE
reference operator[](size_type idx) {
assert(idx < size());
return begin()[idx];
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
const_reference operator[](size_type idx) const {
assert(idx < size());
return begin()[idx];
@@ -235,7 +246,7 @@ void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2));
if (NewCapacity < MinSize)
NewCapacity = MinSize;
T *NewElts = static_cast<T*>(malloc(NewCapacity*sizeof(T)));
T *NewElts = static_cast<T*>(CheckedMalloc(NewCapacity*sizeof(T)));
// Move the elements over.
this->uninitialized_move(this->begin(), this->end(), NewElts);
@@ -299,6 +310,7 @@ protected:
void grow(size_t MinSize = 0) {
this->grow_pod(MinSize*sizeof(T), sizeof(T));
}
public:
void push_back(const T &Elt) {
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
@@ -312,18 +324,16 @@ public:
}
};
/// This class consists of common code factored out of the SmallVector class to
/// reduce code duplication based on the SmallVector 'N' template parameter.
template <typename T>
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
typedef SmallVectorTemplateBase<T, isPodLike<T>::value > SuperClass;
using SuperClass = SmallVectorTemplateBase<T, isPodLike<T>::value>;
SmallVectorImpl(const SmallVectorImpl&) = delete;
public:
typedef typename SuperClass::iterator iterator;
typedef typename SuperClass::const_iterator const_iterator;
typedef typename SuperClass::size_type size_type;
using iterator = typename SuperClass::iterator;
using const_iterator = typename SuperClass::const_iterator;
using size_type = typename SuperClass::size_type;
protected:
// Default ctor - Initialize to empty.
@@ -332,16 +342,15 @@ protected:
}
public:
~SmallVectorImpl() {
// Destroy the constructed elements in the vector.
this->destroy_range(this->begin(), this->end());
SmallVectorImpl(const SmallVectorImpl &) = delete;
~SmallVectorImpl() {
// Subclass has already destructed this vector's elements.
// If this wasn't grown from the inline copy, deallocate the old space.
if (!this->isSmall())
free(this->begin());
}
void clear() {
this->destroy_range(this->begin(), this->end());
this->EndX = this->BeginX;
@@ -377,7 +386,7 @@ public:
this->grow(N);
}
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
LLVM_NODISCARD T pop_back_val() {
T Result = ::std::move(this->back());
this->pop_back();
return Result;
@@ -386,7 +395,10 @@ public:
void swap(SmallVectorImpl &RHS);
/// Add the specified range to the end of the SmallVector.
template<typename in_iter>
template <typename in_iter,
typename = typename std::enable_if<std::is_convertible<
typename std::iterator_traits<in_iter>::iterator_category,
std::input_iterator_tag>::value>::type>
void append(in_iter in_start, in_iter in_end) {
size_type NumInputs = std::distance(in_start, in_end);
// Grow allocated space if needed.
@@ -413,6 +425,9 @@ public:
append(IL.begin(), IL.end());
}
// FIXME: Consider assigning over existing elements, rather than clearing &
// re-initializing them - for all assign(...) variants.
void assign(size_type NumElts, const T &Elt) {
clear();
if (this->capacity() < NumElts)
@@ -421,6 +436,15 @@ public:
std::uninitialized_fill(this->begin(), this->end(), Elt);
}
template <typename in_iter,
typename = typename std::enable_if<std::is_convertible<
typename std::iterator_traits<in_iter>::iterator_category,
std::input_iterator_tag>::value>::type>
void assign(in_iter in_start, in_iter in_end) {
clear();
append(in_start, in_end);
}
void assign(std::initializer_list<T> IL) {
clear();
append(IL);
@@ -569,7 +593,10 @@ public:
return I;
}
template<typename ItTy>
template <typename ItTy,
typename = typename std::enable_if<std::is_convertible<
typename std::iterator_traits<ItTy>::iterator_category,
std::input_iterator_tag>::value>::type>
iterator insert(iterator I, ItTy From, ItTy To) {
// Convert iterator to elt# to avoid invalidating iterator when we reserve()
size_t InsertElt = I - this->begin();
@@ -669,7 +696,6 @@ public:
}
};
template <typename T>
void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
if (this == &RHS) return;
@@ -842,8 +868,13 @@ template <typename T, unsigned N>
class SmallVector : public SmallVectorImpl<T> {
/// Inline space for elements which aren't stored in the base class.
SmallVectorStorage<T, N> Storage;
public:
SmallVector() : SmallVectorImpl<T>(N) {
SmallVector() : SmallVectorImpl<T>(N) {}
~SmallVector() {
// Destroy the constructed elements in the vector.
this->destroy_range(this->begin(), this->end());
}
explicit SmallVector(size_t Size, const T &Value = T())
@@ -851,13 +882,16 @@ public:
this->assign(Size, Value);
}
template<typename ItTy>
template <typename ItTy,
typename = typename std::enable_if<std::is_convertible<
typename std::iterator_traits<ItTy>::iterator_category,
std::input_iterator_tag>::value>::type>
SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
this->append(S, E);
}
template <typename RangeTy>
explicit SmallVector(const wpi::iterator_range<RangeTy> R)
explicit SmallVector(const iterator_range<RangeTy> &R)
: SmallVectorImpl<T>(N) {
this->append(R.begin(), R.end());
}
@@ -881,16 +915,16 @@ public:
SmallVectorImpl<T>::operator=(::std::move(RHS));
}
const SmallVector &operator=(SmallVector &&RHS) {
SmallVectorImpl<T>::operator=(::std::move(RHS));
return *this;
}
SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
if (!RHS.empty())
SmallVectorImpl<T>::operator=(::std::move(RHS));
}
const SmallVector &operator=(SmallVector &&RHS) {
SmallVectorImpl<T>::operator=(::std::move(RHS));
return *this;
}
const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
SmallVectorImpl<T>::operator=(::std::move(RHS));
return *this;
@@ -902,14 +936,15 @@ public:
}
};
template<typename T, unsigned N>
static inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
template <typename T, unsigned N>
inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
return X.capacity_in_bytes();
}
} // End wpi namespace
} // end namespace wpi
namespace std {
/// Implement std::swap in terms of SmallVector swap.
template<typename T>
inline void
@@ -923,6 +958,7 @@ namespace std {
swap(wpi::SmallVector<T, N> &LHS, wpi::SmallVector<T, N> &RHS) {
LHS.swap(RHS);
}
}
#endif
} // end namespace std
#endif // LLVM_ADT_SMALLVECTOR_H

View File

@@ -1,4 +1,4 @@
//===-- llvm/ADT/StringExtras.h - Useful string functions -------*- C++ -*-===//
//===- llvm/ADT/StringExtras.h - Useful string functions --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,40 +11,88 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_STRINGEXTRAS_H
#define LLVM_ADT_STRINGEXTRAS_H
#ifndef WPIUTIL_WPI_STRINGEXTRAS_H
#define WPIUTIL_WPI_STRINGEXTRAS_H
#include "wpi/ArrayRef.h"
#include "wpi/SmallString.h"
#include "wpi/StringRef.h"
#include "wpi/Twine.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <string>
#include <utility>
namespace wpi {
template<typename T> class SmallVectorImpl;
class raw_ostream;
/// hexdigit - Return the hexadecimal character for the
/// given number \p X (which should be less than 16).
static inline char hexdigit(unsigned X, bool LowerCase = false) {
inline char hexdigit(unsigned X, bool LowerCase = false) {
const char HexChar = LowerCase ? 'a' : 'A';
return X < 10 ? '0' + X : HexChar + X - 10;
}
/// Construct a string ref from a boolean.
static inline StringRef toStringRef(bool B) {
return StringRef(B ? "true" : "false");
inline StringRef toStringRef(bool B) { return StringRef(B ? "true" : "false"); }
/// Construct a string ref from an array ref of unsigned chars.
inline StringRef toStringRef(ArrayRef<uint8_t> Input) {
return StringRef(reinterpret_cast<const char *>(Input.begin()), Input.size());
}
/// Construct a string ref from an array ref of unsigned chars.
inline ArrayRef<uint8_t> arrayRefFromStringRef(StringRef Input) {
return {Input.bytes_begin(), Input.bytes_end()};
}
/// Interpret the given character \p C as a hexadecimal digit and return its
/// value.
///
/// If \p C is not a valid hex digit, -1U is returned.
static inline unsigned hexDigitValue(char C) {
inline unsigned hexDigitValue(char C) {
if (C >= '0' && C <= '9') return C-'0';
if (C >= 'a' && C <= 'f') return C-'a'+10U;
if (C >= 'A' && C <= 'F') return C-'A'+10U;
return -1U;
}
static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
/// Checks if character \p C is one of the 10 decimal digits.
inline bool isDigit(char C) { return C >= '0' && C <= '9'; }
/// Checks if character \p C is a hexadecimal numeric character.
inline bool isHexDigit(char C) { return hexDigitValue(C) != -1U; }
/// Checks if character \p C is a valid letter as classified by "C" locale.
inline bool isAlpha(char C) {
return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z');
}
/// Checks whether character \p C is either a decimal digit or an uppercase or
/// lowercase letter as classified by "C" locale.
inline bool isAlnum(char C) { return isAlpha(C) || isDigit(C); }
/// Returns the corresponding lowercase character if \p x is uppercase.
inline char toLower(char x) {
if (x >= 'A' && x <= 'Z')
return x - 'A' + 'a';
return x;
}
/// Returns the corresponding uppercase character if \p x is lowercase.
inline char toUpper(char x) {
if (x >= 'a' && x <= 'z')
return x - 'a' + 'A';
return x;
}
inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
char Buffer[17];
char *BufPtr = std::end(Buffer);
@@ -61,7 +109,7 @@ static inline std::string utohexstr(uint64_t X, bool LowerCase = false) {
/// Convert buffer \p Input to its hexadecimal representation.
/// The returned string is double the size of \p Input.
static inline std::string toHex(StringRef Input) {
inline std::string toHex(StringRef Input) {
static const char *const LUT = "0123456789ABCDEF";
size_t Length = Input.size();
@@ -75,7 +123,74 @@ static inline std::string toHex(StringRef Input) {
return Output;
}
static inline std::string utostr(uint64_t X, bool isNeg = false) {
inline std::string toHex(ArrayRef<uint8_t> Input) {
return toHex(toStringRef(Input));
}
inline uint8_t hexFromNibbles(char MSB, char LSB) {
unsigned U1 = hexDigitValue(MSB);
unsigned U2 = hexDigitValue(LSB);
assert(U1 != -1U && U2 != -1U);
return static_cast<uint8_t>((U1 << 4) | U2);
}
/// Convert hexadecimal string \p Input to its binary representation.
/// The return string is half the size of \p Input.
inline std::string fromHex(StringRef Input) {
if (Input.empty())
return std::string();
std::string Output;
Output.reserve((Input.size() + 1) / 2);
if (Input.size() % 2 == 1) {
Output.push_back(hexFromNibbles('0', Input.front()));
Input = Input.drop_front();
}
assert(Input.size() % 2 == 0);
while (!Input.empty()) {
uint8_t Hex = hexFromNibbles(Input[0], Input[1]);
Output.push_back(Hex);
Input = Input.drop_front(2);
}
return Output;
}
/// Convert the string \p S to an integer of the specified type using
/// the radix \p Base. If \p Base is 0, auto-detects the radix.
/// Returns true if the number was successfully converted, false otherwise.
template <typename N> bool to_integer(StringRef S, N &Num, unsigned Base = 0) {
return !S.getAsInteger(Base, Num);
}
namespace detail {
template <typename N>
inline bool to_float(const Twine &T, N &Num, N (*StrTo)(const char *, char **)) {
SmallString<32> Storage;
StringRef S = T.toNullTerminatedStringRef(Storage);
char *End;
N Temp = StrTo(S.data(), &End);
if (*End != '\0')
return false;
Num = Temp;
return true;
}
}
inline bool to_float(const Twine &T, float &Num) {
return detail::to_float(T, Num, strtof);
}
inline bool to_float(const Twine &T, double &Num) {
return detail::to_float(T, Num, strtod);
}
inline bool to_float(const Twine &T, long double &Num) {
return detail::to_float(T, Num, strtold);
}
inline std::string utostr(uint64_t X, bool isNeg = false) {
char Buffer[21];
char *BufPtr = std::end(Buffer);
@@ -90,8 +205,7 @@ static inline std::string utostr(uint64_t X, bool isNeg = false) {
return std::string(BufPtr, std::end(Buffer));
}
static inline std::string itostr(int64_t X) {
inline std::string itostr(int64_t X) {
if (X < 0)
return utostr(static_cast<uint64_t>(-X), true);
else
@@ -132,7 +246,7 @@ static inline unsigned HashString(StringRef Str, unsigned Result = 0) {
}
/// Returns the English suffix for an ordinal integer (-st, -nd, -rd, -th).
static inline StringRef getOrdinalSuffix(unsigned Val) {
inline StringRef getOrdinalSuffix(unsigned Val) {
// It is critically important that we do this perfectly for
// user-written sequences with over 100 elements.
switch (Val % 100) {
@@ -150,6 +264,15 @@ static inline StringRef getOrdinalSuffix(unsigned Val) {
}
}
/// PrintEscapedString - Print each character of the specified string, escaping
/// it if it is not printable or if it is an escape char.
void PrintEscapedString(StringRef Name, raw_ostream &Out);
/// printLowerCase - Print each character as lowercase if it is uppercase.
void printLowerCase(StringRef String, raw_ostream &Out);
namespace detail {
template <typename IteratorT>
inline std::string join_impl(IteratorT Begin, IteratorT End,
StringRef Separator, std::input_iterator_tag) {
@@ -184,14 +307,74 @@ inline std::string join_impl(IteratorT Begin, IteratorT End,
return S;
}
template <typename Sep>
inline void join_items_impl(std::string &Result, Sep Separator) {}
template <typename Sep, typename Arg>
inline void join_items_impl(std::string &Result, Sep Separator,
const Arg &Item) {
Result += Item;
}
template <typename Sep, typename Arg1, typename... Args>
inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1,
Args &&... Items) {
Result += A1;
Result += Separator;
join_items_impl(Result, Separator, std::forward<Args>(Items)...);
}
inline size_t join_one_item_size(char C) { return 1; }
inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; }
template <typename T> inline size_t join_one_item_size(const T &Str) {
return Str.size();
}
inline size_t join_items_size() { return 0; }
template <typename A1> inline size_t join_items_size(const A1 &A) {
return join_one_item_size(A);
}
template <typename A1, typename... Args>
inline size_t join_items_size(const A1 &A, Args &&... Items) {
return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
}
} // end namespace detail
/// Joins the strings in the range [Begin, End), adding Separator between
/// the elements.
template <typename IteratorT>
inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
typedef typename std::iterator_traits<IteratorT>::iterator_category tag;
return join_impl(Begin, End, Separator, tag());
using tag = typename std::iterator_traits<IteratorT>::iterator_category;
return detail::join_impl(Begin, End, Separator, tag());
}
} // End wpi namespace
/// Joins the strings in the range [R.begin(), R.end()), adding Separator
/// between the elements.
template <typename Range>
inline std::string join(Range &&R, StringRef Separator) {
return join(R.begin(), R.end(), Separator);
}
#endif
/// Joins the strings in the parameter pack \p Items, adding \p Separator
/// between the elements. All arguments must be implicitly convertible to
/// std::string, or there should be an overload of std::string::operator+=()
/// that accepts the argument explicitly.
template <typename Sep, typename... Args>
inline std::string join_items(Sep Separator, Args &&... Items) {
std::string Result;
if (sizeof...(Items) == 0)
return Result;
size_t NS = detail::join_one_item_size(Separator);
size_t NI = detail::join_items_size(std::forward<Args>(Items)...);
Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1);
detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...);
return Result;
}
} // end namespace wpi
#endif // LLVM_ADT_STRINGEXTRAS_H

View File

@@ -1,4 +1,4 @@
//===--- StringMap.h - String Hash table map interface ----------*- C++ -*-===//
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,33 +11,40 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_STRINGMAP_H
#define LLVM_ADT_STRINGMAP_H
#ifndef WPIUTIL_WPI_STRINGMAP_H
#define WPIUTIL_WPI_STRINGMAP_H
#include "wpi/SmallVector.h"
#include "wpi/StringRef.h"
#include "wpi/iterator.h"
#include "wpi/iterator_range.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/deprecated.h"
#include "wpi/memory.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <utility>
namespace wpi {
template<typename ValueT>
class StringMapConstIterator;
template<typename ValueT>
class StringMapIterator;
template<typename ValueTy>
class StringMapEntry;
template<typename ValueTy> class StringMapConstIterator;
template<typename ValueTy> class StringMapIterator;
template<typename ValueTy> class StringMapKeyIterator;
template<typename ValueTy> class StringMapEntry;
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
class StringMapEntryBase {
unsigned StrLen;
size_t StrLen;
public:
explicit StringMapEntryBase(unsigned Len) : StrLen(Len) {}
explicit StringMapEntryBase(size_t Len) : StrLen(Len) {}
unsigned getKeyLength() const { return StrLen; }
size_t getKeyLength() const { return StrLen; }
};
/// StringMapImpl - This is the base class of StringMap that is shared among
@@ -47,17 +54,15 @@ protected:
// Array of NumBuckets pointers to entries, null pointers are holes.
// TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
// by an array of the actual hash values as unsigned integers.
StringMapEntryBase **TheTable;
unsigned NumBuckets;
unsigned NumItems;
unsigned NumTombstones;
StringMapEntryBase **TheTable = nullptr;
unsigned NumBuckets = 0;
unsigned NumItems = 0;
unsigned NumTombstones = 0;
unsigned ItemSize;
protected:
explicit StringMapImpl(unsigned itemSize)
: TheTable(nullptr),
// Initialize the map with zero buckets to allocation.
NumBuckets(0), NumItems(0), NumTombstones(0), ItemSize(itemSize) {}
: ItemSize(itemSize) {}
StringMapImpl(StringMapImpl &&RHS)
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
@@ -121,16 +126,15 @@ public:
/// and data.
template<typename ValueTy>
class StringMapEntry : public StringMapEntryBase {
StringMapEntry(StringMapEntry &E) = delete;
public:
ValueTy second;
explicit StringMapEntry(unsigned strLen)
explicit StringMapEntry(size_t strLen)
: StringMapEntryBase(strLen), second() {}
template <typename... InitTy>
StringMapEntry(unsigned strLen, InitTy &&... InitVals)
StringMapEntry(size_t strLen, InitTy &&... InitVals)
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
StringMapEntry(StringMapEntry &E) = delete;
StringRef getKey() const {
return StringRef(getKeyData(), getKeyLength());
@@ -152,15 +156,14 @@ public:
/// \p InitiVals.
template <typename... InitTy>
static StringMapEntry *Create(StringRef Key, InitTy &&... InitVals) {
unsigned KeyLength = Key.size();
size_t KeyLength = Key.size();
// Allocate a new item with space for the string at the end and a null
// terminator.
unsigned AllocSize = static_cast<unsigned>(sizeof(StringMapEntry))+
KeyLength+1;
size_t AllocSize = sizeof(StringMapEntry) + KeyLength + 1;
StringMapEntry *NewItem =
static_cast<StringMapEntry*>(std::malloc(AllocSize));
static_cast<StringMapEntry*>(CheckedMalloc(AllocSize));
// Construct the value.
new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
@@ -201,9 +204,10 @@ public:
template<typename ValueTy>
class StringMap : public StringMapImpl {
public:
typedef StringMapEntry<ValueTy> MapEntryTy;
using MapEntryTy = StringMapEntry<ValueTy>;
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
explicit StringMap(unsigned InitialSize)
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
@@ -217,11 +221,6 @@ public:
StringMap(StringMap &&RHS)
: StringMapImpl(std::move(RHS)) {}
StringMap &operator=(StringMap RHS) {
StringMapImpl::swap(RHS);
return *this;
}
StringMap(const StringMap &RHS) :
StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
if (RHS.empty())
@@ -256,14 +255,33 @@ public:
// not worthwhile.
}
StringMap &operator=(StringMap RHS) {
StringMapImpl::swap(RHS);
return *this;
}
typedef const char* key_type;
typedef ValueTy mapped_type;
typedef StringMapEntry<ValueTy> value_type;
typedef size_t size_type;
~StringMap() {
// Delete all the elements in the map, but don't reset the elements
// to default values. This is a copy of clear(), but avoids unnecessary
// work not required in the destructor.
if (!empty()) {
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
static_cast<MapEntryTy*>(Bucket)->Destroy();
}
}
}
free(TheTable);
}
typedef StringMapConstIterator<ValueTy> const_iterator;
typedef StringMapIterator<ValueTy> iterator;
using key_type = const char*;
using mapped_type = ValueTy;
using value_type = StringMapEntry<ValueTy>;
using size_type = size_t;
using const_iterator = StringMapConstIterator<ValueTy>;
using iterator = StringMapIterator<ValueTy>;
iterator begin() {
return iterator(TheTable, NumBuckets == 0);
@@ -278,6 +296,11 @@ public:
return const_iterator(TheTable+NumBuckets, true);
}
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
return make_range(StringMapKeyIterator<ValueTy>(begin()),
StringMapKeyIterator<ValueTy>(end()));
}
iterator find(StringRef Key) {
int Bucket = FindKey(Key);
if (Bucket == -1) return end();
@@ -301,9 +324,7 @@ public:
/// Lookup the ValueTy for the \p Key, or create a default constructed value
/// if the key is not in the map.
ValueTy &operator[](StringRef Key) {
return emplace_second(Key).first->second;
}
ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; }
/// count - Return 1 if the element is in the map, 0 otherwise.
size_type count(StringRef Key) const {
@@ -334,7 +355,13 @@ public:
/// if and only if the insertion takes place, and the iterator component of
/// the pair points to the element with key equivalent to the key of the pair.
std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {
return emplace_second(KV.first, std::move(KV.second));
return try_emplace(KV.first, std::move(KV.second));
}
template <typename... ArgsTy>
WPI_DEPRECATED("use try_emplace instead")
std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) {
return try_emplace(Key, std::forward<ArgsTy>(Args)...);
}
/// Emplace a new element for the specified key into the map if the key isn't
@@ -342,7 +369,7 @@ public:
/// if and only if the insertion takes place, and the iterator component of
/// the pair points to the element with key equivalent to the key of the pair.
template <typename... ArgsTy>
std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) {
std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&... Args) {
unsigned BucketNo = LookupBucketFor(Key);
StringMapEntryBase *&Bucket = TheTable[BucketNo];
if (Bucket && Bucket != getTombstoneVal())
@@ -395,68 +422,53 @@ public:
erase(I);
return true;
}
~StringMap() {
// Delete all the elements in the map, but don't reset the elements
// to default values. This is a copy of clear(), but avoids unnecessary
// work not required in the destructor.
if (!empty()) {
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
static_cast<MapEntryTy*>(Bucket)->Destroy();
}
}
}
free(TheTable);
}
};
template <typename ValueTy> class StringMapConstIterator {
template <typename DerivedTy, typename ValueTy>
class StringMapIterBase
: public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
ValueTy> {
protected:
StringMapEntryBase **Ptr;
StringMapEntryBase **Ptr = nullptr;
public:
typedef StringMapEntry<ValueTy> value_type;
StringMapIterBase() = default;
StringMapConstIterator() : Ptr(nullptr) { }
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: Ptr(Bucket) {
explicit StringMapIterBase(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: Ptr(Bucket) {
if (!NoAdvance) AdvancePastEmptyBuckets();
}
const value_type &operator*() const {
return *static_cast<StringMapEntry<ValueTy>*>(*Ptr);
}
const value_type *operator->() const {
return static_cast<StringMapEntry<ValueTy>*>(*Ptr);
DerivedTy &operator=(const DerivedTy &Other) {
Ptr = Other.Ptr;
return static_cast<DerivedTy &>(*this);
}
bool operator==(const StringMapConstIterator &RHS) const {
return Ptr == RHS.Ptr;
}
bool operator!=(const StringMapConstIterator &RHS) const {
return Ptr != RHS.Ptr;
}
bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
inline StringMapConstIterator& operator++() { // Preincrement
DerivedTy &operator++() { // Preincrement
++Ptr;
AdvancePastEmptyBuckets();
return *this;
}
StringMapConstIterator operator++(int) { // Postincrement
StringMapConstIterator tmp = *this; ++*this; return tmp;
return static_cast<DerivedTy &>(*this);
}
inline StringMapConstIterator& operator--() { // Predecrement
DerivedTy operator++(int) { // Post-increment
DerivedTy Tmp(Ptr);
++*this;
return Tmp;
}
DerivedTy &operator--() { // Predecrement
--Ptr;
ReversePastEmptyBuckets();
return *this;
return static_cast<DerivedTy &>(*this);
}
StringMapConstIterator operator--(int) { // Postdecrement
StringMapConstIterator tmp = *this; --*this; return tmp;
DerivedTy operator--(int) { // Post-decrement
DerivedTy Tmp(Ptr);
--*this;
return Tmp;
}
private:
@@ -470,20 +482,70 @@ private:
}
};
template<typename ValueTy>
class StringMapIterator : public StringMapConstIterator<ValueTy> {
template <typename ValueTy>
class StringMapConstIterator
: public StringMapIterBase<StringMapConstIterator<ValueTy>,
const StringMapEntry<ValueTy>> {
using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
const StringMapEntry<ValueTy>>;
public:
StringMapIterator() {}
using value_type = const StringMapEntry<ValueTy>;
StringMapConstIterator() = default;
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: base(Bucket, NoAdvance) {}
value_type &operator*() const {
return *static_cast<value_type *>(*this->Ptr);
}
};
template <typename ValueTy>
class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
StringMapEntry<ValueTy>> {
using base =
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
public:
using value_type = StringMapEntry<ValueTy>;
StringMapIterator() = default;
explicit StringMapIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: StringMapConstIterator<ValueTy>(Bucket, NoAdvance) {
: base(Bucket, NoAdvance) {}
value_type &operator*() const {
return *static_cast<value_type *>(*this->Ptr);
}
StringMapEntry<ValueTy> &operator*() const {
return *static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
operator StringMapConstIterator<ValueTy>() const {
return StringMapConstIterator<ValueTy>(this->Ptr, true);
}
StringMapEntry<ValueTy> *operator->() const {
return static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
};
template <typename ValueTy>
class StringMapKeyIterator
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
StringMapConstIterator<ValueTy>,
std::forward_iterator_tag, StringRef> {
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
StringMapConstIterator<ValueTy>,
std::forward_iterator_tag, StringRef>;
public:
StringMapKeyIterator() = default;
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
: base(std::move(Iter)) {}
StringRef &operator*() {
Key = this->wrapped()->getKey();
return Key;
}
private:
StringRef Key;
};
template <typename ValueTy>
@@ -571,6 +633,6 @@ inline bool operator>=(const StringMap<ValueTy>& lhs,
return !(lhs < rhs);
}
} // namespace wpi
} // end namespace wpi
#endif
#endif // LLVM_ADT_STRINGMAP_H

View File

@@ -1,4 +1,4 @@
//===--- StringRef.h - Constant String Reference Wrapper --------*- C++ -*-===//
//===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,23 +7,26 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_STRINGREF_H
#define LLVM_ADT_STRINGREF_H
#ifndef WPIUTIL_WPI_STRINGREF_H
#define WPIUTIL_WPI_STRINGREF_H
#include "wpi/STLExtras.h"
#include "wpi/iterator_range.h"
#include "wpi/Compiler.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iosfwd>
#include <limits>
#include <ostream>
#include <string>
#include <type_traits>
#include <utility>
namespace wpi {
template <typename T>
class SmallVectorImpl;
class hash_code;
template <typename T> class SmallVectorImpl;
class StringRef;
/// Helper functions for StringRef::getAsInteger.
@@ -32,6 +35,10 @@ namespace wpi {
bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result) noexcept;
bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
unsigned long long &Result) noexcept;
bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result) noexcept;
/// StringRef - Represent a constant reference to a string, i.e. a character
/// array and a length, which need not be null terminated.
///
@@ -41,76 +48,56 @@ namespace wpi {
/// general safe to store a StringRef.
class StringRef {
public:
typedef const char *iterator;
typedef const char *const_iterator;
static const size_t npos = ~size_t(0);
typedef size_t size_type;
using iterator = const char *;
using const_iterator = const char *;
using size_type = size_t;
private:
/// The start of the string, in an external buffer.
const char *Data;
const char *Data = nullptr;
/// The length of the string.
/// MSB of length indicates if we are null terminated or not
/// Flag set is null terminated, flag not set is not
size_t Length;
size_t Length = 0;
// Workaround memcmp issue with null pointers (undefined behavior)
// by providing a specialized version
LLVM_ATTRIBUTE_ALWAYS_INLINE
static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) noexcept {
if (Length == 0) { return 0; }
return ::memcmp(Lhs,Rhs,Length);
}
/// Set the flag to say we are null terminated
void set_null_terminated(bool set) noexcept {
if (set)
Length |= ((size_t)1 << (sizeof(size_t) * 8 - 1));
else {
Length &= ~((size_t)1 << (sizeof(size_t) * 8 - 1));
}
}
public:
/// @name Constructors
/// @{
/// Construct an empty string ref.
/*implicit*/ StringRef() noexcept : Data(""), Length(0) {
set_null_terminated(true);
}
/*implicit*/ StringRef() = default;
/// Disable conversion from nullptr. This prevents things like
/// if (S == nullptr)
StringRef(std::nullptr_t) = delete;
/// Construct a string ref from a cstring.
/*implicit*/ StringRef(const char *Str) noexcept
: Data(Str) {
assert(Str && "StringRef cannot be built from a NULL argument");
Length = ::strlen(Str); // invoking strlen(NULL) is undefined behavior
// Require length to not use MSB of size
assert(Length < ~((size_t)1 << (sizeof(size_t) * 8 - 1)));
// If from a const char*, we are null terminated
set_null_terminated(true);
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
/*implicit*/ StringRef(const char *Str)
: Data(Str), Length(Str ? ::strlen(Str) : 0) {}
/// Construct a string ref from a pointer and length.
/*implicit*/ StringRef(const char *data, size_t length, bool isNullTerminated = false) noexcept
: Data(data), Length(length) {
assert((data || length == 0) &&
"StringRef cannot be built from a NULL argument with non-null length");
// Require length to not use MSB of size
assert(Length < ~((size_t)1 << (sizeof(size_t) * 8 - 1)));
// If passed an explicit length, use the parameter
// Default to false (not null) to match previous behavior.
set_null_terminated(isNullTerminated);
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
/*implicit*/ constexpr StringRef(const char *data, size_t length)
: Data(data), Length(length) {}
/// Construct a string ref from an std::string.
LLVM_ATTRIBUTE_ALWAYS_INLINE
/*implicit*/ StringRef(const std::string &Str)
: Data(Str.data()), Length(Str.length()) {
// Require length to not use MSB of size
assert(Length < ~((size_t)1 << (sizeof(size_t) * 8 - 1)));
// If from a std::string, we are null terminated
set_null_terminated(true);
}
: Data(Str.data()), Length(Str.length()) {}
static StringRef withNullAsEmpty(const char *data) {
return StringRef(data ? data : "");
}
/// @}
/// @name Iterators
@@ -118,7 +105,7 @@ namespace wpi {
iterator begin() const noexcept { return Data; }
iterator end() const noexcept { return Data + size(); }
iterator end() const noexcept { return Data + Length; }
const unsigned char *bytes_begin() const noexcept {
return reinterpret_cast<const unsigned char *>(begin());
@@ -136,95 +123,110 @@ namespace wpi {
/// data - Get a pointer to the start of the string (which may not be null
/// terminated).
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
const char *data() const noexcept { return Data; }
/// c_str - Get a null terminated pointer to the start of the string
/// If string is not null terminated, use buffer to store new string
const char *c_str(wpi::SmallVectorImpl<char>& buf) const;
/// empty - Check if the string is empty.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool empty() const noexcept { return size() == 0; }
/// size - Get the string size.
size_t size() const noexcept {
return Length & ~((size_t)1 << (sizeof(size_t) * 8 - 1));
}
/// is_null_terminated - Get if the string is guaranteed null terminated
bool is_null_terminated() const noexcept {
return (Length & ((size_t)1 << (sizeof(size_t) * 8 - 1))) ==
((size_t)1 << (sizeof(size_t) * 8 - 1));
}
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t size() const noexcept { return Length; }
/// front - Get the first character in the string.
LLVM_NODISCARD
char front() const noexcept {
assert(!empty());
return Data[0];
}
/// back - Get the last character in the string.
LLVM_NODISCARD
char back() const noexcept {
assert(!empty());
return Data[size()-1];
return Data[Length-1];
}
// copy - Allocate copy in Allocator and return StringRef to it.
template <typename Allocator> StringRef copy(Allocator &A) const {
template <typename Allocator>
LLVM_NODISCARD StringRef copy(Allocator &A) const {
// Don't request a length 0 copy from the allocator.
if (empty())
return StringRef();
char *S = A.template Allocate<char>(size());
char *S = A.template Allocate<char>(Length);
std::copy(begin(), end(), S);
return StringRef(S, size());
return StringRef(S, Length);
}
/// equals - Check for string equality, this is more efficient than
/// compare() when the relative ordering of inequal strings isn't needed.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool equals(StringRef RHS) const noexcept {
return (size() == RHS.size() &&
compareMemory(Data, RHS.Data, RHS.size()) == 0);
return (Length == RHS.Length &&
compareMemory(Data, RHS.Data, RHS.Length) == 0);
}
/// equals_lower - Check for string equality, ignoring case.
LLVM_NODISCARD
bool equals_lower(StringRef RHS) const noexcept {
return size() == RHS.size() && compare_lower(RHS) == 0;
return Length == RHS.Length && compare_lower(RHS) == 0;
}
/// compare - Compare two strings; the result is -1, 0, or 1 if this string
/// is lexicographically less than, equal to, or greater than the \p RHS.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
int compare(StringRef RHS) const noexcept {
// Check the prefix for a mismatch.
if (int Res = compareMemory(Data, RHS.Data, std::min(size(), RHS.size())))
if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length)))
return Res < 0 ? -1 : 1;
// Otherwise the prefixes match, so we only need to check the lengths.
if (size() == RHS.size())
if (Length == RHS.Length)
return 0;
return size() < RHS.size() ? -1 : 1;
return Length < RHS.Length ? -1 : 1;
}
/// compare_lower - Compare two strings, ignoring case.
LLVM_NODISCARD
int compare_lower(StringRef RHS) const noexcept;
/// compare_numeric - Compare two strings, treating sequences of digits as
/// numbers.
LLVM_NODISCARD
int compare_numeric(StringRef RHS) const noexcept;
/// str - Get the contents as an std::string.
LLVM_NODISCARD
std::string str() const {
if (!Data) return std::string();
return std::string(Data, size());
return std::string(Data, Length);
}
/// @}
/// @name Operator Overloads
/// @{
LLVM_NODISCARD
char operator[](size_t Index) const noexcept {
assert(Index < size() && "Invalid index!");
assert(Index < Length && "Invalid index!");
return Data[Index];
}
/// Disallow accidental assignment from a temporary std::string.
///
/// The declaration here is extra complicated so that `stringRef = {}`
/// and `stringRef = "abc"` continue to select the move assignment operator.
template <typename T>
typename std::enable_if<std::is_same<T, std::string>::value,
StringRef>::type &
operator=(T &&Str) = delete;
/// @}
/// @name Type Conversions
/// @{
@@ -238,21 +240,27 @@ namespace wpi {
/// @{
/// Check if this string starts with the given \p Prefix.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool startswith(StringRef Prefix) const noexcept {
return size() >= Prefix.size() &&
compareMemory(Data, Prefix.Data, Prefix.size()) == 0;
return Length >= Prefix.Length &&
compareMemory(Data, Prefix.Data, Prefix.Length) == 0;
}
/// Check if this string starts with the given \p Prefix, ignoring case.
LLVM_NODISCARD
bool startswith_lower(StringRef Prefix) const noexcept;
/// Check if this string ends with the given \p Suffix.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool endswith(StringRef Suffix) const noexcept {
return size() >= Suffix.size() &&
compareMemory(end() - Suffix.size(), Suffix.Data, Suffix.size()) == 0;
return Length >= Suffix.Length &&
compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
}
/// Check if this string ends with the given \p Suffix, ignoring case.
LLVM_NODISCARD
bool endswith_lower(StringRef Suffix) const noexcept;
/// @}
@@ -263,28 +271,72 @@ namespace wpi {
///
/// \returns The index of the first occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t find(char C, size_t From = 0) const noexcept {
size_t FindBegin = std::min(From, size());
if (FindBegin < size()) { // Avoid calling memchr with nullptr.
size_t FindBegin = std::min(From, Length);
if (FindBegin < Length) { // Avoid calling memchr with nullptr.
// Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(Data + FindBegin, C, size() - FindBegin))
if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin))
return static_cast<const char *>(P) - Data;
}
return npos;
}
/// Search for the first character \p C in the string, ignoring case.
///
/// \returns The index of the first occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t find_lower(char C, size_t From = 0) const noexcept;
/// Search for the first character satisfying the predicate \p F
///
/// \returns The index of the first character satisfying \p F starting from
/// \p From, or npos if not found.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t find_if(function_ref<bool(char)> F, size_t From = 0) const noexcept {
StringRef S = drop_front(From);
while (!S.empty()) {
if (F(S.front()))
return size() - S.size();
S = S.drop_front();
}
return npos;
}
/// Search for the first character not satisfying the predicate \p F
///
/// \returns The index of the first character not satisfying \p F starting
/// from \p From, or npos if not found.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t find_if_not(function_ref<bool(char)> F, size_t From = 0) const noexcept {
return find_if([F](char c) { return !F(c); }, From);
}
/// Search for the first string \p Str in the string.
///
/// \returns The index of the first occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t find(StringRef Str, size_t From = 0) const noexcept;
/// Search for the first string \p Str in the string, ignoring case.
///
/// \returns The index of the first occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t find_lower(StringRef Str, size_t From = 0) const noexcept;
/// Search for the last character \p C in the string.
///
/// \returns The index of the last occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind(char C, size_t From = npos) const noexcept {
From = std::min(From, size());
From = std::min(From, Length);
size_t i = From;
while (i != 0) {
--i;
@@ -294,14 +346,30 @@ namespace wpi {
return npos;
}
/// Search for the last character \p C in the string, ignoring case.
///
/// \returns The index of the last occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind_lower(char C, size_t From = npos) const noexcept;
/// Search for the last string \p Str in the string.
///
/// \returns The index of the last occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind(StringRef Str) const noexcept;
/// Search for the last string \p Str in the string, ignoring case.
///
/// \returns The index of the last occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind_lower(StringRef Str) const noexcept;
/// Find the first character in the string that is \p C, or npos if not
/// found. Same as find.
LLVM_NODISCARD
size_t find_first_of(char C, size_t From = 0) const noexcept {
return find(C, From);
}
@@ -310,20 +378,24 @@ namespace wpi {
/// not found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_first_of(StringRef Chars, size_t From = 0) const noexcept;
/// Find the first character in the string that is not \p C or npos if not
/// found.
LLVM_NODISCARD
size_t find_first_not_of(char C, size_t From = 0) const noexcept;
/// Find the first character in the string that is not in the string
/// \p Chars, or npos if not found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_first_not_of(StringRef Chars, size_t From = 0) const noexcept;
/// Find the last character in the string that is \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t find_last_of(char C, size_t From = npos) const noexcept {
return rfind(C, From);
}
@@ -332,26 +404,56 @@ namespace wpi {
/// found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_last_of(StringRef Chars, size_t From = npos) const noexcept;
/// Find the last character in the string that is not \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t find_last_not_of(char C, size_t From = npos) const noexcept;
/// Find the last character in the string that is not in \p Chars, or
/// npos if not found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_last_not_of(StringRef Chars, size_t From = npos) const noexcept;
/// Return true if the given string is a substring of *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains(StringRef Other) const noexcept { return find(Other) != npos; }
/// Return true if the given character is contained in *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains(char C) const noexcept { return find_first_of(C) != npos; }
/// Return true if the given string is a substring of *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains_lower(StringRef Other) const noexcept {
return find_lower(Other) != npos;
}
/// Return true if the given character is contained in *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains_lower(char C) const noexcept { return find_lower(C) != npos; }
/// @}
/// @name Helpful Algorithms
/// @{
/// Return the number of occurrences of \p C in the string.
LLVM_NODISCARD
size_t count(char C) const noexcept {
size_t Count = 0;
for (size_t i = 0, e = size(); i != e; ++i)
for (size_t i = 0, e = Length; i != e; ++i)
if (Data[i] == C)
++Count;
return Count;
@@ -393,14 +495,47 @@ namespace wpi {
return false;
}
/// Parse the current string as an integer of the specified radix. If
/// \p Radix is specified as zero, this does radix autosensing using
/// extended C rules: 0 is octal, 0x is hex, 0b is binary.
///
/// If the string does not begin with a number of the specified radix,
/// this returns true to signify the error. The string is considered
/// erroneous if empty or if it overflows T.
/// The portion of the string representing the discovered numeric value
/// is removed from the beginning of the string.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
consumeInteger(unsigned Radix, T &Result) noexcept {
long long LLVal;
if (consumeSignedInteger(*this, Radix, LLVal) ||
static_cast<long long>(static_cast<T>(LLVal)) != LLVal)
return true;
Result = LLVal;
return false;
}
template <typename T>
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
consumeInteger(unsigned Radix, T &Result) noexcept {
unsigned long long ULLVal;
if (consumeUnsignedInteger(*this, Radix, ULLVal) ||
static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
return true;
Result = ULLVal;
return false;
}
/// @}
/// @name String Operations
/// @{
// Convert the given ASCII string to lowercase.
LLVM_NODISCARD
std::string lower() const;
/// Convert the given ASCII string to uppercase.
LLVM_NODISCARD
std::string upper() const;
/// @}
@@ -416,13 +551,55 @@ namespace wpi {
/// \param N The number of characters to included in the substring. If N
/// exceeds the number of characters remaining in the string, the string
/// suffix (starting with \p Start) will be returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef substr(size_t Start, size_t N = npos) const noexcept {
Start = std::min(Start, size());
return StringRef(Data + Start, std::min(N, size() - Start));
Start = std::min(Start, Length);
return StringRef(Data + Start, std::min(N, Length - Start));
}
/// Return a StringRef equal to 'this' but with only the first \p N
/// elements remaining. If \p N is greater than the length of the
/// string, the entire string is returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_front(size_t N = 1) const noexcept {
if (N >= size())
return *this;
return drop_back(size() - N);
}
/// Return a StringRef equal to 'this' but with only the last \p N
/// elements remaining. If \p N is greater than the length of the
/// string, the entire string is returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_back(size_t N = 1) const noexcept {
if (N >= size())
return *this;
return drop_front(size() - N);
}
/// Return the longest prefix of 'this' such that every character
/// in the prefix satisfies the given predicate.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_while(function_ref<bool(char)> F) const noexcept {
return substr(0, find_if_not(F));
}
/// Return the longest prefix of 'this' such that no character in
/// the prefix satisfies the given predicate.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_until(function_ref<bool(char)> F) const noexcept {
return substr(0, find_if(F));
}
/// Return a StringRef equal to 'this' but with the first \p N elements
/// dropped.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_front(size_t N = 1) const noexcept {
assert(size() >= N && "Dropping more elements than exist");
return substr(N);
@@ -430,11 +607,51 @@ namespace wpi {
/// Return a StringRef equal to 'this' but with the last \p N elements
/// dropped.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_back(size_t N = 1) const noexcept {
assert(size() >= N && "Dropping more elements than exist");
return substr(0, size()-N);
}
/// Return a StringRef equal to 'this', but with all characters satisfying
/// the given predicate dropped from the beginning of the string.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_while(function_ref<bool(char)> F) const noexcept {
return substr(find_if_not(F));
}
/// Return a StringRef equal to 'this', but with all characters not
/// satisfying the given predicate dropped from the beginning of the string.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_until(function_ref<bool(char)> F) const noexcept {
return substr(find_if(F));
}
/// Returns true if this StringRef has the given prefix and removes that
/// prefix.
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool consume_front(StringRef Prefix) noexcept {
if (!startswith(Prefix))
return false;
*this = drop_front(Prefix.size());
return true;
}
/// Returns true if this StringRef has the given suffix and removes that
/// suffix.
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool consume_back(StringRef Suffix) noexcept {
if (!endswith(Suffix))
return false;
*this = drop_back(Suffix.size());
return true;
}
/// Return a reference to the substring from [Start, End).
///
/// \param Start The index of the starting character in the substring; if
@@ -446,9 +663,11 @@ namespace wpi {
/// remaining in the string, the string suffix (starting with \p Start)
/// will be returned. If this is less than \p Start, an empty string will
/// be returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef slice(size_t Start, size_t End) const noexcept {
Start = std::min(Start, size());
End = std::min(std::max(Start, End), size());
Start = std::min(Start, Length);
End = std::min(std::max(Start, End), Length);
return StringRef(Data + Start, End - Start);
}
@@ -462,6 +681,7 @@ namespace wpi {
///
/// \param Separator The character to split on.
/// \returns The split substrings.
LLVM_NODISCARD
std::pair<StringRef, StringRef> split(char Separator) const {
size_t Idx = find(Separator);
if (Idx == npos)
@@ -479,6 +699,7 @@ namespace wpi {
///
/// \param Separator - The string to split on.
/// \return - The split substrings.
LLVM_NODISCARD
std::pair<StringRef, StringRef> split(StringRef Separator) const {
size_t Idx = find(Separator);
if (Idx == npos)
@@ -531,6 +752,7 @@ namespace wpi {
///
/// \param Separator - The character to split on.
/// \return - The split substrings.
LLVM_NODISCARD
std::pair<StringRef, StringRef> rsplit(char Separator) const {
size_t Idx = rfind(Separator);
if (Idx == npos)
@@ -540,36 +762,42 @@ namespace wpi {
/// Return string with consecutive \p Char characters starting from the
/// the left removed.
LLVM_NODISCARD
StringRef ltrim(char Char) const noexcept {
return drop_front(std::min(size(), find_first_not_of(Char)));
return drop_front(std::min(Length, find_first_not_of(Char)));
}
/// Return string with consecutive characters in \p Chars starting from
/// the left removed.
LLVM_NODISCARD
StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const noexcept {
return drop_front(std::min(size(), find_first_not_of(Chars)));
return drop_front(std::min(Length, find_first_not_of(Chars)));
}
/// Return string with consecutive \p Char characters starting from the
/// right removed.
LLVM_NODISCARD
StringRef rtrim(char Char) const noexcept {
return drop_back(size() - std::min(size(), find_last_not_of(Char) + 1));
return drop_back(size() - std::min(Length, find_last_not_of(Char) + 1));
}
/// Return string with consecutive characters in \p Chars starting from
/// the right removed.
LLVM_NODISCARD
StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const noexcept {
return drop_back(size() - std::min(size(), find_last_not_of(Chars) + 1));
return drop_back(size() - std::min(Length, find_last_not_of(Chars) + 1));
}
/// Return string with consecutive \p Char characters starting from the
/// left and right removed.
LLVM_NODISCARD
StringRef trim(char Char) const noexcept {
return ltrim(Char).rtrim(Char);
}
/// Return string with consecutive characters in \p Chars starting from
/// the left and right removed.
LLVM_NODISCARD
StringRef trim(StringRef Chars = " \t\n\v\f\r") const noexcept {
return ltrim(Chars).rtrim(Chars);
}
@@ -577,14 +805,48 @@ namespace wpi {
/// @}
};
/// A wrapper around a string literal that serves as a proxy for constructing
/// global tables of StringRefs with the length computed at compile time.
/// In order to avoid the invocation of a global constructor, StringLiteral
/// should *only* be used in a constexpr context, as such:
///
/// constexpr StringLiteral S("test");
///
class StringLiteral : public StringRef {
private:
constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) {
}
public:
template <size_t N>
constexpr StringLiteral(const char (&Str)[N])
#if defined(__clang__) && __has_attribute(enable_if)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
__attribute((enable_if(__builtin_strlen(Str) == N - 1,
"invalid string literal")))
#pragma clang diagnostic pop
#endif
: StringRef(Str, N - 1) {
}
// Explicit construction for strings like "foo\0bar".
template <size_t N>
static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) {
return StringLiteral(Str, N - 1);
}
};
/// @name StringRef Comparison Operators
/// @{
inline bool operator==(StringRef LHS, StringRef RHS) noexcept {
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool operator==(StringRef LHS, StringRef RHS) noexcept {
return LHS.equals(RHS);
}
inline bool operator!=(StringRef LHS, StringRef RHS) noexcept {
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool operator!=(StringRef LHS, StringRef RHS) noexcept {
return !(LHS == RHS);
}
@@ -656,19 +918,18 @@ namespace wpi {
return buffer.append(string.data(), string.size());
}
inline std::ostream &operator<<(std::ostream &os, StringRef string) {
os.write(string.data(), string.size());
return os;
}
std::ostream &operator<<(std::ostream &os, StringRef string);
/// @}
/// \brief Compute a hash_code for a StringRef.
/// Compute a hash_code for a StringRef.
LLVM_NODISCARD
hash_code hash_value(StringRef S);
// StringRefs can be treated like a POD type.
template <typename T> struct isPodLike;
template <> struct isPodLike<StringRef> { static const bool value = true; };
} // namespace wpi
#endif
} // end namespace wpi
#endif // LLVM_ADT_STRINGREF_H

View File

@@ -1,4 +1,4 @@
//===-- Twine.h - Fast Temporary String Concatenation -----------*- C++ -*-===//
//===- Twine.h - Fast Temporary String Concatenation ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,17 +7,17 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_TWINE_H
#define LLVM_ADT_TWINE_H
#ifndef WPIUTIL_WPI_TWINE_H
#define WPIUTIL_WPI_TWINE_H
#include "wpi/SmallVector.h"
#include "wpi/StringRef.h"
#include <cassert>
#include <cstdint>
#include <string>
#include <stdint.h>
namespace wpi {
class raw_ostream;
/// Twine - A lightweight data structure for efficiently representing the
@@ -146,22 +146,22 @@ namespace wpi {
const uint64_t *uHex;
};
private:
/// LHS - The prefix in the concatenation, which may be uninitialized for
/// Null or Empty kinds.
Child LHS;
/// RHS - The suffix in the concatenation, which may be uninitialized for
/// Null or Empty kinds.
Child RHS;
/// LHSKind - The NodeKind of the left hand side, \see getLHSKind().
NodeKind LHSKind;
/// RHSKind - The NodeKind of the right hand side, \see getRHSKind().
NodeKind RHSKind;
private:
/// LHSKind - The NodeKind of the left hand side, \see getLHSKind().
NodeKind LHSKind = EmptyKind;
/// RHSKind - The NodeKind of the right hand side, \see getRHSKind().
NodeKind RHSKind = EmptyKind;
/// Construct a nullary twine; the kind must be NullKind or EmptyKind.
explicit Twine(NodeKind Kind)
: LHSKind(Kind), RHSKind(EmptyKind) {
explicit Twine(NodeKind Kind) : LHSKind(Kind) {
assert(isNullary() && "Invalid kind!");
}
@@ -179,10 +179,6 @@ namespace wpi {
assert(isValid() && "Invalid twine!");
}
/// Since the intended use of twines is as temporary objects, assignments
/// when concatenating might cause undefined behavior or stack corruptions
Twine &operator=(const Twine &Other) = delete;
/// Check for the null twine.
bool isNull() const {
return getLHSKind() == NullKind;
@@ -252,7 +248,7 @@ namespace wpi {
/// @{
/// Construct from an empty string.
/*implicit*/ Twine() : LHSKind(EmptyKind), RHSKind(EmptyKind) {
/*implicit*/ Twine() {
assert(isValid() && "Invalid twine!");
}
@@ -263,8 +259,7 @@ namespace wpi {
/// We take care here to optimize "" into the empty twine -- this will be
/// optimized out for string constants. This allows Twine arguments have
/// default "" values, without introducing unnecessary string constants.
/*implicit*/ Twine(const char *Str)
: RHSKind(EmptyKind) {
/*implicit*/ Twine(const char *Str) {
if (Str[0] != '\0') {
LHS.cString = Str;
LHSKind = CStringKind;
@@ -275,77 +270,66 @@ namespace wpi {
}
/// Construct from an std::string.
/*implicit*/ Twine(const std::string &Str)
: LHSKind(StdStringKind), RHSKind(EmptyKind) {
/*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) {
LHS.stdString = &Str;
assert(isValid() && "Invalid twine!");
}
/// Construct from a StringRef.
/*implicit*/ Twine(const StringRef &Str)
: LHSKind(StringRefKind), RHSKind(EmptyKind) {
/*implicit*/ Twine(const StringRef &Str) : LHSKind(StringRefKind) {
LHS.stringRef = &Str;
assert(isValid() && "Invalid twine!");
}
/// Construct from a SmallString.
/*implicit*/ Twine(const SmallVectorImpl<char> &Str)
: LHSKind(SmallStringKind), RHSKind(EmptyKind) {
: LHSKind(SmallStringKind) {
LHS.smallString = &Str;
assert(isValid() && "Invalid twine!");
}
/// Construct from a char.
explicit Twine(char Val)
: LHSKind(CharKind), RHSKind(EmptyKind) {
explicit Twine(char Val) : LHSKind(CharKind) {
LHS.character = Val;
}
/// Construct from a signed char.
explicit Twine(signed char Val)
: LHSKind(CharKind), RHSKind(EmptyKind) {
explicit Twine(signed char Val) : LHSKind(CharKind) {
LHS.character = static_cast<char>(Val);
}
/// Construct from an unsigned char.
explicit Twine(unsigned char Val)
: LHSKind(CharKind), RHSKind(EmptyKind) {
explicit Twine(unsigned char Val) : LHSKind(CharKind) {
LHS.character = static_cast<char>(Val);
}
/// Construct a twine to print \p Val as an unsigned decimal integer.
explicit Twine(unsigned Val)
: LHSKind(DecUIKind), RHSKind(EmptyKind) {
explicit Twine(unsigned Val) : LHSKind(DecUIKind) {
LHS.decUI = Val;
}
/// Construct a twine to print \p Val as a signed decimal integer.
explicit Twine(int Val)
: LHSKind(DecIKind), RHSKind(EmptyKind) {
explicit Twine(int Val) : LHSKind(DecIKind) {
LHS.decI = Val;
}
/// Construct a twine to print \p Val as an unsigned decimal integer.
explicit Twine(const unsigned long &Val)
: LHSKind(DecULKind), RHSKind(EmptyKind) {
explicit Twine(const unsigned long &Val) : LHSKind(DecULKind) {
LHS.decUL = &Val;
}
/// Construct a twine to print \p Val as a signed decimal integer.
explicit Twine(const long &Val)
: LHSKind(DecLKind), RHSKind(EmptyKind) {
explicit Twine(const long &Val) : LHSKind(DecLKind) {
LHS.decL = &Val;
}
/// Construct a twine to print \p Val as an unsigned decimal integer.
explicit Twine(const unsigned long long &Val)
: LHSKind(DecULLKind), RHSKind(EmptyKind) {
explicit Twine(const unsigned long long &Val) : LHSKind(DecULLKind) {
LHS.decULL = &Val;
}
/// Construct a twine to print \p Val as a signed decimal integer.
explicit Twine(const long long &Val)
: LHSKind(DecLLKind), RHSKind(EmptyKind) {
explicit Twine(const long long &Val) : LHSKind(DecLLKind) {
LHS.decLL = &Val;
}
@@ -370,6 +354,10 @@ namespace wpi {
assert(isValid() && "Invalid twine!");
}
/// Since the intended use of twines is as temporary objects, assignments
/// when concatenating might cause undefined behavior or stack corruptions
Twine &operator=(const Twine &) = delete;
/// Create a 'null' string, which is an empty string that always
/// concatenates to form another empty string.
static Twine createNull() {
@@ -539,6 +527,7 @@ namespace wpi {
}
/// @}
}
#endif
} // end namespace wpi
#endif // LLVM_ADT_TWINE_H

View File

@@ -12,6 +12,7 @@
#include "wpi/ArrayRef.h"
#include "wpi/StringRef.h"
#include "wpi/Twine.h"
#include "wpi/mutex.h"
namespace wpi {
@@ -25,7 +26,7 @@ class UDPClient {
public:
explicit UDPClient(Logger& logger);
UDPClient(StringRef address, Logger& logger);
UDPClient(const Twine& address, Logger& logger);
UDPClient(const UDPClient& other) = delete;
UDPClient(UDPClient&& other);
~UDPClient();
@@ -36,8 +37,8 @@ class UDPClient {
int start();
void shutdown();
// The passed in address MUST be a resolved IP address.
int send(ArrayRef<uint8_t> data, StringRef server, int port);
int send(StringRef data, StringRef server, int port);
int send(ArrayRef<uint8_t> data, const Twine& server, int port);
int send(StringRef data, const Twine& server, int port);
};
} // namespace wpi

View File

@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_WINDOWSERROR_H
#define LLVM_SUPPORT_WINDOWSERROR_H
#ifndef WPIUTIL_WPI_WINDOWSERROR_H
#define WPIUTIL_WPI_WINDOWSERROR_H
#include <system_error>

View File

@@ -0,0 +1,339 @@
//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_ITERATOR_H
#define WPIUTIL_WPI_ITERATOR_H
#include "wpi/iterator_range.h"
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <utility>
namespace wpi {
/// CRTP base class which implements the entire standard iterator facade
/// in terms of a minimal subset of the interface.
///
/// Use this when it is reasonable to implement most of the iterator
/// functionality in terms of a core subset. If you need special behavior or
/// there are performance implications for this, you may want to override the
/// relevant members instead.
///
/// Note, one abstraction that this does *not* provide is implementing
/// subtraction in terms of addition by negating the difference. Negation isn't
/// always information preserving, and I can see very reasonable iterator
/// designs where this doesn't work well. It doesn't really force much added
/// boilerplate anyways.
///
/// Another abstraction that this doesn't provide is implementing increment in
/// terms of addition of one. These aren't equivalent for all iterator
/// categories, and respecting that adds a lot of complexity for little gain.
///
/// Classes wishing to use `iterator_facade_base` should implement the following
/// methods:
///
/// Forward Iterators:
/// (All of the following methods)
/// - DerivedT &operator=(const DerivedT &R);
/// - bool operator==(const DerivedT &R) const;
/// - const T &operator*() const;
/// - T &operator*();
/// - DerivedT &operator++();
///
/// Bidirectional Iterators:
/// (All methods of forward iterators, plus the following)
/// - DerivedT &operator--();
///
/// Random-access Iterators:
/// (All methods of bidirectional iterators excluding the following)
/// - DerivedT &operator++();
/// - DerivedT &operator--();
/// (and plus the following)
/// - bool operator<(const DerivedT &RHS) const;
/// - DifferenceTypeT operator-(const DerivedT &R) const;
/// - DerivedT &operator+=(DifferenceTypeT N);
/// - DerivedT &operator-=(DifferenceTypeT N);
///
template <typename DerivedT, typename IteratorCategoryT, typename T,
typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
typename ReferenceT = T &>
class iterator_facade_base
: public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT,
ReferenceT> {
protected:
enum {
IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
IteratorCategoryT>::value,
IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag,
IteratorCategoryT>::value,
};
/// A proxy object for computing a reference via indirecting a copy of an
/// iterator. This is used in APIs which need to produce a reference via
/// indirection but for which the iterator object might be a temporary. The
/// proxy preserves the iterator internally and exposes the indirected
/// reference via a conversion operator.
class ReferenceProxy {
friend iterator_facade_base;
DerivedT I;
ReferenceProxy(DerivedT I) : I(std::move(I)) {}
public:
operator ReferenceT() const { return *I; }
};
public:
DerivedT operator+(DifferenceTypeT n) const {
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
"Must pass the derived type to this template!");
static_assert(
IsRandomAccess,
"The '+' operator is only defined for random access iterators.");
DerivedT tmp = *static_cast<const DerivedT *>(this);
tmp += n;
return tmp;
}
friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
static_assert(
IsRandomAccess,
"The '+' operator is only defined for random access iterators.");
return i + n;
}
DerivedT operator-(DifferenceTypeT n) const {
static_assert(
IsRandomAccess,
"The '-' operator is only defined for random access iterators.");
DerivedT tmp = *static_cast<const DerivedT *>(this);
tmp -= n;
return tmp;
}
DerivedT &operator++() {
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
"Must pass the derived type to this template!");
return static_cast<DerivedT *>(this)->operator+=(1);
}
DerivedT operator++(int) {
DerivedT tmp = *static_cast<DerivedT *>(this);
++*static_cast<DerivedT *>(this);
return tmp;
}
DerivedT &operator--() {
static_assert(
IsBidirectional,
"The decrement operator is only defined for bidirectional iterators.");
return static_cast<DerivedT *>(this)->operator-=(1);
}
DerivedT operator--(int) {
static_assert(
IsBidirectional,
"The decrement operator is only defined for bidirectional iterators.");
DerivedT tmp = *static_cast<DerivedT *>(this);
--*static_cast<DerivedT *>(this);
return tmp;
}
bool operator!=(const DerivedT &RHS) const {
return !static_cast<const DerivedT *>(this)->operator==(RHS);
}
bool operator>(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return !static_cast<const DerivedT *>(this)->operator<(RHS) &&
!static_cast<const DerivedT *>(this)->operator==(RHS);
}
bool operator<=(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return !static_cast<const DerivedT *>(this)->operator>(RHS);
}
bool operator>=(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return !static_cast<const DerivedT *>(this)->operator<(RHS);
}
PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
PointerT operator->() const {
return &static_cast<const DerivedT *>(this)->operator*();
}
ReferenceProxy operator[](DifferenceTypeT n) {
static_assert(IsRandomAccess,
"Subscripting is only defined for random access iterators.");
return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n));
}
ReferenceProxy operator[](DifferenceTypeT n) const {
static_assert(IsRandomAccess,
"Subscripting is only defined for random access iterators.");
return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
}
};
/// CRTP base class for adapting an iterator to a different type.
///
/// This class can be used through CRTP to adapt one iterator into another.
/// Typically this is done through providing in the derived class a custom \c
/// operator* implementation. Other methods can be overridden as well.
template <
typename DerivedT, typename WrappedIteratorT,
typename IteratorCategoryT =
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
typename DifferenceTypeT =
typename std::iterator_traits<WrappedIteratorT>::difference_type,
typename PointerT = typename std::conditional<
std::is_same<T, typename std::iterator_traits<
WrappedIteratorT>::value_type>::value,
typename std::iterator_traits<WrappedIteratorT>::pointer, T *>::type,
typename ReferenceT = typename std::conditional<
std::is_same<T, typename std::iterator_traits<
WrappedIteratorT>::value_type>::value,
typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type,
// Don't provide these, they are mostly to act as aliases below.
typename WrappedTraitsT = std::iterator_traits<WrappedIteratorT>>
class iterator_adaptor_base
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
DifferenceTypeT, PointerT, ReferenceT> {
using BaseT = typename iterator_adaptor_base::iterator_facade_base;
protected:
WrappedIteratorT I;
iterator_adaptor_base() = default;
explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {
static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
"Must pass the derived type to this template!");
}
const WrappedIteratorT &wrapped() const { return I; }
public:
using difference_type = DifferenceTypeT;
DerivedT &operator+=(difference_type n) {
static_assert(
BaseT::IsRandomAccess,
"The '+=' operator is only defined for random access iterators.");
I += n;
return *static_cast<DerivedT *>(this);
}
DerivedT &operator-=(difference_type n) {
static_assert(
BaseT::IsRandomAccess,
"The '-=' operator is only defined for random access iterators.");
I -= n;
return *static_cast<DerivedT *>(this);
}
using BaseT::operator-;
difference_type operator-(const DerivedT &RHS) const {
static_assert(
BaseT::IsRandomAccess,
"The '-' operator is only defined for random access iterators.");
return I - RHS.I;
}
// We have to explicitly provide ++ and -- rather than letting the facade
// forward to += because WrappedIteratorT might not support +=.
using BaseT::operator++;
DerivedT &operator++() {
++I;
return *static_cast<DerivedT *>(this);
}
using BaseT::operator--;
DerivedT &operator--() {
static_assert(
BaseT::IsBidirectional,
"The decrement operator is only defined for bidirectional iterators.");
--I;
return *static_cast<DerivedT *>(this);
}
bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
bool operator<(const DerivedT &RHS) const {
static_assert(
BaseT::IsRandomAccess,
"Relational operators are only defined for random access iterators.");
return I < RHS.I;
}
ReferenceT operator*() const { return *I; }
};
/// An iterator type that allows iterating over the pointees via some
/// other iterator.
///
/// The typical usage of this is to expose a type that iterates over Ts, but
/// which is implemented with some iterator over T*s:
///
/// \code
/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
/// \endcode
template <typename WrappedIteratorT,
typename T = typename std::remove_reference<
decltype(**std::declval<WrappedIteratorT>())>::type>
struct pointee_iterator
: iterator_adaptor_base<
pointee_iterator<WrappedIteratorT>, WrappedIteratorT,
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
T> {
pointee_iterator() = default;
template <typename U>
pointee_iterator(U &&u)
: pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
T &operator*() const { return **this->I; }
};
template <typename RangeT, typename WrappedIteratorT =
decltype(std::begin(std::declval<RangeT>()))>
iterator_range<pointee_iterator<WrappedIteratorT>>
make_pointee_range(RangeT &&Range) {
using PointeeIteratorT = pointee_iterator<WrappedIteratorT>;
return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))),
PointeeIteratorT(std::end(std::forward<RangeT>(Range))));
}
template <typename WrappedIteratorT,
typename T = decltype(&*std::declval<WrappedIteratorT>())>
class pointer_iterator
: public iterator_adaptor_base<pointer_iterator<WrappedIteratorT>,
WrappedIteratorT, T> {
mutable T Ptr;
public:
pointer_iterator() = default;
explicit pointer_iterator(WrappedIteratorT u)
: pointer_iterator::iterator_adaptor_base(std::move(u)) {}
T &operator*() { return Ptr = &*this->I; }
const T &operator*() const { return Ptr = &*this->I; }
};
template <typename RangeT, typename WrappedIteratorT =
decltype(std::begin(std::declval<RangeT>()))>
iterator_range<pointer_iterator<WrappedIteratorT>>
make_pointer_range(RangeT &&Range) {
using PointerIteratorT = pointer_iterator<WrappedIteratorT>;
return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))),
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
}
} // end namespace wpi
#endif // LLVM_ADT_ITERATOR_H

View File

@@ -16,15 +16,15 @@
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ITERATOR_RANGE_H
#define LLVM_ADT_ITERATOR_RANGE_H
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
#define WPIUTIL_WPI_ITERATOR_RANGE_H
#include <utility>
#include <iterator>
#include <utility>
namespace wpi {
/// \brief A range adaptor for a pair of iterators.
/// A range adaptor for a pair of iterators.
///
/// This just wraps two iterators into a range-compatible interface. Nothing
/// fancy at all.
@@ -47,7 +47,7 @@ public:
IteratorT end() const { return end_iterator; }
};
/// \brief Convenience function for iterating over sub-ranges.
/// Convenience function for iterating over sub-ranges.
///
/// This provides a bit of syntactic sugar to make using sub-ranges
/// in for loops a bit easier. Analogous to std::make_pair().

View File

@@ -952,7 +952,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::object_t& obj)
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
for (const auto& i : *inner_object) {
obj.emplace_second(i.first(), i.second);
obj.try_emplace(i.first(), i.second);
}
}
@@ -1247,7 +1247,7 @@ struct external_constructor<value_t::object>
j.m_value = value_t::object;
for (const auto& x : obj)
{
j.m_value.object->emplace_second(x.first, x.second);
j.m_value.object->try_emplace(x.first, x.second);
}
j.assert_invariant();
}
@@ -6188,7 +6188,7 @@ class json
}
// add element to array
m_value.object->emplace_second(val.first, std::move(val.second));
m_value.object->try_emplace(val.first, std::move(val.second));
}
/*!
@@ -6326,7 +6326,7 @@ class json
}
// add element to array (perfect forwarding)
auto res = m_value.object->emplace_second(key, std::forward<Args>(args)...);
auto res = m_value.object->try_emplace(key, std::forward<Args>(args)...);
// create result iterator and set iterator to the result of emplace
auto it = begin();
it.m_it.object_iterator = res.first;

View File

@@ -9,9 +9,6 @@
#define WPIUTIL_WPI_MEMORY_H_
#include <cstdlib>
#include <exception>
#include "wpi/raw_ostream.h"
namespace wpi {
@@ -21,28 +18,14 @@ namespace wpi {
* @param size number of bytes per object to allocate
* @return Pointer to beginning of newly allocated memory.
*/
inline void* CheckedCalloc(size_t num, size_t size) {
void* p = std::calloc(num, size);
if (!p) {
errs() << "FATAL: failed to allocate " << (num * size) << " bytes\n";
std::terminate();
}
return p;
}
void* CheckedCalloc(size_t num, size_t size);
/**
* Wrapper around std::malloc that calls std::terminate on out of memory.
* @param size number of bytes to allocate
* @return Pointer to beginning of newly allocated memory.
*/
inline void* CheckedMalloc(size_t size) {
void* p = std::malloc(size == 0 ? 1 : size);
if (!p) {
errs() << "FATAL: failed to allocate " << size << " bytes\n";
std::terminate();
}
return p;
}
void* CheckedMalloc(size_t size);
/**
* Wrapper around std::realloc that calls std::terminate on out of memory.
@@ -50,14 +33,7 @@ inline void* CheckedMalloc(size_t size) {
* @param size number of bytes to allocate
* @return Pointer to beginning of newly allocated memory.
*/
inline void* CheckedRealloc(void* ptr, size_t size) {
void* p = std::realloc(ptr, size == 0 ? 1 : size);
if (!p) {
errs() << "FATAL: failed to allocate " << size << " bytes\n";
std::terminate();
}
return p;
}
void* CheckedRealloc(void* ptr, size_t size);
} // namespace wpi

View File

@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_RAW_OS_OSTREAM_H
#define LLVM_SUPPORT_RAW_OS_OSTREAM_H
#ifndef WPIUTIL_WPI_RAW_OS_OSTREAM_H
#define WPIUTIL_WPI_RAW_OS_OSTREAM_H
#include "wpi/raw_ostream.h"
#include <iosfwd>

View File

@@ -11,22 +11,32 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_RAW_OSTREAM_H
#define LLVM_SUPPORT_RAW_OSTREAM_H
#ifndef WPIUTIL_WPI_RAW_OSTREAM_H
#define WPIUTIL_WPI_RAW_OSTREAM_H
#include "wpi/ArrayRef.h"
#include "wpi/FileSystem.h"
#include "wpi/SmallVector.h"
#include "wpi/StringRef.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <system_error>
namespace wpi {
class format_object_base;
class FormattedString;
class FormattedNumber;
template <typename T> class SmallVectorImpl;
class FormattedBytes;
namespace sys {
namespace fs {
enum OpenFlags : unsigned;
} // end namespace fs
} // end namespace sys
/// This class implements an extremely fast bulk output stream that can *only*
/// output to a stream. It does not support seeking, reopening, rewinding, line
@@ -34,9 +44,6 @@ template <typename T> class SmallVectorImpl;
/// a chunk at a time.
class raw_ostream {
private:
void operator=(const raw_ostream &) = delete;
raw_ostream(const raw_ostream &) = delete;
/// The buffer is handled in such a way that the buffer is
/// uninitialized, unbuffered, or out of space when OutBufCur >=
/// OutBufEnd. Thus a single comparison suffices to determine if we
@@ -66,7 +73,7 @@ private:
public:
// color order matches ANSI escape sequence, don't change
enum Colors {
BLACK=0,
BLACK = 0,
RED,
GREEN,
YELLOW,
@@ -83,6 +90,9 @@ public:
OutBufStart = OutBufEnd = OutBufCur = nullptr;
}
raw_ostream(const raw_ostream &) = delete;
void operator=(const raw_ostream &) = delete;
virtual ~raw_ostream();
/// tell - Return the current offset with the file.
@@ -196,7 +206,7 @@ public:
return write(Str.data(), Str.length());
}
raw_ostream &operator<<(const wpi::SmallVectorImpl<char> &Str) {
raw_ostream &operator<<(const SmallVectorImpl<char> &Str) {
return write(Str.data(), Str.size());
}
@@ -205,7 +215,7 @@ public:
return write(Arr.data(), Arr.size());
}
raw_ostream &operator<<(const wpi::SmallVectorImpl<uint8_t> &Arr) {
raw_ostream &operator<<(const SmallVectorImpl<uint8_t> &Arr) {
return write(Arr.data(), Arr.size());
}
@@ -214,6 +224,7 @@ public:
raw_ostream &operator<<(unsigned long long N);
raw_ostream &operator<<(long long N);
raw_ostream &operator<<(const void *P);
raw_ostream &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long>(N));
}
@@ -246,9 +257,15 @@ public:
// Formatted output, see the formatHex() function in Support/Format.h.
raw_ostream &operator<<(const FormattedNumber &);
// Formatted output, see the format_bytes() function in Support/Format.h.
raw_ostream &operator<<(const FormattedBytes &);
/// indent - Insert 'NumSpaces' spaces.
raw_ostream &indent(unsigned NumSpaces);
/// write_zeros - Insert 'NumZeros' nulls.
raw_ostream &write_zeros(unsigned NumZeros);
/// Changes the foreground color of text that will be output from this point
/// forward.
/// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
@@ -336,6 +353,8 @@ private:
/// Copy data into the buffer. Size must not be greater than the number of
/// unused bytes in the buffer.
void copy_to_buffer(const char *Ptr, size_t Size);
virtual void anchor();
};
/// An abstract base class for streams implementations that also support a
@@ -343,6 +362,7 @@ private:
/// but needs to patch in a header that needs to know the output size.
class raw_pwrite_stream : public raw_ostream {
virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0;
void anchor() override;
public:
explicit raw_pwrite_stream(bool Unbuffered = false)
@@ -369,9 +389,7 @@ class raw_fd_ostream : public raw_pwrite_stream {
int FD;
bool ShouldClose;
/// Error This flag is true if an error of any kind has been detected.
///
bool Error;
std::error_code EC;
uint64_t pos;
@@ -390,7 +408,9 @@ class raw_fd_ostream : public raw_pwrite_stream {
size_t preferred_buffer_size() const override;
/// Set the flag indicating that an output error has been encountered.
void error_detected() { Error = true; }
void error_detected(std::error_code EC) { this->EC = EC; }
void anchor() override;
public:
/// Open the specified file for writing. If an error occurs, information
@@ -422,13 +442,13 @@ public:
/// to the offset specified from the beginning of the file.
uint64_t seek(uint64_t off);
std::error_code error() const { return EC; }
/// Return the value of the flag in this raw_fd_ostream indicating whether an
/// output error has been encountered.
/// This doesn't implicitly flush any pending output. Also, it doesn't
/// guarantee to detect all errors unless the stream has been closed.
bool has_error() const {
return Error;
}
bool has_error() const { return bool(EC); }
/// Set the flag read by has_error() to false. If the error flag is set at the
/// time when this raw_ostream's destructor is called, report_fatal_error is
@@ -439,9 +459,7 @@ public:
/// Unless explicitly silenced."
/// - from The Zen of Python, by Tim Peters
///
void clear_error() {
Error = false;
}
void clear_error() { EC = std::error_code(); }
};
/// This returns a reference to a raw_ostream for standard output. Use it like:
@@ -507,7 +525,8 @@ public:
explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
SetUnbuffered();
}
~raw_svector_ostream() override {}
~raw_svector_ostream() override = default;
void flush() = delete;
@@ -539,7 +558,8 @@ public:
explicit raw_vector_ostream(std::vector<char> &O) : OS(O) {
SetUnbuffered();
}
~raw_vector_ostream() override {}
~raw_vector_ostream() override = default;
void flush() = delete;
@@ -571,7 +591,8 @@ public:
explicit raw_usvector_ostream(SmallVectorImpl<uint8_t> &O) : OS(O) {
SetUnbuffered();
}
~raw_usvector_ostream() override {}
~raw_usvector_ostream() override = default;
void flush() = delete;
@@ -603,7 +624,8 @@ public:
explicit raw_uvector_ostream(std::vector<uint8_t> &O) : OS(O) {
SetUnbuffered();
}
~raw_uvector_ostream() override {}
~raw_uvector_ostream() override = default;
void flush() = delete;
@@ -623,7 +645,7 @@ class raw_null_ostream : public raw_pwrite_stream {
uint64_t current_pos() const override;
public:
explicit raw_null_ostream() {}
explicit raw_null_ostream() = default;
~raw_null_ostream() override;
};
@@ -636,6 +658,6 @@ public:
~buffer_ostream() override { OS << str(); }
};
} // end wpi namespace
} // end namespace wpi
#endif // LLVM_SUPPORT_RAW_OSTREAM_H

View File

@@ -11,13 +11,17 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_TYPE_TRAITS_H
#define LLVM_SUPPORT_TYPE_TRAITS_H
#ifndef WPIUTIL_WPI_TYPE_TRAITS_H
#define WPIUTIL_WPI_TYPE_TRAITS_H
#include "wpi/Compiler.h"
#include <type_traits>
#include <utility>
#include "wpi/Compiler.h"
#ifndef __has_feature
#define WPI_DEFINED_HAS_FEATURE
#define __has_feature(x) 0
#endif
namespace wpi {
@@ -46,11 +50,11 @@ struct isPodLike {
// std::pair's are pod-like if their elements are.
template<typename T, typename U>
struct isPodLike<std::pair<T, U> > {
struct isPodLike<std::pair<T, U>> {
static const bool value = isPodLike<T>::value && isPodLike<U>::value;
};
/// \brief Metafunction that determines whether the given type is either an
/// Metafunction that determines whether the given type is either an
/// integral type or an enumeration type, including enum classes.
///
/// Note that this accepts potentially more integral types than is_integral
@@ -58,7 +62,7 @@ struct isPodLike<std::pair<T, U> > {
/// Also note that enum classes aren't implicitly convertible to integral types,
/// the value may therefore need to be explicitly converted before being used.
template <typename T> class is_integral_or_enum {
typedef typename std::remove_reference<T>::type UnderlyingT;
using UnderlyingT = typename std::remove_reference<T>::type;
public:
static const bool value =
@@ -69,27 +73,53 @@ public:
std::is_convertible<UnderlyingT, unsigned long long>::value);
};
/// \brief If T is a pointer, just return it. If it is not, return T&.
/// If T is a pointer, just return it. If it is not, return T&.
template<typename T, typename Enable = void>
struct add_lvalue_reference_if_not_pointer { typedef T &type; };
struct add_lvalue_reference_if_not_pointer { using type = T &; };
template <typename T>
struct add_lvalue_reference_if_not_pointer<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
typedef T type;
using type = T;
};
/// \brief If T is a pointer to X, return a pointer to const X. If it is not,
/// If T is a pointer to X, return a pointer to const X. If it is not,
/// return const T.
template<typename T, typename Enable = void>
struct add_const_past_pointer { typedef const T type; };
struct add_const_past_pointer { using type = const T; };
template <typename T>
struct add_const_past_pointer<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
typedef const typename std::remove_pointer<T>::type *type;
using type = const typename std::remove_pointer<T>::type *;
};
template <typename T, typename Enable = void>
struct const_pointer_or_const_ref {
using type = const T &;
};
template <typename T>
struct const_pointer_or_const_ref<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
using type = typename add_const_past_pointer<T>::type;
};
} // namespace wpi
// If the compiler supports detecting whether a class is final, define
// an LLVM_IS_FINAL macro. If it cannot be defined properly, this
// macro will be left undefined.
#ifndef LLVM_IS_FINAL
#if __cplusplus >= 201402L || defined(_MSC_VER)
#define LLVM_IS_FINAL(Ty) std::is_final<Ty>()
#elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0)
#define LLVM_IS_FINAL(Ty) __is_final(Ty)
#endif
#endif
#ifdef WPI_DEFINED_HAS_FEATURE
#undef __has_feature
#undef WPI_DEFINED_HAS_FEATURE
#endif
#endif // LLVM_SUPPORT_TYPE_TRAITS_H