Update LLVM to latest upstream. (#1080)

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -39,6 +39,7 @@ SOFTWARE.
#include <cstdlib>
#include "wpi/Format.h"
#include "wpi/SmallString.h"
#include "wpi/raw_istream.h"
#include "wpi/raw_ostream.h"
@@ -1604,7 +1605,7 @@ void json::parser::parse_internal(bool keep, json& result)
if (keep and keep_tag and not value.is_discarded())
{
result.m_value.object->emplace_second(StringRef(key.data(), key.size()), std::move(value));
result.m_value.object->try_emplace(StringRef(key.data(), key.size()), std::move(value));
}
// comma -> next value

View File

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

View File

@@ -0,0 +1,264 @@
//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "wpi/NativeFormatting.h"
#include "wpi/ArrayRef.h"
#include "wpi/SmallString.h"
#include "wpi/StringExtras.h"
#include "wpi/Format.h"
#include <float.h>
using namespace wpi;
template<typename T, std::size_t N>
static int format_to_buffer(T Value, char (&Buffer)[N]) {
char *EndPtr = std::end(Buffer);
char *CurPtr = EndPtr;
do {
*--CurPtr = '0' + char(Value % 10);
Value /= 10;
} while (Value);
return EndPtr - CurPtr;
}
static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
assert(!Buffer.empty());
ArrayRef<char> ThisGroup;
int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
ThisGroup = Buffer.take_front(InitialDigits);
S.write(ThisGroup.data(), ThisGroup.size());
Buffer = Buffer.drop_front(InitialDigits);
assert(Buffer.size() % 3 == 0);
while (!Buffer.empty()) {
S << ',';
ThisGroup = Buffer.take_front(3);
S.write(ThisGroup.data(), 3);
Buffer = Buffer.drop_front(3);
}
}
template <typename T>
static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
IntegerStyle Style, bool IsNegative) {
static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
char NumberBuffer[128];
std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
size_t Len = 0;
Len = format_to_buffer(N, NumberBuffer);
if (IsNegative)
S << '-';
if (Len < MinDigits && Style != IntegerStyle::Number) {
for (size_t I = Len; I < MinDigits; ++I)
S << '0';
}
if (Style == IntegerStyle::Number) {
writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
} else {
S.write(std::end(NumberBuffer) - Len, Len);
}
}
template <typename T>
static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
IntegerStyle Style, bool IsNegative = false) {
// Output using 32-bit div/mod if possible.
if (N == static_cast<uint32_t>(N))
write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
IsNegative);
else
write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
}
template <typename T>
static void write_signed(raw_ostream &S, T N, size_t MinDigits,
IntegerStyle Style) {
static_assert(std::is_signed<T>::value, "Value is not signed!");
using UnsignedT = typename std::make_unsigned<T>::type;
if (N >= 0) {
write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
return;
}
UnsignedT UN = -(UnsignedT)N;
write_unsigned(S, UN, MinDigits, Style, true);
}
void wpi::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
IntegerStyle Style) {
write_unsigned(S, N, MinDigits, Style);
}
void wpi::write_integer(raw_ostream &S, int N, size_t MinDigits,
IntegerStyle Style) {
write_signed(S, N, MinDigits, Style);
}
void wpi::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
IntegerStyle Style) {
write_unsigned(S, N, MinDigits, Style);
}
void wpi::write_integer(raw_ostream &S, long N, size_t MinDigits,
IntegerStyle Style) {
write_signed(S, N, MinDigits, Style);
}
void wpi::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
IntegerStyle Style) {
write_unsigned(S, N, MinDigits, Style);
}
void wpi::write_integer(raw_ostream &S, long long N, size_t MinDigits,
IntegerStyle Style) {
write_signed(S, N, MinDigits, Style);
}
void wpi::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
Optional<size_t> Width) {
const size_t kMaxWidth = 128u;
size_t W = std::min(kMaxWidth, Width.getValueOr(0u));
unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
bool Prefix = (Style == HexPrintStyle::PrefixLower ||
Style == HexPrintStyle::PrefixUpper);
bool Upper =
(Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
unsigned PrefixChars = Prefix ? 2 : 0;
unsigned NumChars =
std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
char NumberBuffer[kMaxWidth];
::memset(NumberBuffer, '0', wpi::array_lengthof(NumberBuffer));
if (Prefix)
NumberBuffer[1] = 'x';
char *EndPtr = NumberBuffer + NumChars;
char *CurPtr = EndPtr;
while (N) {
unsigned char x = static_cast<unsigned char>(N) % 16;
*--CurPtr = hexdigit(x, !Upper);
N /= 16;
}
S.write(NumberBuffer, NumChars);
}
void wpi::write_double(raw_ostream &S, double N, FloatStyle Style,
Optional<size_t> Precision) {
size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
if (std::isnan(N)) {
S << "nan";
return;
} else if (std::isinf(N)) {
S << "INF";
return;
}
char Letter;
if (Style == FloatStyle::Exponent)
Letter = 'e';
else if (Style == FloatStyle::ExponentUpper)
Letter = 'E';
else
Letter = 'f';
SmallString<8> Spec;
wpi::raw_svector_ostream Out(Spec);
Out << "%." << Prec << Letter;
if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
#ifdef _WIN32
// On MSVCRT and compatible, output of %e is incompatible to Posix
// by default. Number of exponent digits should be at least 2. "%+03d"
// FIXME: Implement our formatter to here or Support/Format.h!
#if defined(__MINGW32__)
// FIXME: It should be generic to C++11.
if (N == 0.0 && std::signbit(N)) {
char NegativeZero[] = "-0.000000e+00";
if (Style == FloatStyle::ExponentUpper)
NegativeZero[strlen(NegativeZero) - 4] = 'E';
S << NegativeZero;
return;
}
#else
int fpcl = _fpclass(N);
// negative zero
if (fpcl == _FPCLASS_NZ) {
char NegativeZero[] = "-0.000000e+00";
if (Style == FloatStyle::ExponentUpper)
NegativeZero[strlen(NegativeZero) - 4] = 'E';
S << NegativeZero;
return;
}
#endif
char buf[32];
unsigned len;
len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
if (len <= sizeof(buf) - 2) {
if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
buf[len - 3] == '0') {
int cs = buf[len - 4];
if (cs == '+' || cs == '-') {
int c1 = buf[len - 2];
int c0 = buf[len - 1];
if (isdigit(static_cast<unsigned char>(c1)) &&
isdigit(static_cast<unsigned char>(c0))) {
// Trim leading '0': "...e+012" -> "...e+12\0"
buf[len - 3] = c1;
buf[len - 2] = c0;
buf[--len] = 0;
}
}
}
S << buf;
return;
}
#endif
}
if (Style == FloatStyle::Percent)
N *= 100.0;
char Buf[32];
format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
S << Buf;
if (Style == FloatStyle::Percent)
S << '%';
}
bool wpi::isPrefixedHexStyle(HexPrintStyle S) {
return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
}
size_t wpi::getDefaultPrecision(FloatStyle Style) {
switch (Style) {
case FloatStyle::Exponent:
case FloatStyle::ExponentUpper:
return 6; // Number of decimal places.
case FloatStyle::Fixed:
case FloatStyle::Percent:
return 2; // Number of decimal places.
}
LLVM_BUILTIN_UNREACHABLE;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,9 +9,11 @@
#include "wpi/StringRef.h"
#include "wpi/Hashing.h"
#include "wpi/StringExtras.h"
#include "wpi/SmallVector.h"
#include <bitset>
#include <climits>
#include <ostream>
using namespace wpi;
@@ -20,28 +22,12 @@ using namespace wpi;
const size_t StringRef::npos;
#endif
static char ascii_tolower(char x) noexcept {
if (x >= 'A' && x <= 'Z')
return x - 'A' + 'a';
return x;
}
static char ascii_toupper(char x) noexcept {
if (x >= 'a' && x <= 'z')
return x - 'a' + 'A';
return x;
}
static bool ascii_isdigit(char x) noexcept {
return x >= '0' && x <= '9';
}
// strncasecmp() is not available on non-POSIX systems, so define an
// alternative function here.
static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) noexcept {
for (size_t I = 0; I < Length; ++I) {
unsigned char LHC = ascii_tolower(LHS[I]);
unsigned char RHC = ascii_tolower(RHS[I]);
unsigned char LHC = toLower(LHS[I]);
unsigned char RHC = toLower(RHS[I]);
if (LHC != RHC)
return LHC < RHC ? -1 : 1;
}
@@ -50,36 +36,41 @@ static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) no
/// compare_lower - Compare strings, ignoring case.
int StringRef::compare_lower(StringRef RHS) const noexcept {
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(size(), RHS.size())))
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(Length, RHS.Length)))
return Res;
if (size() == RHS.size())
if (Length == RHS.Length)
return 0;
return size() < RHS.size() ? -1 : 1;
return Length < RHS.Length ? -1 : 1;
}
/// Check if this string starts with the given \p Prefix, ignoring case.
bool StringRef::startswith_lower(StringRef Prefix) const noexcept {
return size() >= Prefix.size() &&
ascii_strncasecmp(Data, Prefix.Data, Prefix.size()) == 0;
return Length >= Prefix.Length &&
ascii_strncasecmp(Data, Prefix.Data, Prefix.Length) == 0;
}
/// Check if this string ends with the given \p Suffix, ignoring case.
bool StringRef::endswith_lower(StringRef Suffix) const noexcept {
return size() >= Suffix.size() &&
ascii_strncasecmp(end() - Suffix.size(), Suffix.Data, Suffix.size()) == 0;
return Length >= Suffix.Length &&
ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
}
size_t StringRef::find_lower(char C, size_t From) const noexcept {
char L = toLower(C);
return find_if([L](char D) { return toLower(D) == L; }, From);
}
/// compare_numeric - Compare strings, handle embedded numbers.
int StringRef::compare_numeric(StringRef RHS) const noexcept {
for (size_t I = 0, E = std::min(size(), RHS.size()); I != E; ++I) {
for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) {
// Check for sequences of digits.
if (ascii_isdigit(Data[I]) && ascii_isdigit(RHS.Data[I])) {
if (isDigit(Data[I]) && isDigit(RHS.Data[I])) {
// The longer sequence of numbers is considered larger.
// This doesn't really handle prefixed zeros well.
size_t J;
for (J = I + 1; J != E + 1; ++J) {
bool ld = J < size() && ascii_isdigit(Data[J]);
bool rd = J < RHS.size() && ascii_isdigit(RHS.Data[J]);
bool ld = J < Length && isDigit(Data[J]);
bool rd = J < RHS.Length && isDigit(RHS.Data[J]);
if (ld != rd)
return rd ? -1 : 1;
if (!rd)
@@ -95,9 +86,9 @@ int StringRef::compare_numeric(StringRef RHS) const noexcept {
if (Data[I] != RHS.Data[I])
return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1;
}
if (size() == RHS.size())
if (Length == RHS.Length)
return 0;
return size() < RHS.size() ? -1 : 1;
return Length < RHS.Length ? -1 : 1;
}
//===----------------------------------------------------------------------===//
@@ -107,7 +98,7 @@ int StringRef::compare_numeric(StringRef RHS) const noexcept {
std::string StringRef::lower() const {
std::string Result(size(), char());
for (size_type i = 0, e = size(); i != e; ++i) {
Result[i] = ascii_tolower(Data[i]);
Result[i] = toLower(Data[i]);
}
return Result;
}
@@ -115,25 +106,11 @@ std::string StringRef::lower() const {
std::string StringRef::upper() const {
std::string Result(size(), char());
for (size_type i = 0, e = size(); i != e; ++i) {
Result[i] = ascii_toupper(Data[i]);
Result[i] = toUpper(Data[i]);
}
return Result;
}
const char *StringRef::c_str(wpi::SmallVectorImpl<char>& buf) const {
if (is_null_terminated()) {
// If null terminated, return data directly
return data();
} else {
// If not null terminated, use SmallVectorImpl to store data
// copy data, and return a known null terminated string
buf.clear();
buf.append(begin(), end());
buf.push_back(0);
return buf.begin();
}
}
//===----------------------------------------------------------------------===//
// String Searching
//===----------------------------------------------------------------------===//
@@ -144,19 +121,23 @@ const char *StringRef::c_str(wpi::SmallVectorImpl<char>& buf) const {
/// \return - The index of the first occurrence of \arg Str, or npos if not
/// found.
size_t StringRef::find(StringRef Str, size_t From) const noexcept {
if (From > size())
if (From > Length)
return npos;
const char *Start = Data + From;
size_t Size = Length - From;
const char *Needle = Str.data();
size_t N = Str.size();
if (N == 0)
return From;
size_t Size = size() - From;
if (Size < N)
return npos;
if (N == 1) {
const char *Ptr = (const char *)::memchr(Start, Needle[0], Size);
return Ptr == nullptr ? npos : Ptr - Data;
}
const char *Start = Data + From;
const char *Stop = Start + (Size - N + 1);
// For short haystacks or unsupported needles fall back to the naive algorithm
@@ -176,25 +157,49 @@ size_t StringRef::find(StringRef Str, size_t From) const noexcept {
BadCharSkip[(uint8_t)Str[i]] = N-1-i;
do {
if (std::memcmp(Start, Needle, N) == 0)
return Start - Data;
uint8_t Last = Start[N - 1];
if (LLVM_UNLIKELY(Last == (uint8_t)Needle[N - 1]))
if (std::memcmp(Start, Needle, N - 1) == 0)
return Start - Data;
// Otherwise skip the appropriate number of bytes.
Start += BadCharSkip[(uint8_t)Start[N-1]];
Start += BadCharSkip[Last];
} while (Start < Stop);
return npos;
}
size_t StringRef::find_lower(StringRef Str, size_t From) const noexcept {
StringRef This = substr(From);
while (This.size() >= Str.size()) {
if (This.startswith_lower(Str))
return From;
This = This.drop_front();
++From;
}
return npos;
}
size_t StringRef::rfind_lower(char C, size_t From) const noexcept {
From = std::min(From, Length);
size_t i = From;
while (i != 0) {
--i;
if (toLower(Data[i]) == toLower(C))
return i;
}
return npos;
}
/// rfind - Search for the last string \arg Str in the string.
///
/// \return - The index of the last occurrence of \arg Str, or npos if not
/// found.
size_t StringRef::rfind(StringRef Str) const noexcept {
size_t N = Str.size();
if (N > size())
if (N > Length)
return npos;
for (size_t i = size() - N + 1, e = 0; i != e;) {
for (size_t i = Length - N + 1, e = 0; i != e;) {
--i;
if (substr(i, N).equals(Str))
return i;
@@ -202,6 +207,18 @@ size_t StringRef::rfind(StringRef Str) const noexcept {
return npos;
}
size_t StringRef::rfind_lower(StringRef Str) const noexcept {
size_t N = Str.size();
if (N > Length)
return npos;
for (size_t i = Length - N + 1, e = 0; i != e;) {
--i;
if (substr(i, N).equals_lower(Str))
return i;
}
return npos;
}
/// find_first_of - Find the first character in the string that is in \arg
/// Chars, or npos if not found.
///
@@ -212,7 +229,7 @@ StringRef::size_type StringRef::find_first_of(StringRef Chars,
for (size_type i = 0; i != Chars.size(); ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()), e = size(); i != e; ++i)
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
if (CharBits.test((unsigned char)Data[i]))
return i;
return npos;
@@ -221,7 +238,7 @@ StringRef::size_type StringRef::find_first_of(StringRef Chars,
/// find_first_not_of - Find the first character in the string that is not
/// \arg C or npos if not found.
StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const noexcept {
for (size_type i = std::min(From, size()), e = size(); i != e; ++i)
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
if (Data[i] != C)
return i;
return npos;
@@ -237,7 +254,7 @@ StringRef::size_type StringRef::find_first_not_of(StringRef Chars,
for (size_type i = 0; i != Chars.size(); ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()), e = size(); i != e; ++i)
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
if (!CharBits.test((unsigned char)Data[i]))
return i;
return npos;
@@ -253,7 +270,7 @@ StringRef::size_type StringRef::find_last_of(StringRef Chars,
for (size_type i = 0; i != Chars.size(); ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --i)
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
if (CharBits.test((unsigned char)Data[i]))
return i;
return npos;
@@ -262,7 +279,7 @@ StringRef::size_type StringRef::find_last_of(StringRef Chars,
/// find_last_not_of - Find the last character in the string that is not
/// \arg C, or npos if not found.
StringRef::size_type StringRef::find_last_not_of(char C, size_t From) const noexcept {
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --i)
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
if (Data[i] != C)
return i;
return npos;
@@ -278,7 +295,7 @@ StringRef::size_type StringRef::find_last_not_of(StringRef Chars,
for (size_type i = 0, e = Chars.size(); i != e; ++i)
CharBits.set((unsigned char)Chars[i]);
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --i)
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
if (!CharBits.test((unsigned char)Data[i]))
return i;
return npos;
@@ -346,15 +363,18 @@ void StringRef::split(SmallVectorImpl<StringRef> &A, char Separator,
size_t StringRef::count(StringRef Str) const noexcept {
size_t Count = 0;
size_t N = Str.size();
if (N > size())
if (N > Length)
return 0;
for (size_t i = 0, e = size() - N + 1; i != e; ++i)
for (size_t i = 0, e = Length - N + 1; i != e; ++i)
if (substr(i, N).equals(Str))
++Count;
return Count;
}
static unsigned GetAutoSenseRadix(StringRef &Str) noexcept {
if (Str.empty())
return 10;
if (Str.startswith("0x") || Str.startswith("0X")) {
Str = Str.substr(2);
return 16;
@@ -370,17 +390,16 @@ static unsigned GetAutoSenseRadix(StringRef &Str) noexcept {
return 8;
}
if (Str.startswith("0"))
if (Str[0] == '0' && Str.size() > 1 && isDigit(Str[1])) {
Str = Str.substr(1);
return 8;
}
return 10;
}
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
/// sequence of radix up to 36 to an unsigned long long value.
bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
unsigned long long &Result) noexcept {
bool wpi::consumeUnsignedInteger(StringRef &Str, unsigned Radix,
unsigned long long &Result) noexcept {
// Autosense radix if not specified.
if (Radix == 0)
Radix = GetAutoSenseRadix(Str);
@@ -389,44 +408,51 @@ bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
if (Str.empty()) return true;
// Parse all the bytes of the string given this radix. Watch for overflow.
StringRef Str2 = Str;
Result = 0;
while (!Str.empty()) {
while (!Str2.empty()) {
unsigned CharVal;
if (Str[0] >= '0' && Str[0] <= '9')
CharVal = Str[0]-'0';
else if (Str[0] >= 'a' && Str[0] <= 'z')
CharVal = Str[0]-'a'+10;
else if (Str[0] >= 'A' && Str[0] <= 'Z')
CharVal = Str[0]-'A'+10;
if (Str2[0] >= '0' && Str2[0] <= '9')
CharVal = Str2[0] - '0';
else if (Str2[0] >= 'a' && Str2[0] <= 'z')
CharVal = Str2[0] - 'a' + 10;
else if (Str2[0] >= 'A' && Str2[0] <= 'Z')
CharVal = Str2[0] - 'A' + 10;
else
return true;
break;
// If the parsed value is larger than the integer radix, the string is
// invalid.
// If the parsed value is larger than the integer radix, we cannot
// consume any more characters.
if (CharVal >= Radix)
return true;
break;
// Add in this character.
unsigned long long PrevResult = Result;
Result = Result*Radix+CharVal;
Result = Result * Radix + CharVal;
// Check for overflow by shifting back and seeing if bits were lost.
if (Result/Radix < PrevResult)
if (Result / Radix < PrevResult)
return true;
Str = Str.substr(1);
Str2 = Str2.substr(1);
}
// We consider the operation a failure if no characters were consumed
// successfully.
if (Str.size() == Str2.size())
return true;
Str = Str2;
return false;
}
bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
long long &Result) noexcept {
bool wpi::consumeSignedInteger(StringRef &Str, unsigned Radix,
long long &Result) noexcept {
unsigned long long ULLVal;
// Handle positive strings first.
if (Str.empty() || Str.front() != '-') {
if (getAsUnsignedInteger(Str, Radix, ULLVal) ||
if (consumeUnsignedInteger(Str, Radix, ULLVal) ||
// Check for value so large it overflows a signed value.
(long long)ULLVal < 0)
return true;
@@ -435,17 +461,46 @@ bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
}
// Get the positive part of the value.
if (getAsUnsignedInteger(Str.substr(1), Radix, ULLVal) ||
StringRef Str2 = Str.drop_front(1);
if (consumeUnsignedInteger(Str2, Radix, ULLVal) ||
// Reject values so large they'd overflow as negative signed, but allow
// "-0". This negates the unsigned so that the negative isn't undefined
// on signed overflow.
(long long)-ULLVal > 0)
return true;
Str = Str2;
Result = -ULLVal;
return false;
}
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
/// sequence of radix up to 36 to an unsigned long long value.
bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
unsigned long long &Result) noexcept {
if (consumeUnsignedInteger(Str, Radix, Result))
return true;
// For getAsUnsignedInteger, we require the whole string to be consumed or
// else we consider it a failure.
return !Str.empty();
}
bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
long long &Result) noexcept {
if (consumeSignedInteger(Str, Radix, Result))
return true;
// For getAsSignedInteger, we require the whole string to be consumed or else
// we consider it a failure.
return !Str.empty();
}
std::ostream &wpi::operator<<(std::ostream &os, StringRef string) {
os.write(string.data(), string.size());
return os;
}
// Implementation of StringRef hashing.
hash_code wpi::hash_value(StringRef S) {
return hash_combine_range(S.begin(), S.end());

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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