mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
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:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]));
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
264
wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
Normal file
264
wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
Normal 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;
|
||||
}
|
||||
@@ -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 ¤t_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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
43
wpiutil/src/main/native/cpp/memory.cpp
Normal file
43
wpiutil/src/main/native/cpp/memory.cpp
Normal 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
|
||||
@@ -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";
|
||||
|
||||
@@ -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>)> {
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
291
wpiutil/src/main/native/include/wpi/ErrorOr.h
Normal file
291
wpiutil/src/main/native/include/wpi/ErrorOr.h
Normal 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
|
||||
@@ -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 ¤t_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 ¤t_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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
49
wpiutil/src/main/native/include/wpi/NativeFormatting.h
Normal file
49
wpiutil/src/main/native/include/wpi/NativeFormatting.h
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
339
wpiutil/src/main/native/include/wpi/iterator.h
Normal file
339
wpiutil/src/main/native/include/wpi/iterator.h
Normal 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
|
||||
@@ -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().
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user