mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-06 03:31:43 +00:00
[wpiutil] Separate third party libraries (#4190)
This commit is contained in:
833
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
vendored
Normal file
833
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
vendored
Normal file
@@ -0,0 +1,833 @@
|
||||
/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
|
||||
*
|
||||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
* See https://llvm.org/LICENSE.txt for license information.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*
|
||||
*===------------------------------------------------------------------------=*/
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Sept 2001: fixed const & error conditions per
|
||||
mods suggested by S. Parent & A. Lillich.
|
||||
June 2002: Tim Dodd added detection and handling of incomplete
|
||||
source sequences, enhanced error detection, added casts
|
||||
to eliminate compiler warnings.
|
||||
July 2003: slight mods to back out aggressive FFFE detection.
|
||||
Jan 2004: updated switches in from-UTF8 conversions.
|
||||
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
|
||||
|
||||
See the header file "ConvertUTF.h" for complete documentation.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#ifdef CVTUTF_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "Windows/WindowsSupport.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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;
|
||||
static const UTF32 halfMask = 0x3FFUL;
|
||||
|
||||
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
||||
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
||||
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
||||
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||
* get the number of trailing bytes that are supposed to follow it.
|
||||
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
||||
* left as-is for anyone who may want to do such conversion, which was
|
||||
* allowed in earlier algorithms.
|
||||
*/
|
||||
static const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||
* This table contains as many values as there might be trailing bytes
|
||||
* in a UTF-8 sequence.
|
||||
*/
|
||||
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
||||
|
||||
/*
|
||||
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
|
||||
* into the first byte, depending on how many bytes follow. There are
|
||||
* as many entries in this table as there are UTF-8 sequence types.
|
||||
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
|
||||
* for *legal* UTF-8 will be 4 or fewer bytes total.
|
||||
*/
|
||||
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* The interface converts a whole buffer to avoid function-call overhead.
|
||||
* Constants have been gathered. Loops & conditionals have been removed as
|
||||
* much as possible for efficiency, in favor of drop-through switches.
|
||||
* (See "Note A" at the bottom of the file for equivalent code.)
|
||||
* If your compiler supports it, the "isLegalUTF8" call can be turned
|
||||
* into an inline function.
|
||||
*/
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
if (target >= targetEnd) {
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch = *source++;
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_LEGAL_UTF32) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
UTF32 ch, ch2;
|
||||
while (source < sourceEnd) {
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target >= targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
*target++ = ch;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
#ifdef CVTUTF_DEBUG
|
||||
if (result == sourceIllegal) {
|
||||
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
UTF32 ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Figure out how many bytes the result will require */
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
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;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
ch = *source++;
|
||||
if (flags == strictConversion ) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Figure out how many bytes the result will require. Turn any
|
||||
* illegally large UTF32 things (> Plane 17) into replacement chars.
|
||||
*/
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
result = sourceIllegal;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
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;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
||||
* This must be called with the length pre-determined by the first byte.
|
||||
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
||||
* length = trailingBytesForUTF8[*source]+1;
|
||||
* and the sequence is illegal right away if there aren't that many bytes
|
||||
* available.
|
||||
* If presented with a length > 4, this returns false. The Unicode
|
||||
* definition of UTF-8 goes up to 4-byte sequences.
|
||||
*/
|
||||
|
||||
static Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||
UTF8 a;
|
||||
const UTF8 *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return false;
|
||||
/* Everything else falls through when "true"... */
|
||||
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) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return false; break;
|
||||
case 0xED: if (a > 0x9F) return false; break;
|
||||
case 0xF0: if (a < 0x90) return false; break;
|
||||
case 0xF4: if (a > 0x8F) return false; break;
|
||||
default: if (a < 0x80) return false;
|
||||
}
|
||||
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||
}
|
||||
if (*source > 0xF4) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 sequence is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
|
||||
int length = trailingBytesForUTF8[*source]+1;
|
||||
if (length > sourceEnd - source) {
|
||||
return false;
|
||||
}
|
||||
return isLegalUTF8(source, length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static unsigned
|
||||
findMaximalSubpartOfIllFormedUTF8Sequence(const UTF8 *source,
|
||||
const UTF8 *sourceEnd) {
|
||||
UTF8 b1, b2, b3;
|
||||
|
||||
assert(!isLegalUTF8Sequence(source, sourceEnd));
|
||||
|
||||
/*
|
||||
* Unicode 6.3.0, D93b:
|
||||
*
|
||||
* Maximal subpart of an ill-formed subsequence: The longest code unit
|
||||
* subsequence starting at an unconvertible offset that is either:
|
||||
* a. the initial subsequence of a well-formed code unit sequence, or
|
||||
* b. a subsequence of length one.
|
||||
*/
|
||||
|
||||
if (source == sourceEnd)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Perform case analysis. See Unicode 6.3.0, Table 3-7. Well-Formed UTF-8
|
||||
* Byte Sequences.
|
||||
*/
|
||||
|
||||
b1 = *source;
|
||||
++source;
|
||||
if (b1 >= 0xC2 && b1 <= 0xDF) {
|
||||
/*
|
||||
* First byte is valid, but we know that this code unit sequence is
|
||||
* invalid, so the maximal subpart has to end after the first byte.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (source == sourceEnd)
|
||||
return 1;
|
||||
|
||||
b2 = *source;
|
||||
++source;
|
||||
|
||||
if (b1 == 0xE0) {
|
||||
return (b2 >= 0xA0 && b2 <= 0xBF) ? 2 : 1;
|
||||
}
|
||||
if (b1 >= 0xE1 && b1 <= 0xEC) {
|
||||
return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
|
||||
}
|
||||
if (b1 == 0xED) {
|
||||
return (b2 >= 0x80 && b2 <= 0x9F) ? 2 : 1;
|
||||
}
|
||||
if (b1 >= 0xEE && b1 <= 0xEF) {
|
||||
return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
|
||||
}
|
||||
if (b1 == 0xF0) {
|
||||
if (b2 >= 0x90 && b2 <= 0xBF) {
|
||||
if (source == sourceEnd)
|
||||
return 2;
|
||||
|
||||
b3 = *source;
|
||||
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (b1 >= 0xF1 && b1 <= 0xF3) {
|
||||
if (b2 >= 0x80 && b2 <= 0xBF) {
|
||||
if (source == sourceEnd)
|
||||
return 2;
|
||||
|
||||
b3 = *source;
|
||||
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (b1 == 0xF4) {
|
||||
if (b2 >= 0x80 && b2 <= 0x8F) {
|
||||
if (source == sourceEnd)
|
||||
return 2;
|
||||
|
||||
b3 = *source;
|
||||
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert((b1 >= 0x80 && b1 <= 0xC1) || b1 >= 0xF5);
|
||||
/*
|
||||
* There are no valid sequences that start with these bytes. Maximal subpart
|
||||
* is defined to have length 1 in these cases.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return the total number of bytes in a codepoint
|
||||
* represented in UTF-8, given the value of the first byte.
|
||||
*/
|
||||
unsigned getNumBytesForUTF8(UTF8 first) {
|
||||
return trailingBytesForUTF8[first] + 1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 string is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) {
|
||||
while (*source != sourceEnd) {
|
||||
int length = trailingBytesForUTF8[**source] + 1;
|
||||
if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
|
||||
return false;
|
||||
*source += length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (extraBytesToRead >= sourceEnd - source) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (!isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
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];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_UTF16) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
source -= (extraBytesToRead+1); /* return to the start */
|
||||
break; /* Bail out; shouldn't continue */
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static ConversionResult ConvertUTF8toUTF32Impl(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags,
|
||||
Boolean InputIsPartial) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (extraBytesToRead >= sourceEnd - source) {
|
||||
if (flags == strictConversion || InputIsPartial) {
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
} else {
|
||||
result = sourceIllegal;
|
||||
|
||||
/*
|
||||
* Replace the maximal subpart of ill-formed sequence with
|
||||
* replacement character.
|
||||
*/
|
||||
source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
|
||||
sourceEnd);
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (target >= targetEnd) {
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
|
||||
/* Do this check whether lenient or strict */
|
||||
if (!isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
if (flags == strictConversion) {
|
||||
/* Abort conversion. */
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Replace the maximal subpart of ill-formed sequence with
|
||||
* replacement character.
|
||||
*/
|
||||
source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
|
||||
sourceEnd);
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
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];
|
||||
|
||||
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||
/*
|
||||
* UTF-16 surrogate values are illegal in UTF-32, and anything
|
||||
* over Plane 17 (> 0x10FFFF) is illegal.
|
||||
*/
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = ch;
|
||||
}
|
||||
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
|
||||
result = sourceIllegal;
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32Partial(const UTF8 **sourceStart,
|
||||
const UTF8 *sourceEnd,
|
||||
UTF32 **targetStart,
|
||||
UTF32 *targetEnd,
|
||||
ConversionFlags flags) {
|
||||
return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
|
||||
flags, /*InputIsPartial=*/true);
|
||||
}
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
|
||||
const UTF8 *sourceEnd, UTF32 **targetStart,
|
||||
UTF32 *targetEnd, ConversionFlags flags) {
|
||||
return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
|
||||
flags, /*InputIsPartial=*/false);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Note A.
|
||||
The fall-through switches in UTF-8 reading code save a
|
||||
temp variable, some decrements & conditionals. The switches
|
||||
are equivalent to the following loop:
|
||||
{
|
||||
int tmpBytesToRead = extraBytesToRead+1;
|
||||
do {
|
||||
ch += *source++;
|
||||
--tmpBytesToRead;
|
||||
if (tmpBytesToRead) ch <<= 6;
|
||||
} while (tmpBytesToRead > 0);
|
||||
}
|
||||
In UTF-8 writing code, the switches on "bytesToWrite" are
|
||||
similarly unrolled loops.
|
||||
|
||||
--------------------------------------------------------------------- */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace sys {
|
||||
namespace windows {
|
||||
std::error_code CodePageToUTF16(unsigned codepage,
|
||||
std::string_view original,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
if (!original.empty()) {
|
||||
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), 0);
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
|
||||
utf16.reserve(len + 1);
|
||||
utf16.set_size(len);
|
||||
|
||||
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
|
||||
original.size(), utf16.begin(), utf16.size());
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Make utf16 null terminated.
|
||||
utf16.push_back(0);
|
||||
utf16.pop_back();
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code UTF8ToUTF16(std::string_view utf8,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_UTF8, utf8, utf16);
|
||||
}
|
||||
|
||||
std::error_code CurCPToUTF16(std::string_view 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> &converted) {
|
||||
if (utf16_len) {
|
||||
// Get length.
|
||||
int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(),
|
||||
0, NULL, NULL);
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
|
||||
converted.reserve(len);
|
||||
converted.set_size(len);
|
||||
|
||||
// Now do the actual conversion.
|
||||
len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(),
|
||||
converted.size(), NULL, NULL);
|
||||
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Make the new string null terminated.
|
||||
converted.push_back(0);
|
||||
converted.pop_back();
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
|
||||
wpi::SmallVectorImpl<char> &utf8) {
|
||||
return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8);
|
||||
}
|
||||
|
||||
std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
|
||||
wpi::SmallVectorImpl<char> &curcp) {
|
||||
return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp);
|
||||
}
|
||||
|
||||
} // end namespace windows
|
||||
} // end namespace sys
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
ConvertUTF_RESTORE_WARNINGS
|
||||
253
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
vendored
Normal file
253
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/span.h"
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SwapByteOrder.h"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
|
||||
char *&ResultPtr, const UTF8 *&ErrorPtr) {
|
||||
assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
|
||||
ConversionResult result = conversionOK;
|
||||
// Copy the character span over.
|
||||
if (WideCharWidth == 1) {
|
||||
const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.data());
|
||||
if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.data() + Source.size()))) {
|
||||
result = sourceIllegal;
|
||||
ErrorPtr = Pos;
|
||||
} else {
|
||||
memcpy(ResultPtr, Source.data(), Source.size());
|
||||
ResultPtr += Source.size();
|
||||
}
|
||||
} else if (WideCharWidth == 2) {
|
||||
const UTF8 *sourceStart = (const UTF8*)Source.data();
|
||||
// FIXME: Make the type of the result buffer correct instead of
|
||||
// using reinterpret_cast.
|
||||
UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
|
||||
ConversionFlags flags = strictConversion;
|
||||
result = ConvertUTF8toUTF16(
|
||||
&sourceStart, sourceStart + Source.size(),
|
||||
&targetStart, targetStart + Source.size(), flags);
|
||||
if (result == conversionOK)
|
||||
ResultPtr = reinterpret_cast<char*>(targetStart);
|
||||
else
|
||||
ErrorPtr = sourceStart;
|
||||
} else if (WideCharWidth == 4) {
|
||||
const UTF8 *sourceStart = (const UTF8*)Source.data();
|
||||
// FIXME: Make the type of the result buffer correct instead of
|
||||
// using reinterpret_cast.
|
||||
UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
|
||||
ConversionFlags flags = strictConversion;
|
||||
result = ConvertUTF8toUTF32(
|
||||
&sourceStart, sourceStart + Source.size(),
|
||||
&targetStart, targetStart + Source.size(), flags);
|
||||
if (result == conversionOK)
|
||||
ResultPtr = reinterpret_cast<char*>(targetStart);
|
||||
else
|
||||
ErrorPtr = sourceStart;
|
||||
}
|
||||
assert((result != targetExhausted)
|
||||
&& "ConvertUTF8toUTFXX exhausted target buffer");
|
||||
return result == conversionOK;
|
||||
}
|
||||
|
||||
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
|
||||
const UTF32 *SourceStart = &Source;
|
||||
const UTF32 *SourceEnd = SourceStart + 1;
|
||||
UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
|
||||
UTF8 *TargetEnd = TargetStart + 4;
|
||||
ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
|
||||
&TargetStart, TargetEnd,
|
||||
strictConversion);
|
||||
if (CR != conversionOK)
|
||||
return false;
|
||||
|
||||
ResultPtr = reinterpret_cast<char*>(TargetStart);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasUTF16ByteOrderMark(span<const char> S) {
|
||||
return (S.size() >= 2 &&
|
||||
((S[0] == '\xff' && S[1] == '\xfe') ||
|
||||
(S[0] == '\xfe' && S[1] == '\xff')));
|
||||
}
|
||||
|
||||
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
|
||||
assert(Out.empty());
|
||||
|
||||
// Error out on an uneven byte count.
|
||||
if (SrcBytes.size() % 2)
|
||||
return false;
|
||||
|
||||
// Avoid OOB by returning early on empty input.
|
||||
if (SrcBytes.empty())
|
||||
return true;
|
||||
|
||||
const UTF16 *Src = reinterpret_cast<const UTF16 *>(SrcBytes.begin());
|
||||
const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(SrcBytes.end());
|
||||
|
||||
assert((uintptr_t)Src % sizeof(UTF16) == 0);
|
||||
|
||||
// Byteswap if necessary.
|
||||
std::vector<UTF16> ByteSwapped;
|
||||
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
|
||||
ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
|
||||
for (unsigned I = 0, E = ByteSwapped.size(); I != E; ++I)
|
||||
ByteSwapped[I] = wpi::ByteSwap_16(ByteSwapped[I]);
|
||||
Src = &ByteSwapped[0];
|
||||
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
|
||||
}
|
||||
|
||||
// Skip the BOM for conversion.
|
||||
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE)
|
||||
Src++;
|
||||
|
||||
// Just allocate enough space up front. We'll shrink it later. Allocate
|
||||
// enough that we can fit a null terminator without reallocating.
|
||||
Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
|
||||
UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]);
|
||||
UTF8 *DstEnd = Dst + Out.size();
|
||||
|
||||
ConversionResult CR =
|
||||
ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
|
||||
assert(CR != targetExhausted);
|
||||
|
||||
if (CR != conversionOK) {
|
||||
Out.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]);
|
||||
Out.push_back(0);
|
||||
Out.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out)
|
||||
{
|
||||
return convertUTF16ToUTF8String(
|
||||
span<const char>(reinterpret_cast<const char *>(Src.data()),
|
||||
Src.size() * sizeof(UTF16)), Out);
|
||||
}
|
||||
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16) {
|
||||
assert(DstUTF16.empty());
|
||||
|
||||
// Avoid OOB by returning early on empty input.
|
||||
if (SrcUTF8.empty()) {
|
||||
DstUTF16.push_back(0);
|
||||
DstUTF16.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.data());
|
||||
const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.data() + SrcUTF8.size());
|
||||
|
||||
// Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding
|
||||
// as UTF-16 should always require the same amount or less code units than the
|
||||
// UTF-8 encoding. Allocate one extra byte for the null terminator though,
|
||||
// so that someone calling DstUTF16.data() gets a null terminated string.
|
||||
// We resize down later so we don't have to worry that this over allocates.
|
||||
DstUTF16.resize(SrcUTF8.size()+1);
|
||||
UTF16 *Dst = &DstUTF16[0];
|
||||
UTF16 *DstEnd = Dst + DstUTF16.size();
|
||||
|
||||
ConversionResult CR =
|
||||
ConvertUTF8toUTF16(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
|
||||
assert(CR != targetExhausted);
|
||||
|
||||
if (CR != conversionOK) {
|
||||
DstUTF16.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
DstUTF16.resize(Dst - &DstUTF16[0]);
|
||||
DstUTF16.push_back(0);
|
||||
DstUTF16.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(sizeof(wchar_t) == 1 || sizeof(wchar_t) == 2 ||
|
||||
sizeof(wchar_t) == 4,
|
||||
"Expected wchar_t to be 1, 2, or 4 bytes");
|
||||
|
||||
template <typename TResult>
|
||||
static inline bool ConvertUTF8toWideInternal(std::string_view Source,
|
||||
TResult &Result) {
|
||||
// Even in the case of UTF-16, the number of bytes in a UTF-8 string is
|
||||
// at least as large as the number of elements in the resulting wide
|
||||
// string, because surrogate pairs take at least 4 bytes in UTF-8.
|
||||
Result.resize(Source.size() + 1);
|
||||
char *ResultPtr = reinterpret_cast<char *>(&Result[0]);
|
||||
const UTF8 *ErrorPtr;
|
||||
if (!ConvertUTF8toWide(sizeof(wchar_t), Source, ResultPtr, ErrorPtr)) {
|
||||
Result.clear();
|
||||
return false;
|
||||
}
|
||||
Result.resize(reinterpret_cast<wchar_t *>(ResultPtr) - &Result[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result) {
|
||||
return ConvertUTF8toWideInternal(Source, Result);
|
||||
}
|
||||
|
||||
bool ConvertUTF8toWide(const char *Source, std::wstring &Result) {
|
||||
if (!Source) {
|
||||
Result.clear();
|
||||
return true;
|
||||
}
|
||||
return ConvertUTF8toWide(std::string_view(Source), Result);
|
||||
}
|
||||
|
||||
bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result) {
|
||||
if (sizeof(wchar_t) == 1) {
|
||||
const UTF8 *Start = reinterpret_cast<const UTF8 *>(Source.data());
|
||||
const UTF8 *End =
|
||||
reinterpret_cast<const UTF8 *>(Source.data() + Source.size());
|
||||
if (!isLegalUTF8String(&Start, End))
|
||||
return false;
|
||||
Result.resize(Source.size());
|
||||
memcpy(&Result[0], Source.data(), Source.size());
|
||||
return true;
|
||||
} else if (sizeof(wchar_t) == 2) {
|
||||
return convertUTF16ToUTF8String(
|
||||
span<const UTF16>(reinterpret_cast<const UTF16 *>(Source.data()),
|
||||
Source.size()),
|
||||
Result);
|
||||
} else if (sizeof(wchar_t) == 4) {
|
||||
const UTF32 *Start = reinterpret_cast<const UTF32 *>(Source.data());
|
||||
const UTF32 *End =
|
||||
reinterpret_cast<const UTF32 *>(Source.data() + Source.size());
|
||||
Result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * Source.size());
|
||||
UTF8 *ResultPtr = reinterpret_cast<UTF8 *>(&Result[0]);
|
||||
UTF8 *ResultEnd = reinterpret_cast<UTF8 *>(&Result[0] + Result.size());
|
||||
if (ConvertUTF32toUTF8(&Start, End, &ResultPtr, ResultEnd,
|
||||
strictConversion) == conversionOK) {
|
||||
Result.resize(reinterpret_cast<char *>(ResultPtr) - &Result[0]);
|
||||
return true;
|
||||
} else {
|
||||
Result.clear();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
wpi_unreachable(
|
||||
"Control should never reach this point; see static_assert further up");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
240
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ErrorHandling.cpp
vendored
Normal file
240
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ErrorHandling.cpp
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines an API used to indicate fatal error conditions. Non-fatal
|
||||
// errors (most of them) should be handled through LLVMContext.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Errc.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "fmt/format.h"
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
static fatal_error_handler_t ErrorHandler = nullptr;
|
||||
static void *ErrorHandlerUserData = nullptr;
|
||||
|
||||
static fatal_error_handler_t BadAllocErrorHandler = nullptr;
|
||||
static void *BadAllocErrorHandlerUserData = nullptr;
|
||||
|
||||
// Mutexes to synchronize installing error handlers and calling error handlers.
|
||||
// Do not use ManagedStatic, or that may allocate memory while attempting to
|
||||
// report an OOM.
|
||||
//
|
||||
// This usage of std::mutex has to be conditionalized behind ifdefs because
|
||||
// of this script:
|
||||
// compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
|
||||
// That script attempts to statically link the LLVM symbolizer library with the
|
||||
// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
|
||||
// cuts out the threading portions of the hermetic copy of libc++ that it
|
||||
// builds. We can remove these ifdefs if that script goes away.
|
||||
static std::mutex ErrorHandlerMutex;
|
||||
static std::mutex BadAllocErrorHandlerMutex;
|
||||
|
||||
void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
std::scoped_lock Lock(ErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Error handler already registered!\n");
|
||||
ErrorHandler = handler;
|
||||
ErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void wpi::remove_fatal_error_handler() {
|
||||
std::scoped_lock Lock(ErrorHandlerMutex);
|
||||
ErrorHandler = nullptr;
|
||||
ErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const char *Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(std::string_view(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
|
||||
wpi::fatal_error_handler_t handler = nullptr;
|
||||
void* handlerData = nullptr;
|
||||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
std::scoped_lock Lock(ErrorHandlerMutex);
|
||||
handler = ErrorHandler;
|
||||
handlerData = ErrorHandlerUserData;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(handlerData, std::string{Reason}, GenCrashDiag);
|
||||
} else {
|
||||
fmt::print(stderr, "LLVM ERROR: {}\n", Reason);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
|
||||
BadAllocErrorHandler = handler;
|
||||
BadAllocErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void wpi::remove_bad_alloc_error_handler() {
|
||||
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
|
||||
BadAllocErrorHandler = nullptr;
|
||||
BadAllocErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
||||
void wpi::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
|
||||
fatal_error_handler_t Handler = nullptr;
|
||||
void *HandlerData = nullptr;
|
||||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
|
||||
Handler = BadAllocErrorHandler;
|
||||
HandlerData = BadAllocErrorHandlerUserData;
|
||||
}
|
||||
|
||||
if (Handler) {
|
||||
Handler(HandlerData, Reason, GenCrashDiag);
|
||||
wpi_unreachable("bad alloc handler should not return");
|
||||
}
|
||||
|
||||
// Don't call the normal error handler. It may allocate memory. Directly write
|
||||
// an OOM to stderr and abort.
|
||||
const char *OOMMessage = "LLVM ERROR: out of memory\n";
|
||||
const char *Newline = "\n";
|
||||
#ifdef _WIN32
|
||||
(void)!::_write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::_write(2, Reason, strlen(Reason));
|
||||
(void)!::_write(2, Newline, strlen(Newline));
|
||||
#else
|
||||
(void)!::write(2, OOMMessage, strlen(OOMMessage));
|
||||
(void)!::write(2, Reason, strlen(Reason));
|
||||
(void)!::write(2, Newline, strlen(Newline));
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
// Causes crash on allocation failure. It is called prior to the handler set by
|
||||
// 'install_bad_alloc_error_handler'.
|
||||
static void out_of_memory_new_handler() {
|
||||
wpi::report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
|
||||
// Installs new handler that causes crash on allocation failure. It is called by
|
||||
// InitLLVM.
|
||||
void wpi::install_out_of_memory_new_handler() {
|
||||
std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
|
||||
(void)old;
|
||||
assert((old == nullptr || old == out_of_memory_new_handler) &&
|
||||
"new-handler already installed");
|
||||
}
|
||||
|
||||
void wpi::wpi_unreachable_internal(const char *msg, const char *file,
|
||||
unsigned line) {
|
||||
// This code intentionally doesn't call the ErrorHandler callback, because
|
||||
// wpi_unreachable is intended to be used to indicate "impossible"
|
||||
// situations, and not legitimate runtime errors.
|
||||
if (msg)
|
||||
fmt::print(stderr, "{}\n", msg);
|
||||
std::fputs("UNREACHABLE executed", stderr);
|
||||
if (file)
|
||||
fmt::print(stderr, " at {}:{}", file, line);
|
||||
fmt::print(stderr, "{}", "!\n");
|
||||
abort();
|
||||
#ifdef LLVM_BUILTIN_UNREACHABLE
|
||||
// Windows systems and possibly others don't declare abort() to be noreturn,
|
||||
// so use the unreachable builtin to avoid a Clang self-host warning.
|
||||
LLVM_BUILTIN_UNREACHABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <winerror.h>
|
||||
|
||||
// I'd rather not double the line count of the following.
|
||||
#define MAP_ERR_TO_COND(x, y) \
|
||||
case x: \
|
||||
return std::make_error_code(std::errc::y)
|
||||
|
||||
std::error_code wpi::mapWindowsError(unsigned EV) {
|
||||
switch (EV) {
|
||||
MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
|
||||
MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
|
||||
MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
|
||||
MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
|
||||
MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
|
||||
MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
|
||||
MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
|
||||
MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
|
||||
MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
|
||||
MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
|
||||
MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
|
||||
MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
|
||||
MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
|
||||
MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
|
||||
MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
|
||||
MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
|
||||
MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
|
||||
MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
|
||||
MAP_ERR_TO_COND(ERROR_SEEK, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
|
||||
MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
|
||||
MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
|
||||
MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
|
||||
MAP_ERR_TO_COND(WSAEACCES, permission_denied);
|
||||
MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
|
||||
MAP_ERR_TO_COND(WSAEFAULT, bad_address);
|
||||
MAP_ERR_TO_COND(WSAEINTR, interrupted);
|
||||
MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
|
||||
MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
|
||||
MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
|
||||
default:
|
||||
return std::error_code(EV, std::system_category());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
28
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Hashing.cpp
vendored
Normal file
28
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Hashing.cpp
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
//===-------------- lib/Support/Hashing.cpp -------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides implementation bits for the LLVM common hashing
|
||||
// infrastructure. Documentation and most of the other information is in the
|
||||
// header file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/Hashing.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
// Provide a definition and static initializer for the fixed seed. This
|
||||
// initializer should always be zero to ensure its value can never appear to be
|
||||
// non-zero, even during dynamic initialization.
|
||||
uint64_t wpi::hashing::detail::fixed_seed_override = 0;
|
||||
|
||||
// Implement the function for forced setting of the fixed seed.
|
||||
// FIXME: Use atomic operations here so that there is no data race.
|
||||
void wpi::set_fixed_execution_hash_seed(uint64_t fixed_value) {
|
||||
hashing::detail::fixed_seed_override = fixed_value;
|
||||
}
|
||||
77
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ManagedStatic.cpp
vendored
Normal file
77
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ManagedStatic.cpp
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the ManagedStatic class and wpi_shutdown().
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/ManagedStatic.h"
|
||||
#include "wpi/mutex.h"
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
using namespace wpi;
|
||||
|
||||
static const ManagedStaticBase *StaticList = nullptr;
|
||||
|
||||
static wpi::mutex *getManagedStaticMutex() {
|
||||
static wpi::mutex m;
|
||||
return &m;
|
||||
}
|
||||
|
||||
void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
|
||||
void (*Deleter)(void*)) const {
|
||||
assert(Creator);
|
||||
if (1) {
|
||||
std::scoped_lock Lock(*getManagedStaticMutex());
|
||||
|
||||
if (!Ptr.load(std::memory_order_relaxed)) {
|
||||
void *Tmp = Creator();
|
||||
|
||||
Ptr.store(Tmp, std::memory_order_release);
|
||||
DeleterFn = Deleter;
|
||||
|
||||
// Add to list of managed statics.
|
||||
Next = StaticList;
|
||||
StaticList = this;
|
||||
}
|
||||
} else {
|
||||
assert(!Ptr && !DeleterFn && !Next &&
|
||||
"Partially initialized ManagedStatic!?");
|
||||
Ptr = Creator();
|
||||
DeleterFn = Deleter;
|
||||
|
||||
// Add to list of managed statics.
|
||||
Next = StaticList;
|
||||
StaticList = this;
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedStaticBase::destroy() const {
|
||||
assert(DeleterFn && "ManagedStatic not initialized correctly!");
|
||||
assert(StaticList == this &&
|
||||
"Not destroyed in reverse order of construction?");
|
||||
// Unlink from list.
|
||||
StaticList = Next;
|
||||
Next = nullptr;
|
||||
|
||||
// Destroy memory.
|
||||
DeleterFn(Ptr);
|
||||
|
||||
// Cleanup.
|
||||
Ptr = nullptr;
|
||||
DeleterFn = nullptr;
|
||||
}
|
||||
|
||||
/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
|
||||
/// IMPORTANT: it's only safe to call wpi_shutdown() in single thread,
|
||||
/// without any other threads executing LLVM APIs.
|
||||
/// wpi_shutdown() should be the last use of LLVM APIs.
|
||||
void wpi::wpi_shutdown() {
|
||||
while (StaticList)
|
||||
StaticList->destroy();
|
||||
}
|
||||
34
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemAlloc.cpp
vendored
Normal file
34
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemAlloc.cpp
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
//===- MemAlloc.cpp - Memory allocation functions -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
// These are out of line to have __cpp_aligned_new not affect ABI.
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
|
||||
wpi::allocate_buffer(size_t Size, size_t Alignment) {
|
||||
return ::operator new(Size
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
void wpi::deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
|
||||
::operator delete(Ptr
|
||||
#ifdef __cpp_sized_deallocation
|
||||
,
|
||||
Size
|
||||
#endif
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
523
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
vendored
Normal file
523
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MemoryBuffer interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/MemoryBuffer.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// no matching operator delete
|
||||
#pragma warning(disable : 4291)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h> // NOLINT(build/include_order)
|
||||
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <system_error>
|
||||
|
||||
#include "wpi/Errc.h"
|
||||
#include "wpi/Errno.h"
|
||||
#include "wpi/MappedFileRegion.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/SmallVectorMemoryBuffer.h"
|
||||
#include "wpi/fs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wpi/WindowsError.h"
|
||||
#endif
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemoryBuffer implementation itself.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MemoryBuffer::~MemoryBuffer() {}
|
||||
|
||||
/// init - Initialize this MemoryBuffer as a reference to externally allocated
|
||||
/// memory.
|
||||
void MemoryBuffer::Init(const uint8_t* bufStart, const uint8_t* bufEnd) {
|
||||
m_bufferStart = bufStart;
|
||||
m_bufferEnd = bufEnd;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemoryBufferMem implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// CopyStringRef - Copies contents of a StringRef into a block of memory and
|
||||
/// null-terminates it.
|
||||
static void CopyStringView(uint8_t* memory, std::string_view data) {
|
||||
if (!data.empty()) {
|
||||
std::memcpy(memory, data.data(), data.size());
|
||||
}
|
||||
memory[data.size()] = 0; // Null terminate string.
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct NamedBufferAlloc {
|
||||
std::string_view name;
|
||||
explicit NamedBufferAlloc(std::string_view name) : name(name) {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void* operator new(size_t N, NamedBufferAlloc alloc) {
|
||||
uint8_t* mem = static_cast<uint8_t*>(operator new(N + alloc.name.size() + 1));
|
||||
CopyStringView(mem + N, alloc.name);
|
||||
return mem;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
|
||||
template <typename MB>
|
||||
class MemoryBufferMem : public MB {
|
||||
public:
|
||||
explicit MemoryBufferMem(span<const uint8_t> inputData) {
|
||||
MemoryBuffer::Init(inputData.begin(), inputData.end());
|
||||
}
|
||||
|
||||
/// Disable sized deallocation for MemoryBufferMem, because it has
|
||||
/// tail-allocated data.
|
||||
void operator delete(void* p) { ::operator delete(p); } // NOLINT
|
||||
|
||||
std::string_view GetBufferIdentifier() const override {
|
||||
// The name is stored after the class itself.
|
||||
return std::string_view(reinterpret_cast<const char*>(this + 1));
|
||||
}
|
||||
|
||||
MemoryBuffer::BufferKind GetBufferKind() const override {
|
||||
return MemoryBuffer::MemoryBuffer_Malloc;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetFileAux(std::string_view filename,
|
||||
std::error_code& ec, int64_t fileSize,
|
||||
uint64_t mapSize, uint64_t offset);
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(
|
||||
span<const uint8_t> inputData, std::string_view bufferName) {
|
||||
auto* ret = new (NamedBufferAlloc(bufferName))
|
||||
MemoryBufferMem<MemoryBuffer>(inputData);
|
||||
return std::unique_ptr<MemoryBuffer>(ret);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(MemoryBufferRef ref) {
|
||||
return std::unique_ptr<MemoryBuffer>(
|
||||
GetMemBuffer(ref.GetBuffer(), ref.GetBufferIdentifier()));
|
||||
}
|
||||
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetMemBufferCopyImpl(
|
||||
span<const uint8_t> inputData, std::string_view bufferName,
|
||||
std::error_code& ec) {
|
||||
auto buf =
|
||||
WritableMemoryBuffer::GetNewUninitMemBuffer(inputData.size(), bufferName);
|
||||
if (!buf) {
|
||||
ec = make_error_code(errc::not_enough_memory);
|
||||
return nullptr;
|
||||
}
|
||||
std::memcpy(buf->begin(), inputData.data(), inputData.size());
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBufferCopy(
|
||||
span<const uint8_t> inputData, std::string_view bufferName) {
|
||||
std::error_code ec;
|
||||
return GetMemBufferCopyImpl(inputData, bufferName, ec);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFileSlice(
|
||||
std::string_view filePath, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset) {
|
||||
return GetFileAux<MemoryBuffer>(filePath, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemoryBuffer::getFile implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename MB>
|
||||
constexpr auto kMapMode = MappedFileRegion::kReadOnly;
|
||||
template <>
|
||||
constexpr auto kMapMode<MemoryBuffer> = MappedFileRegion::kReadOnly;
|
||||
template <>
|
||||
constexpr auto kMapMode<WritableMemoryBuffer> = MappedFileRegion::kPriv;
|
||||
template <>
|
||||
constexpr auto kMapMode<WriteThroughMemoryBuffer> =
|
||||
MappedFileRegion::kReadWrite;
|
||||
|
||||
/// Memory maps a file descriptor using MappedFileRegion.
|
||||
///
|
||||
/// This handles converting the offset into a legal offset on the platform.
|
||||
template <typename MB>
|
||||
class MemoryBufferMMapFile : public MB {
|
||||
MappedFileRegion m_mfr;
|
||||
|
||||
static uint64_t getLegalMapOffset(uint64_t offset) {
|
||||
return offset & ~(MappedFileRegion::GetAlignment() - 1);
|
||||
}
|
||||
|
||||
static uint64_t getLegalMapSize(uint64_t len, uint64_t offset) {
|
||||
return len + (offset - getLegalMapOffset(offset));
|
||||
}
|
||||
|
||||
const uint8_t* getStart(uint64_t len, uint64_t offset) {
|
||||
return m_mfr.const_data() + (offset - getLegalMapOffset(offset));
|
||||
}
|
||||
|
||||
public:
|
||||
MemoryBufferMMapFile(fs::file_t f, uint64_t len, uint64_t offset,
|
||||
std::error_code& ec)
|
||||
: m_mfr(f, getLegalMapSize(len, offset), getLegalMapOffset(offset),
|
||||
kMapMode<MB>, ec) {
|
||||
if (!ec) {
|
||||
const uint8_t* Start = getStart(len, offset);
|
||||
MemoryBuffer::Init(Start, Start + len);
|
||||
}
|
||||
}
|
||||
|
||||
/// Disable sized deallocation for MemoryBufferMMapFile, because it has
|
||||
/// tail-allocated data.
|
||||
void operator delete(void* p) { ::operator delete(p); } // NOLINT
|
||||
|
||||
std::string_view GetBufferIdentifier() const override {
|
||||
// The name is stored after the class itself.
|
||||
return std::string_view(reinterpret_cast<const char*>(this + 1));
|
||||
}
|
||||
|
||||
MemoryBuffer::BufferKind GetBufferKind() const override {
|
||||
return MemoryBuffer::MemoryBuffer_MMap;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetMemoryBufferForStream(
|
||||
fs::file_t f, std::string_view bufferName, std::error_code& ec) {
|
||||
constexpr size_t ChunkSize = 4096 * 4;
|
||||
SmallVector<uint8_t, ChunkSize> buffer;
|
||||
#ifdef _WIN32
|
||||
DWORD readBytes;
|
||||
#else
|
||||
ssize_t readBytes;
|
||||
#endif
|
||||
// Read into Buffer until we hit EOF.
|
||||
do {
|
||||
buffer.reserve(buffer.size() + ChunkSize);
|
||||
#ifdef _WIN32
|
||||
if (!ReadFile(f, buffer.end(), ChunkSize, &readBytes, nullptr)) {
|
||||
ec = mapWindowsError(GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
readBytes = sys::RetryAfterSignal(-1, ::read, f, buffer.end(), ChunkSize);
|
||||
if (readBytes == -1) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
buffer.set_size(buffer.size() + readBytes);
|
||||
} while (readBytes != 0);
|
||||
|
||||
return GetMemBufferCopyImpl(buffer, bufferName, ec);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFile(std::string_view filename,
|
||||
std::error_code& ec,
|
||||
int64_t fileSize) {
|
||||
return GetFileAux<MemoryBuffer>(filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetOpenFileImpl(fs::file_t f,
|
||||
std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t fileSize, uint64_t mapSize,
|
||||
int64_t offset);
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetFileAux(std::string_view filename,
|
||||
std::error_code& ec, int64_t fileSize,
|
||||
uint64_t mapSize, uint64_t offset) {
|
||||
fs::file_t F = fs::OpenFileForRead(filename, ec, fs::OF_None);
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto Ret = GetOpenFileImpl<MB>(F, filename, ec, fileSize, mapSize, offset);
|
||||
fs::CloseFile(F);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize) {
|
||||
return GetFileAux<WritableMemoryBuffer>(filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetFileSlice(
|
||||
std::string_view filename, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset) {
|
||||
return GetFileAux<WritableMemoryBuffer>(filename, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer>
|
||||
WritableMemoryBuffer::GetNewUninitMemBuffer(size_t size,
|
||||
std::string_view bufferName) {
|
||||
using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>;
|
||||
// Allocate space for the MemoryBuffer, the data and the name. It is important
|
||||
// that MemoryBuffer and data are aligned so PointerIntPair works with them.
|
||||
// TODO: Is 16-byte alignment enough? We copy small object files with large
|
||||
// alignment expectations into this buffer.
|
||||
size_t alignedStringLen =
|
||||
alignTo(sizeof(MemBuffer) + bufferName.size() + 1, 16);
|
||||
size_t realLen = alignedStringLen + size + 1;
|
||||
uint8_t* mem = static_cast<uint8_t*>(operator new(realLen, std::nothrow));
|
||||
if (!mem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The name is stored after the class itself.
|
||||
CopyStringView(mem + sizeof(MemBuffer), bufferName);
|
||||
|
||||
// The buffer begins after the name and must be aligned.
|
||||
uint8_t* buf = mem + alignedStringLen;
|
||||
buf[size] = 0; // Null terminate buffer.
|
||||
|
||||
auto* ret = new (mem) MemBuffer({buf, size});
|
||||
return std::unique_ptr<WritableMemoryBuffer>(ret);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetNewMemBuffer(
|
||||
size_t size, std::string_view bufferName) {
|
||||
auto sb = WritableMemoryBuffer::GetNewUninitMemBuffer(size, bufferName);
|
||||
if (!sb) {
|
||||
return nullptr;
|
||||
}
|
||||
std::memset(sb->begin(), 0, size);
|
||||
return sb;
|
||||
}
|
||||
|
||||
static std::unique_ptr<WriteThroughMemoryBuffer> GetReadWriteFile(
|
||||
std::string_view filename, std::error_code& ec, uint64_t fileSize,
|
||||
uint64_t mapSize, uint64_t offset) {
|
||||
fs::file_t f =
|
||||
fs::OpenFileForReadWrite(filename, ec, fs::CD_OpenExisting, fs::OF_None);
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Default is to map the full file.
|
||||
if (mapSize == uint64_t(-1)) {
|
||||
// If we don't know the file size, use fstat to find out. fstat on an open
|
||||
// file descriptor is cheaper than stat on a random path.
|
||||
if (fileSize == uint64_t(-1)) {
|
||||
#ifdef _WIN32
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't mmap it, so error out.
|
||||
if (GetFileType(f) != FILE_TYPE_DISK) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LARGE_INTEGER fileSizeWin;
|
||||
if (!GetFileSizeEx(f, &fileSizeWin)) {
|
||||
ec = wpi::mapWindowsError(GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
fileSize = fileSizeWin.QuadPart;
|
||||
#else
|
||||
struct stat status;
|
||||
if (fstat(f, &status) < 0) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't mmap it, so error out.
|
||||
if (status.st_mode != S_IFREG && status.st_mode != S_IFBLK) {
|
||||
ec = make_error_code(errc::invalid_argument);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fileSize = status.st_size;
|
||||
#endif
|
||||
}
|
||||
mapSize = fileSize;
|
||||
}
|
||||
|
||||
std::unique_ptr<WriteThroughMemoryBuffer> result(new (NamedBufferAlloc(
|
||||
filename)) MemoryBufferMMapFile<WriteThroughMemoryBuffer>(f, mapSize,
|
||||
offset, ec));
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<WriteThroughMemoryBuffer> WriteThroughMemoryBuffer::GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize) {
|
||||
return GetReadWriteFile(filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
/// Map a subrange of the specified file as a WritableMemoryBuffer.
|
||||
std::unique_ptr<WriteThroughMemoryBuffer>
|
||||
WriteThroughMemoryBuffer::GetFileSlice(std::string_view filename,
|
||||
std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset) {
|
||||
return GetReadWriteFile(filename, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
template <typename MB>
|
||||
static std::unique_ptr<MB> GetOpenFileImpl(fs::file_t f,
|
||||
std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t fileSize, uint64_t mapSize,
|
||||
int64_t offset) {
|
||||
// Default is to map the full file.
|
||||
if (mapSize == uint64_t(-1)) {
|
||||
// If we don't know the file size, use fstat to find out. fstat on an open
|
||||
// file descriptor is cheaper than stat on a random path.
|
||||
if (fileSize == uint64_t(-1)) {
|
||||
#ifdef _WIN32
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't trust the size. Create the memory
|
||||
// buffer by copying off the stream.
|
||||
LARGE_INTEGER fileSizeWin;
|
||||
if (GetFileType(f) != FILE_TYPE_DISK || !GetFileSizeEx(f, &fileSizeWin)) {
|
||||
return GetMemoryBufferForStream(f, filename, ec);
|
||||
}
|
||||
fileSize = fileSizeWin.QuadPart;
|
||||
#else
|
||||
struct stat status;
|
||||
if (fstat(f, &status) < 0) {
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If this not a file or a block device (e.g. it's a named pipe
|
||||
// or character device), we can't trust the size. Create the memory
|
||||
// buffer by copying off the stream.
|
||||
if (status.st_mode != S_IFREG && status.st_mode != S_IFBLK) {
|
||||
return GetMemoryBufferForStream(f, filename, ec);
|
||||
}
|
||||
|
||||
fileSize = status.st_size;
|
||||
#endif
|
||||
}
|
||||
mapSize = fileSize;
|
||||
}
|
||||
|
||||
// Don't use mmap for small files
|
||||
if (mapSize >= 4 * 4096) {
|
||||
std::unique_ptr<MB> result(new (NamedBufferAlloc(
|
||||
filename)) MemoryBufferMMapFile<MB>(f, mapSize, offset, ec));
|
||||
if (!ec) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
auto buf = WritableMemoryBuffer::GetNewUninitMemBuffer(mapSize, filename);
|
||||
if (!buf) {
|
||||
// Failed to create a buffer. The only way it can fail is if
|
||||
// new(std::nothrow) returns 0.
|
||||
ec = make_error_code(errc::not_enough_memory);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* bufPtr = buf.get()->begin();
|
||||
|
||||
size_t bytesLeft = mapSize;
|
||||
while (bytesLeft) {
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER offsetWin;
|
||||
offsetWin.QuadPart = offset;
|
||||
DWORD numRead;
|
||||
if (!SetFilePointerEx(f, offsetWin, nullptr, FILE_BEGIN) ||
|
||||
!ReadFile(f, bufPtr, bytesLeft, &numRead, nullptr)) {
|
||||
ec = mapWindowsError(GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
// TODO
|
||||
#else
|
||||
ssize_t numRead = sys::RetryAfterSignal(-1, ::pread, f, bufPtr, bytesLeft,
|
||||
mapSize - bytesLeft + offset);
|
||||
if (numRead == -1) {
|
||||
// Error while reading.
|
||||
ec = std::error_code(errno, std::generic_category());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
if (numRead == 0) {
|
||||
std::memset(bufPtr, 0, bytesLeft); // zero-initialize rest of the buffer.
|
||||
break;
|
||||
}
|
||||
bytesLeft -= numRead;
|
||||
bufPtr += numRead;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetOpenFile(
|
||||
fs::file_t f, std::string_view filename, std::error_code& ec,
|
||||
uint64_t fileSize) {
|
||||
return GetOpenFileImpl<MemoryBuffer>(f, filename, ec, fileSize, fileSize, 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetOpenFileSlice(
|
||||
fs::file_t f, std::string_view filename, std::error_code& ec,
|
||||
uint64_t mapSize, int64_t offset) {
|
||||
assert(mapSize != uint64_t(-1));
|
||||
return GetOpenFileImpl<MemoryBuffer>(f, filename, ec, -1, mapSize, offset);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFileAsStream(
|
||||
std::string_view filename, std::error_code& ec) {
|
||||
fs::file_t f = fs::OpenFileForRead(filename, ec, fs::OF_None);
|
||||
if (ec) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<MemoryBuffer> ret = GetMemoryBufferForStream(f, filename, ec);
|
||||
fs::CloseFile(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MemoryBufferRef MemoryBuffer::GetMemBufferRef() const {
|
||||
return MemoryBufferRef(GetBuffer(), GetBufferIdentifier());
|
||||
}
|
||||
|
||||
SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() {}
|
||||
271
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallPtrSet.cpp
vendored
Normal file
271
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallPtrSet.cpp
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SmallPtrSet class. See SmallPtrSet.h for an
|
||||
// overview of the algorithm.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/SmallPtrSet.h"
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
void SmallPtrSetImplBase::shrink_and_clear() {
|
||||
assert(!isSmall() && "Can't shrink a small set!");
|
||||
free(CurArray);
|
||||
|
||||
// Reduce the number of buckets.
|
||||
unsigned Size = size();
|
||||
CurArraySize = Size > 16 ? 1 << (Log2_32_Ceil(Size) + 1) : 32;
|
||||
NumNonEmpty = NumTombstones = 0;
|
||||
|
||||
// Install the new array. Clear all the buckets to empty.
|
||||
CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize);
|
||||
|
||||
memset(CurArray, -1, CurArraySize*sizeof(void*));
|
||||
}
|
||||
|
||||
std::pair<const void *const *, bool>
|
||||
SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
|
||||
if (LLVM_UNLIKELY(size() * 4 >= CurArraySize * 3)) {
|
||||
// If more than 3/4 of the array is full, grow.
|
||||
Grow(CurArraySize < 64 ? 128 : CurArraySize * 2);
|
||||
} else if (LLVM_UNLIKELY(CurArraySize - NumNonEmpty < CurArraySize / 8)) {
|
||||
// If fewer of 1/8 of the array is empty (meaning that many are filled with
|
||||
// tombstones), rehash.
|
||||
Grow(CurArraySize);
|
||||
}
|
||||
|
||||
// Okay, we know we have space. Find a hash bucket.
|
||||
const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr));
|
||||
if (*Bucket == Ptr)
|
||||
return std::make_pair(Bucket, false); // Already inserted, good.
|
||||
|
||||
// Otherwise, insert it!
|
||||
if (*Bucket == getTombstoneMarker())
|
||||
--NumTombstones;
|
||||
else
|
||||
++NumNonEmpty; // Track density.
|
||||
*Bucket = Ptr;
|
||||
incrementEpoch();
|
||||
return std::make_pair(Bucket, 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 (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.
|
||||
if (LLVM_LIKELY(Array[Bucket] == getEmptyMarker()))
|
||||
return Tombstone ? Tombstone : Array+Bucket;
|
||||
|
||||
// Found Ptr's bucket?
|
||||
if (LLVM_LIKELY(Array[Bucket] == Ptr))
|
||||
return Array+Bucket;
|
||||
|
||||
// If this is a tombstone, remember it. If Ptr ends up not in the set, we
|
||||
// prefer to return it than something that would require more probing.
|
||||
if (Array[Bucket] == getTombstoneMarker() && !Tombstone)
|
||||
Tombstone = Array+Bucket; // Remember the first tombstone found.
|
||||
|
||||
// It's a hash collision or a tombstone. Reprobe.
|
||||
Bucket = (Bucket + ProbeAmt++) & (ArraySize-1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
///
|
||||
void SmallPtrSetImplBase::Grow(unsigned NewSize) {
|
||||
const void **OldBuckets = CurArray;
|
||||
const void **OldEnd = EndPointer();
|
||||
bool WasSmall = isSmall();
|
||||
|
||||
// Install the new array. Clear all the buckets to empty.
|
||||
const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize);
|
||||
|
||||
// Reset member only if memory was allocated successfully
|
||||
CurArray = NewBuckets;
|
||||
CurArraySize = NewSize;
|
||||
memset(CurArray, -1, NewSize*sizeof(void*));
|
||||
|
||||
// Copy over all valid entries.
|
||||
for (const void **BucketPtr = OldBuckets; BucketPtr != OldEnd; ++BucketPtr) {
|
||||
// Copy over the element if it is valid.
|
||||
const void *Elt = *BucketPtr;
|
||||
if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())
|
||||
*const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt);
|
||||
}
|
||||
|
||||
if (!WasSmall)
|
||||
free(OldBuckets);
|
||||
NumNonEmpty -= NumTombstones;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
|
||||
const SmallPtrSetImplBase &that) {
|
||||
SmallArray = SmallStorage;
|
||||
|
||||
// If we're becoming small, prepare to insert into our stack space
|
||||
if (that.isSmall()) {
|
||||
CurArray = SmallArray;
|
||||
// Otherwise, allocate new heap space (unless we were the same size)
|
||||
} else {
|
||||
CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize);
|
||||
}
|
||||
|
||||
// Copy over the that array.
|
||||
CopyHelper(that);
|
||||
}
|
||||
|
||||
SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
|
||||
unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that) {
|
||||
SmallArray = SmallStorage;
|
||||
MoveHelper(SmallSize, std::move(that));
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) {
|
||||
assert(&RHS != this && "Self-copy should be handled by the caller.");
|
||||
|
||||
if (isSmall() && RHS.isSmall())
|
||||
assert(CurArraySize == RHS.CurArraySize &&
|
||||
"Cannot assign sets with different small sizes");
|
||||
|
||||
// If we're becoming small, prepare to insert into our stack space
|
||||
if (RHS.isSmall()) {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
CurArray = SmallArray;
|
||||
// Otherwise, allocate new heap space (unless we were the same size)
|
||||
} else if (CurArraySize != RHS.CurArraySize) {
|
||||
if (isSmall())
|
||||
CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize);
|
||||
else {
|
||||
const void **T = (const void**)safe_realloc(CurArray,
|
||||
sizeof(void*) * RHS.CurArraySize);
|
||||
CurArray = T;
|
||||
}
|
||||
}
|
||||
|
||||
CopyHelper(RHS);
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::CopyHelper(const SmallPtrSetImplBase &RHS) {
|
||||
// Copy over the new array size
|
||||
CurArraySize = RHS.CurArraySize;
|
||||
|
||||
// Copy over the contents from the other set
|
||||
std::copy(RHS.CurArray, RHS.EndPointer(), CurArray);
|
||||
|
||||
NumNonEmpty = RHS.NumNonEmpty;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&RHS) {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
MoveHelper(SmallSize, std::move(RHS));
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::MoveHelper(unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&RHS) {
|
||||
assert(&RHS != this && "Self-move should be handled by the caller.");
|
||||
|
||||
if (RHS.isSmall()) {
|
||||
// Copy a small RHS rather than moving.
|
||||
CurArray = SmallArray;
|
||||
std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, CurArray);
|
||||
} else {
|
||||
CurArray = RHS.CurArray;
|
||||
RHS.CurArray = RHS.SmallArray;
|
||||
}
|
||||
|
||||
// Copy the rest of the trivial members.
|
||||
CurArraySize = RHS.CurArraySize;
|
||||
NumNonEmpty = RHS.NumNonEmpty;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
|
||||
// Make the RHS small and empty.
|
||||
RHS.CurArraySize = SmallSize;
|
||||
assert(RHS.CurArray == RHS.SmallArray);
|
||||
RHS.NumNonEmpty = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) {
|
||||
if (this == &RHS) return;
|
||||
|
||||
// We can only avoid copying elements if neither set is small.
|
||||
if (!this->isSmall() && !RHS.isSmall()) {
|
||||
std::swap(this->CurArray, RHS.CurArray);
|
||||
std::swap(this->CurArraySize, RHS.CurArraySize);
|
||||
std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap(this->NumTombstones, RHS.NumTombstones);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: From here on we assume that both sets have the same small size.
|
||||
|
||||
// If only RHS is small, copy the small elements into LHS and move the pointer
|
||||
// from LHS to RHS.
|
||||
if (!this->isSmall() && RHS.isSmall()) {
|
||||
assert(RHS.CurArray == RHS.SmallArray);
|
||||
std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, this->SmallArray);
|
||||
std::swap(RHS.CurArraySize, this->CurArraySize);
|
||||
std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap(this->NumTombstones, RHS.NumTombstones);
|
||||
RHS.CurArray = this->CurArray;
|
||||
this->CurArray = this->SmallArray;
|
||||
return;
|
||||
}
|
||||
|
||||
// If only LHS is small, copy the small elements into RHS and move the pointer
|
||||
// from RHS to LHS.
|
||||
if (this->isSmall() && !RHS.isSmall()) {
|
||||
assert(this->CurArray == this->SmallArray);
|
||||
std::copy(this->CurArray, this->CurArray + this->NumNonEmpty,
|
||||
RHS.SmallArray);
|
||||
std::swap(RHS.CurArraySize, this->CurArraySize);
|
||||
std::swap(RHS.NumNonEmpty, this->NumNonEmpty);
|
||||
std::swap(RHS.NumTombstones, this->NumTombstones);
|
||||
this->CurArray = RHS.CurArray;
|
||||
RHS.CurArray = RHS.SmallArray;
|
||||
return;
|
||||
}
|
||||
|
||||
// Both a small, just swap the small elements.
|
||||
assert(this->isSmall() && RHS.isSmall());
|
||||
unsigned MinNonEmpty = std::min(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap_ranges(this->SmallArray, this->SmallArray + MinNonEmpty,
|
||||
RHS.SmallArray);
|
||||
if (this->NumNonEmpty > MinNonEmpty) {
|
||||
std::copy(this->SmallArray + MinNonEmpty,
|
||||
this->SmallArray + this->NumNonEmpty,
|
||||
RHS.SmallArray + MinNonEmpty);
|
||||
} else {
|
||||
std::copy(RHS.SmallArray + MinNonEmpty, RHS.SmallArray + RHS.NumNonEmpty,
|
||||
this->SmallArray + MinNonEmpty);
|
||||
}
|
||||
assert(this->CurArraySize == RHS.CurArraySize);
|
||||
std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
|
||||
std::swap(this->NumTombstones, RHS.NumTombstones);
|
||||
}
|
||||
120
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
vendored
Normal file
120
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SmallVector class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <cstdint>
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
using namespace wpi;
|
||||
|
||||
// Check that no bytes are wasted and everything is well-aligned.
|
||||
namespace {
|
||||
struct Struct16B {
|
||||
alignas(16) void *X;
|
||||
};
|
||||
struct Struct32B {
|
||||
alignas(32) void *X;
|
||||
};
|
||||
}
|
||||
static_assert(sizeof(SmallVector<void *, 0>) ==
|
||||
sizeof(unsigned) * 2 + sizeof(void *),
|
||||
"wasted space in SmallVector size 0");
|
||||
static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
|
||||
"wrong alignment for 16-byte aligned T");
|
||||
static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
|
||||
"wrong alignment for 32-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
|
||||
"missing padding for 16-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
|
||||
"missing padding for 32-byte aligned T");
|
||||
static_assert(sizeof(SmallVector<void *, 1>) ==
|
||||
sizeof(unsigned) * 2 + sizeof(void *) * 2,
|
||||
"wasted space in SmallVector size 1");
|
||||
|
||||
/// Report that MinSize doesn't fit into this vector's size type. Throws
|
||||
/// std::length_error or calls report_fatal_error.
|
||||
LLVM_ATTRIBUTE_NORETURN
|
||||
static void report_size_overflow(size_t MinSize, size_t MaxSize);
|
||||
static void report_size_overflow(size_t MinSize, size_t MaxSize) {
|
||||
std::string Reason = "SmallVector unable to grow. Requested capacity (" +
|
||||
std::to_string(MinSize) +
|
||||
") is larger than maximum value for size type (" +
|
||||
std::to_string(MaxSize) + ")";
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
throw std::length_error(Reason);
|
||||
#else
|
||||
report_fatal_error(Reason);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Report that this vector is already at maximum capacity. Throws
|
||||
/// std::length_error or calls report_fatal_error.
|
||||
LLVM_ATTRIBUTE_NORETURN static void report_at_maximum_capacity(size_t MaxSize);
|
||||
static void report_at_maximum_capacity(size_t MaxSize) {
|
||||
std::string Reason =
|
||||
"SmallVector capacity unable to grow. Already at maximum size " +
|
||||
std::to_string(MaxSize);
|
||||
#ifdef LLVM_ENABLE_EXCEPTIONS
|
||||
throw std::length_error(Reason);
|
||||
#else
|
||||
report_fatal_error(Reason);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
|
||||
constexpr size_t MaxSize = std::numeric_limits<unsigned>::max();
|
||||
|
||||
// Ensure we can fit the new capacity.
|
||||
// This is only going to be applicable when the capacity is 32 bit.
|
||||
if (MinSize > MaxSize)
|
||||
report_size_overflow(MinSize, MaxSize);
|
||||
|
||||
// Ensure we can meet the guarantee of space for at least one more element.
|
||||
// The above check alone will not catch the case where grow is called with a
|
||||
// default MinSize of 0, but the current capacity cannot be increased.
|
||||
// This is only going to be applicable when the capacity is 32 bit.
|
||||
if (OldCapacity == MaxSize)
|
||||
report_at_maximum_capacity(MaxSize);
|
||||
|
||||
// In theory 2*capacity can overflow if the capacity is 64 bit, but the
|
||||
// original capacity would never be large enough for this to be a problem.
|
||||
size_t NewCapacity = 2 * OldCapacity + 1; // Always grow.
|
||||
return (std::min)((std::max)(NewCapacity, MinSize), MaxSize);
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
void *SmallVectorBase::mallocForGrow(size_t MinSize, size_t TSize,
|
||||
size_t &NewCapacity) {
|
||||
NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
|
||||
return wpi::safe_malloc(NewCapacity * TSize);
|
||||
}
|
||||
|
||||
// Note: Moving this function into the header may cause performance regression.
|
||||
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSize,
|
||||
size_t TSize) {
|
||||
size_t NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
|
||||
void *NewElts;
|
||||
if (BeginX == FirstEl) {
|
||||
NewElts = safe_malloc(NewCapacity * TSize);
|
||||
|
||||
// Copy the elements over. No need to run dtors on PODs.
|
||||
memcpy(NewElts, this->BeginX, size() * TSize);
|
||||
} else {
|
||||
// If this wasn't grown from the inline copy, grow the allocated space.
|
||||
NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
|
||||
}
|
||||
|
||||
this->BeginX = NewElts;
|
||||
this->Capacity = NewCapacity;
|
||||
}
|
||||
360
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringExtras.cpp
vendored
Normal file
360
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringExtras.cpp
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
//===-- StringExtras.cpp - Implement the StringExtras header --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the StringExtras.h header
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringExtras.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
|
||||
// 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 = wpi::toLower(lhs[i]);
|
||||
unsigned char rhc = wpi::toLower(rhs[i]);
|
||||
if (lhc != rhc) {
|
||||
return lhc < rhc ? -1 : 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wpi::compare_lower(std::string_view lhs, std::string_view rhs) noexcept {
|
||||
if (int Res = ascii_strncasecmp(lhs.data(), rhs.data(),
|
||||
(std::min)(lhs.size(), rhs.size()))) {
|
||||
return Res;
|
||||
}
|
||||
if (lhs.size() == rhs.size()) {
|
||||
return 0;
|
||||
}
|
||||
return lhs.size() < rhs.size() ? -1 : 1;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::find_lower(
|
||||
std::string_view str, char ch, std::string_view::size_type from) noexcept {
|
||||
char lch = toLower(ch);
|
||||
auto s = drop_front(str, from);
|
||||
while (!s.empty()) {
|
||||
if (toLower(s.front()) == lch) {
|
||||
return str.size() - s.size();
|
||||
}
|
||||
s.remove_prefix(1);
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::find_lower(
|
||||
std::string_view str, std::string_view other,
|
||||
std::string_view::size_type from) noexcept {
|
||||
auto s = substr(str, from);
|
||||
while (s.size() >= other.size()) {
|
||||
if (starts_with_lower(s, other)) {
|
||||
return from;
|
||||
}
|
||||
s.remove_prefix(1);
|
||||
++from;
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::rfind_lower(
|
||||
std::string_view str, char ch, std::string_view::size_type from) noexcept {
|
||||
from = (std::min)(from, str.size());
|
||||
auto data = str.data();
|
||||
std::string_view::size_type i = from;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
if (toLower(data[i]) == toLower(ch)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
std::string_view::size_type wpi::rfind_lower(std::string_view str,
|
||||
std::string_view other) noexcept {
|
||||
std::string_view::size_type n = other.size();
|
||||
if (n > str.size()) {
|
||||
return std::string_view::npos;
|
||||
}
|
||||
for (size_t i = str.size() - n + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (equals_lower(substr(str, i, n), other)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
|
||||
bool wpi::starts_with_lower(std::string_view str,
|
||||
std::string_view prefix) noexcept {
|
||||
return str.size() >= prefix.size() &&
|
||||
ascii_strncasecmp(str.data(), prefix.data(), prefix.size()) == 0;
|
||||
}
|
||||
|
||||
bool wpi::ends_with_lower(std::string_view str,
|
||||
std::string_view suffix) noexcept {
|
||||
return str.size() >= suffix.size() &&
|
||||
ascii_strncasecmp(str.data() + str.size() - suffix.size(),
|
||||
suffix.data(), suffix.size()) == 0;
|
||||
}
|
||||
|
||||
void wpi::split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
std::string_view separator, int maxSplit,
|
||||
bool keepEmpty) noexcept {
|
||||
std::string_view s = str;
|
||||
|
||||
// Count down from maxSplit. When maxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make maxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (maxSplit-- != 0) {
|
||||
auto idx = s.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Push this split.
|
||||
if (keepEmpty || idx > 0) {
|
||||
arr.push_back(slice(s, 0, idx));
|
||||
}
|
||||
|
||||
// Jump forward.
|
||||
s = slice(s, idx + separator.size(), std::string_view::npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (keepEmpty || !s.empty()) {
|
||||
arr.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
void wpi::split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
char separator, int maxSplit, bool keepEmpty) noexcept {
|
||||
std::string_view s = str;
|
||||
|
||||
// Count down from maxSplit. When maxSplit is -1, this will just split
|
||||
// "forever". This doesn't support splitting more than 2^31 times
|
||||
// intentionally; if we ever want that we can make maxSplit a 64-bit integer
|
||||
// but that seems unlikely to be useful.
|
||||
while (maxSplit-- != 0) {
|
||||
size_t idx = s.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Push this split.
|
||||
if (keepEmpty || idx > 0) {
|
||||
arr.push_back(slice(s, 0, idx));
|
||||
}
|
||||
|
||||
// Jump forward.
|
||||
s = slice(s, idx + 1, std::string_view::npos);
|
||||
}
|
||||
|
||||
// Push the tail.
|
||||
if (keepEmpty || !s.empty()) {
|
||||
arr.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned GetAutoSenseRadix(std::string_view& str) noexcept {
|
||||
if (str.empty()) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0x") || wpi::starts_with(str, "0X")) {
|
||||
str.remove_prefix(2);
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0b") || wpi::starts_with(str, "0B")) {
|
||||
str.remove_prefix(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (wpi::starts_with(str, "0o")) {
|
||||
str.remove_prefix(2);
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (str[0] == '0' && str.size() > 1 && wpi::isDigit(str[1])) {
|
||||
str.remove_prefix(1);
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
|
||||
bool wpi::detail::ConsumeUnsignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
unsigned long long& result) noexcept { // NOLINT(runtime/int)
|
||||
// Autosense radix if not specified.
|
||||
if (radix == 0) {
|
||||
radix = GetAutoSenseRadix(str);
|
||||
}
|
||||
|
||||
// Empty strings (after the radix autosense) are invalid.
|
||||
if (str.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse all the bytes of the string given this radix. Watch for overflow.
|
||||
std::string_view str2 = str;
|
||||
result = 0;
|
||||
while (!str2.empty()) {
|
||||
unsigned charVal;
|
||||
if (str2[0] >= '0' && str2[0] <= '9') {
|
||||
charVal = str2[0] - '0';
|
||||
} else if (str2[0] >= 'a' && str2[0] <= 'z') {
|
||||
charVal = str2[0] - 'a' + 10;
|
||||
} else if (str2[0] >= 'A' && str2[0] <= 'Z') {
|
||||
charVal = str2[0] - 'A' + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// If the parsed value is larger than the integer radix, we cannot
|
||||
// consume any more characters.
|
||||
if (charVal >= radix) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add in this character.
|
||||
unsigned long long prevResult = result; // NOLINT(runtime/int)
|
||||
result = result * radix + charVal;
|
||||
|
||||
// Check for overflow by shifting back and seeing if bits were lost.
|
||||
if (result / radix < prevResult) {
|
||||
return true;
|
||||
}
|
||||
|
||||
str2.remove_prefix(1);
|
||||
}
|
||||
|
||||
// We consider the operation a failure if no characters were consumed
|
||||
// successfully.
|
||||
if (str.size() == str2.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
str = str2;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::detail::ConsumeSignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
long long& result) noexcept { // NOLINT(runtime/int)
|
||||
unsigned long long ullVal; // NOLINT(runtime/int)
|
||||
|
||||
// Handle positive strings first.
|
||||
if (str.empty() || str.front() != '-') {
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str, radix, ullVal) ||
|
||||
// Check for value so large it overflows a signed value.
|
||||
static_cast<long long>(ullVal) < 0) { // NOLINT(runtime/int)
|
||||
return true;
|
||||
}
|
||||
result = ullVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the positive part of the value.
|
||||
std::string_view str2 = wpi::drop_front(str, 1);
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str2, radix, ullVal) ||
|
||||
// Reject values so large they'd overflow as negative signed, but allow
|
||||
// "-0". This negates the unsigned so that the negative isn't undefined
|
||||
// on signed overflow.
|
||||
static_cast<long long>(-ullVal) > 0) { // NOLINT(runtime/int)
|
||||
return true;
|
||||
}
|
||||
|
||||
str = str2;
|
||||
result = -ullVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsUnsignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
unsigned long long& result) noexcept { // NOLINT(runtime/int)
|
||||
if (wpi::detail::ConsumeUnsignedInteger(str, radix, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For getAsUnsignedInteger, we require the whole string to be consumed or
|
||||
// else we consider it a failure.
|
||||
return !str.empty();
|
||||
}
|
||||
|
||||
bool wpi::detail::GetAsSignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
long long& result) noexcept { // NOLINT(runtime/int)
|
||||
if (wpi::detail::ConsumeSignedInteger(str, radix, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For getAsSignedInteger, we require the whole string to be consumed or else
|
||||
// we consider it a failure.
|
||||
return !str.empty();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<float> wpi::parse_float<float>(std::string_view str) noexcept {
|
||||
if (str.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
wpi::SmallString<32> storage{str};
|
||||
char* end;
|
||||
float val = std::strtof(storage.c_str(), &end);
|
||||
if (*end != '\0') {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<double> wpi::parse_float<double>(std::string_view str) noexcept {
|
||||
if (str.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
wpi::SmallString<32> storage{str};
|
||||
char* end;
|
||||
double val = std::strtod(storage.c_str(), &end);
|
||||
if (*end != '\0') {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<long double> wpi::parse_float<long double>(
|
||||
std::string_view str) noexcept {
|
||||
if (str.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
wpi::SmallString<32> storage{str};
|
||||
char* end;
|
||||
long double val = std::strtold(storage.c_str(), &end);
|
||||
if (*end != '\0') {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
261
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
vendored
Normal file
261
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
//===--- StringMap.cpp - String Hash table map implementation -------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the StringMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringMap.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/DJB.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
/// Returns the number of buckets to allocate to ensure that the DenseMap can
|
||||
/// accommodate \p NumEntries without need to grow().
|
||||
static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
|
||||
// Ensure that "NumEntries * 4 < NumBuckets * 3"
|
||||
if (NumEntries == 0)
|
||||
return 0;
|
||||
// +1 is required because of the strict equality.
|
||||
// For example if NumEntries is 48, we need to return 401.
|
||||
return NextPowerOf2(NumEntries * 4 / 3 + 1);
|
||||
}
|
||||
|
||||
StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
|
||||
ItemSize = itemSize;
|
||||
|
||||
// If a size is specified, initialize the table with that many buckets.
|
||||
if (InitSize) {
|
||||
// The table will grow when the number of entries reach 3/4 of the number of
|
||||
// buckets. To guarantee that "InitSize" number of entries can be inserted
|
||||
// in the table without growing, we allocate just what is needed here.
|
||||
init(getMinBucketToReserveForEntries(InitSize));
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, initialize it with zero buckets to avoid the allocation.
|
||||
TheTable = nullptr;
|
||||
NumBuckets = 0;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
void StringMapImpl::init(unsigned InitSize) {
|
||||
assert((InitSize & (InitSize - 1)) == 0 &&
|
||||
"Init Size must be a power of 2 or zero!");
|
||||
|
||||
unsigned NewNumBuckets = InitSize ? InitSize : 16;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
|
||||
TheTable = static_cast<StringMapEntryBase **>(safe_calloc(
|
||||
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
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0) { // Hash table unallocated so far?
|
||||
init(16);
|
||||
HTSize = NumBuckets;
|
||||
}
|
||||
unsigned FullHashValue = djbHash(Name, 0);
|
||||
unsigned BucketNo = FullHashValue & (HTSize - 1);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
int FirstTombstone = -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)) {
|
||||
// If we found a tombstone, we want to reuse the tombstone instead of an
|
||||
// empty bucket. This reduces probing.
|
||||
if (FirstTombstone != -1) {
|
||||
HashTable[FirstTombstone] = FullHashValue;
|
||||
return FirstTombstone;
|
||||
}
|
||||
|
||||
HashTable[BucketNo] = FullHashValue;
|
||||
return BucketNo;
|
||||
}
|
||||
|
||||
if (BucketItem == getTombstoneVal()) {
|
||||
// Skip over tombstones. However, remember the first one we see.
|
||||
if (FirstTombstone == -1)
|
||||
FirstTombstone = BucketNo;
|
||||
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
|
||||
// If the full hash value matches, check deeply for a match. The common
|
||||
// case here is that we are only looking at the buckets (for item info
|
||||
// being non-null and for the full hash value) not at the items. This
|
||||
// is important for cache locality.
|
||||
|
||||
// Do the comparison like this because Name isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
++ProbeAmt;
|
||||
}
|
||||
}
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int StringMapImpl::FindKey(std::string_view Key) const {
|
||||
unsigned HTSize = NumBuckets;
|
||||
if (HTSize == 0)
|
||||
return -1; // Really empty table?
|
||||
unsigned FullHashValue = djbHash(Key, 0);
|
||||
unsigned BucketNo = FullHashValue & (HTSize - 1);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
unsigned ProbeAmt = 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))
|
||||
return -1;
|
||||
|
||||
if (BucketItem == getTombstoneVal()) {
|
||||
// Ignore tombstones.
|
||||
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
|
||||
// If the full hash value matches, check deeply for a match. The common
|
||||
// case here is that we are only looking at the buckets (for item info
|
||||
// being non-null and for the full hash value) not at the items. This
|
||||
// is important for cache locality.
|
||||
|
||||
// Do the comparison like this because NameStart isn't necessarily
|
||||
// null-terminated!
|
||||
char *ItemStr = (char *)BucketItem + ItemSize;
|
||||
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
|
||||
// We found a match!
|
||||
return BucketNo;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, we didn't find the item. Probe to the next bucket.
|
||||
BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
|
||||
|
||||
// Use quadratic probing, it has fewer clumping artifacts than linear
|
||||
// probing and has good cache behavior in the common case.
|
||||
++ProbeAmt;
|
||||
}
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
|
||||
const char *VStr = (char *)V + ItemSize;
|
||||
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
|
||||
(void)V2;
|
||||
assert(V == V2 && "Didn't find key?");
|
||||
}
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return nullptr;
|
||||
|
||||
StringMapEntryBase *Result = TheTable[Bucket];
|
||||
TheTable[Bucket] = getTombstoneVal();
|
||||
--NumItems;
|
||||
++NumTombstones;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// RehashTable - Grow the table, redistributing values into the buckets with
|
||||
/// the appropriate mod-of-hashtable-size.
|
||||
unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
unsigned NewSize;
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
// If the hash table is now more than 3/4 full, or if fewer than 1/8 of
|
||||
// the buckets are empty (meaning that many are filled with tombstones),
|
||||
// grow/rehash the table.
|
||||
if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
|
||||
NewSize = NumBuckets * 2;
|
||||
} else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
|
||||
NumBuckets / 8)) {
|
||||
NewSize = NumBuckets;
|
||||
} else {
|
||||
return BucketNo;
|
||||
}
|
||||
|
||||
unsigned NewBucketNo = BucketNo;
|
||||
// Allocate one extra bucket which will always be non-empty. This allows the
|
||||
// iterators to stop at end.
|
||||
auto NewTableArray = static_cast<StringMapEntryBase **>(safe_calloc(
|
||||
NewSize + 1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
|
||||
|
||||
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
|
||||
NewTableArray[NewSize] = (StringMapEntryBase *)2;
|
||||
|
||||
// Rehash all the items into their new buckets. Luckily :) we already have
|
||||
// the hash values available, so we don't have to rehash any strings.
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
// Fast case, bucket available.
|
||||
unsigned FullHash = HashTable[I];
|
||||
unsigned NewBucket = FullHash & (NewSize - 1);
|
||||
if (!NewTableArray[NewBucket]) {
|
||||
NewTableArray[FullHash & (NewSize - 1)] = Bucket;
|
||||
NewHashArray[FullHash & (NewSize - 1)] = FullHash;
|
||||
if (I == BucketNo)
|
||||
NewBucketNo = NewBucket;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise probe for a spot.
|
||||
unsigned ProbeSize = 1;
|
||||
do {
|
||||
NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
|
||||
} while (NewTableArray[NewBucket]);
|
||||
|
||||
// Finally found a slot. Fill it in.
|
||||
NewTableArray[NewBucket] = Bucket;
|
||||
NewHashArray[NewBucket] = FullHash;
|
||||
if (I == BucketNo)
|
||||
NewBucketNo = NewBucket;
|
||||
}
|
||||
}
|
||||
|
||||
free(TheTable);
|
||||
|
||||
TheTable = NewTableArray;
|
||||
NumBuckets = NewSize;
|
||||
NumTombstones = 0;
|
||||
return NewBucketNo;
|
||||
}
|
||||
260
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
vendored
Normal file
260
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines things specific to Windows implementations. In addition to
|
||||
// providing some helpers for working with win32 APIs, this header wraps
|
||||
// <windows.h> with some portability macros. Always include WindowsSupport.h
|
||||
// instead of including <windows.h> directly.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//=== WARNING: Implementation here must contain only generic Win32 code that
|
||||
//=== is guaranteed to work on *all* Win32 variants.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_WINDOWSSUPPORT_H
|
||||
#define WPIUTIL_WPI_WINDOWSSUPPORT_H
|
||||
|
||||
// mingw-w64 tends to define it as 0x0502 in its headers.
|
||||
#undef _WIN32_WINNT
|
||||
#undef _WIN32_IE
|
||||
|
||||
// Require at least Windows 7 API.
|
||||
#define _WIN32_WINNT 0x0601
|
||||
#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Chrono.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/VersionTuple.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
#undef WIN32_NO_STATUS
|
||||
#include <winternl.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
// Must be included after windows.h
|
||||
#include <wincrypt.h>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
|
||||
/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
|
||||
/// GetVersionEx is deprecated, but this API exposes the build number which can
|
||||
/// be useful for working around certain kernel bugs.
|
||||
inline wpi::VersionTuple GetWindowsOSVersion() {
|
||||
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
||||
HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
|
||||
if (hMod) {
|
||||
auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
|
||||
if (getVer) {
|
||||
RTL_OSVERSIONINFOEXW info{};
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
if (getVer((PRTL_OSVERSIONINFOW)&info) == ((NTSTATUS)0x00000000L)) {
|
||||
return wpi::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0,
|
||||
info.dwBuildNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
return wpi::VersionTuple(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't
|
||||
/// yet have VersionHelpers.h, so we have our own helper.
|
||||
inline bool RunningWindows8OrGreater() {
|
||||
// Windows 8 is version 6.2, service pack 0.
|
||||
return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
|
||||
}
|
||||
|
||||
/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
|
||||
/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
|
||||
/// GetVersionEx is deprecated, but this API exposes the build number which can
|
||||
/// be useful for working around certain kernel bugs.
|
||||
wpi::VersionTuple GetWindowsOSVersion();
|
||||
|
||||
bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix);
|
||||
|
||||
// Include GetLastError() in a fatal error message.
|
||||
LLVM_ATTRIBUTE_NORETURN inline void ReportLastErrorFatal(const char *Msg) {
|
||||
std::string ErrMsg;
|
||||
MakeErrMsg(&ErrMsg, Msg);
|
||||
wpi::report_fatal_error(ErrMsg);
|
||||
}
|
||||
|
||||
template <typename HandleTraits>
|
||||
class ScopedHandle {
|
||||
typedef typename HandleTraits::handle_type handle_type;
|
||||
handle_type Handle;
|
||||
|
||||
ScopedHandle(const ScopedHandle &other) = delete;
|
||||
void operator=(const ScopedHandle &other) = delete;
|
||||
public:
|
||||
ScopedHandle()
|
||||
: Handle(HandleTraits::GetInvalid()) {}
|
||||
|
||||
explicit ScopedHandle(handle_type h)
|
||||
: Handle(h) {}
|
||||
|
||||
~ScopedHandle() {
|
||||
if (HandleTraits::IsValid(Handle))
|
||||
HandleTraits::Close(Handle);
|
||||
}
|
||||
|
||||
handle_type take() {
|
||||
handle_type t = Handle;
|
||||
Handle = HandleTraits::GetInvalid();
|
||||
return t;
|
||||
}
|
||||
|
||||
ScopedHandle &operator=(handle_type h) {
|
||||
if (HandleTraits::IsValid(Handle))
|
||||
HandleTraits::Close(Handle);
|
||||
Handle = h;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// True if Handle is valid.
|
||||
explicit operator bool() const {
|
||||
return HandleTraits::IsValid(Handle) ? true : false;
|
||||
}
|
||||
|
||||
operator handle_type() const {
|
||||
return Handle;
|
||||
}
|
||||
};
|
||||
|
||||
struct CommonHandleTraits {
|
||||
typedef HANDLE handle_type;
|
||||
|
||||
static handle_type GetInvalid() {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static void Close(handle_type h) {
|
||||
::CloseHandle(h);
|
||||
}
|
||||
|
||||
static bool IsValid(handle_type h) {
|
||||
return h != GetInvalid();
|
||||
}
|
||||
};
|
||||
|
||||
struct JobHandleTraits : CommonHandleTraits {
|
||||
static handle_type GetInvalid() {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct CryptContextTraits : CommonHandleTraits {
|
||||
typedef HCRYPTPROV handle_type;
|
||||
|
||||
static handle_type GetInvalid() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Close(handle_type h) {
|
||||
::CryptReleaseContext(h, 0);
|
||||
}
|
||||
|
||||
static bool IsValid(handle_type h) {
|
||||
return h != GetInvalid();
|
||||
}
|
||||
};
|
||||
|
||||
struct RegTraits : CommonHandleTraits {
|
||||
typedef HKEY handle_type;
|
||||
|
||||
static handle_type GetInvalid() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Close(handle_type h) {
|
||||
::RegCloseKey(h);
|
||||
}
|
||||
|
||||
static bool IsValid(handle_type h) {
|
||||
return h != GetInvalid();
|
||||
}
|
||||
};
|
||||
|
||||
struct FindHandleTraits : CommonHandleTraits {
|
||||
static void Close(handle_type h) {
|
||||
::FindClose(h);
|
||||
}
|
||||
};
|
||||
|
||||
struct FileHandleTraits : CommonHandleTraits {};
|
||||
|
||||
typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle;
|
||||
typedef ScopedHandle<FileHandleTraits> ScopedFileHandle;
|
||||
typedef ScopedHandle<CryptContextTraits> ScopedCryptContext;
|
||||
typedef ScopedHandle<RegTraits> ScopedRegHandle;
|
||||
typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
|
||||
typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
|
||||
|
||||
template <class T>
|
||||
class SmallVectorImpl;
|
||||
|
||||
template <class T>
|
||||
typename SmallVectorImpl<T>::const_pointer
|
||||
c_str(SmallVectorImpl<T> &str) {
|
||||
str.push_back(0);
|
||||
str.pop_back();
|
||||
return str.data();
|
||||
}
|
||||
|
||||
namespace sys {
|
||||
|
||||
inline std::chrono::nanoseconds toDuration(FILETIME Time) {
|
||||
ULARGE_INTEGER TimeInteger;
|
||||
TimeInteger.LowPart = Time.dwLowDateTime;
|
||||
TimeInteger.HighPart = Time.dwHighDateTime;
|
||||
|
||||
// FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
|
||||
return std::chrono::nanoseconds(100 * TimeInteger.QuadPart);
|
||||
}
|
||||
|
||||
inline TimePoint<> toTimePoint(FILETIME Time) {
|
||||
ULARGE_INTEGER TimeInteger;
|
||||
TimeInteger.LowPart = Time.dwLowDateTime;
|
||||
TimeInteger.HighPart = Time.dwHighDateTime;
|
||||
|
||||
// Adjust for different epoch
|
||||
TimeInteger.QuadPart -= 11644473600ll * 10000000;
|
||||
|
||||
// FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
|
||||
return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart));
|
||||
}
|
||||
|
||||
inline FILETIME toFILETIME(TimePoint<> TP) {
|
||||
ULARGE_INTEGER TimeInteger;
|
||||
TimeInteger.QuadPart = TP.time_since_epoch().count() / 100;
|
||||
TimeInteger.QuadPart += 11644473600ll * 10000000;
|
||||
|
||||
FILETIME Time;
|
||||
Time.dwLowDateTime = TimeInteger.LowPart;
|
||||
Time.dwHighDateTime = TimeInteger.HighPart;
|
||||
return Time;
|
||||
}
|
||||
|
||||
} // end namespace sys
|
||||
} // end namespace wpi.
|
||||
|
||||
#endif
|
||||
29
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_os_ostream.cpp
vendored
Normal file
29
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_os_ostream.cpp
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
//===--- raw_os_ostream.cpp - Implement the raw_os_ostream class ----------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This implements support adapting raw_ostream to std::ostream.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/raw_os_ostream.h"
|
||||
#include <ostream>
|
||||
using namespace wpi;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_os_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_os_ostream::~raw_os_ostream() {
|
||||
flush();
|
||||
}
|
||||
|
||||
void raw_os_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.write(Ptr, Size);
|
||||
}
|
||||
|
||||
uint64_t raw_os_ostream::current_pos() const { return OS.tellp(); }
|
||||
737
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
vendored
Normal file
737
wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
vendored
Normal file
@@ -0,0 +1,737 @@
|
||||
//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This implements support for bulk buffered stream output.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _CRT_NONSTDC_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/fs.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
|
||||
// <fcntl.h> may provide O_BINARY.
|
||||
# include <fcntl.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#ifndef STDIN_FILENO
|
||||
# define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
# define STDOUT_FILENO 1
|
||||
#endif
|
||||
#ifndef STDERR_FILENO
|
||||
# define STDERR_FILENO 2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#include "Windows/WindowsSupport.h"
|
||||
#endif
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
constexpr raw_ostream::Colors raw_ostream::BLACK;
|
||||
constexpr raw_ostream::Colors raw_ostream::RED;
|
||||
constexpr raw_ostream::Colors raw_ostream::GREEN;
|
||||
constexpr raw_ostream::Colors raw_ostream::YELLOW;
|
||||
constexpr raw_ostream::Colors raw_ostream::BLUE;
|
||||
constexpr raw_ostream::Colors raw_ostream::MAGENTA;
|
||||
constexpr raw_ostream::Colors raw_ostream::CYAN;
|
||||
constexpr raw_ostream::Colors raw_ostream::WHITE;
|
||||
constexpr raw_ostream::Colors raw_ostream::SAVEDCOLOR;
|
||||
constexpr raw_ostream::Colors raw_ostream::RESET;
|
||||
|
||||
namespace {
|
||||
// Find the length of an array.
|
||||
template <class T, std::size_t N>
|
||||
constexpr inline size_t array_lengthof(T (&)[N]) {
|
||||
return N;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
raw_ostream::~raw_ostream() {
|
||||
// raw_ostream's subclasses should take care to flush the buffer
|
||||
// in their destructors.
|
||||
assert(OutBufCur == OutBufStart &&
|
||||
"raw_ostream destructor called with non-empty buffer!");
|
||||
|
||||
if (BufferMode == BufferKind::InternalBuffer)
|
||||
delete [] OutBufStart;
|
||||
}
|
||||
|
||||
size_t raw_ostream::preferred_buffer_size() const {
|
||||
// BUFSIZ is intended to be a reasonable default.
|
||||
return BUFSIZ;
|
||||
}
|
||||
|
||||
void raw_ostream::SetBuffered() {
|
||||
// Ask the subclass to determine an appropriate buffer size.
|
||||
if (size_t Size = preferred_buffer_size())
|
||||
SetBufferSize(Size);
|
||||
else
|
||||
// It may return 0, meaning this stream should be unbuffered.
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
||||
BufferKind Mode) {
|
||||
assert(((Mode == BufferKind::Unbuffered && !BufferStart && Size == 0) ||
|
||||
(Mode != BufferKind::Unbuffered && BufferStart && Size != 0)) &&
|
||||
"stream must be unbuffered or have at least one byte");
|
||||
// Make sure the current buffer is free of content (we can't flush here; the
|
||||
// child buffer management logic will be in write_impl).
|
||||
assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!");
|
||||
|
||||
if (BufferMode == BufferKind::InternalBuffer)
|
||||
delete [] OutBufStart;
|
||||
OutBufStart = BufferStart;
|
||||
OutBufEnd = OutBufStart+Size;
|
||||
OutBufCur = OutBufStart;
|
||||
BufferMode = Mode;
|
||||
|
||||
assert(OutBufStart <= OutBufEnd && "Invalid size!");
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_escaped(std::string_view Str,
|
||||
bool UseHexEscapes) {
|
||||
for (unsigned char c : Str) {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
*this << '\\' << '\\';
|
||||
break;
|
||||
case '\t':
|
||||
*this << '\\' << 't';
|
||||
break;
|
||||
case '\n':
|
||||
*this << '\\' << 'n';
|
||||
break;
|
||||
case '"':
|
||||
*this << '\\' << '"';
|
||||
break;
|
||||
default:
|
||||
if (isPrint(c)) {
|
||||
*this << c;
|
||||
break;
|
||||
}
|
||||
|
||||
// Write out the escaped representation.
|
||||
if (UseHexEscapes) {
|
||||
*this << '\\' << 'x';
|
||||
*this << hexdigit((c >> 4 & 0xF));
|
||||
*this << hexdigit((c >> 0) & 0xF);
|
||||
} else {
|
||||
// Always use a full 3-character octal escape.
|
||||
*this << '\\';
|
||||
*this << char('0' + ((c >> 6) & 7));
|
||||
*this << char('0' + ((c >> 3) & 7));
|
||||
*this << char('0' + ((c >> 0) & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void raw_ostream::flush_nonempty() {
|
||||
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
|
||||
size_t Length = OutBufCur - OutBufStart;
|
||||
OutBufCur = OutBufStart;
|
||||
flush_tied_then_write(OutBufStart, Length);
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write(unsigned char C) {
|
||||
// Group exceptional cases into a single branch.
|
||||
if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) {
|
||||
if (LLVM_UNLIKELY(!OutBufStart)) {
|
||||
if (BufferMode == BufferKind::Unbuffered) {
|
||||
flush_tied_then_write(reinterpret_cast<char *>(&C), 1);
|
||||
return *this;
|
||||
}
|
||||
// Set up a buffer and start over.
|
||||
SetBuffered();
|
||||
return write(C);
|
||||
}
|
||||
|
||||
flush_nonempty();
|
||||
}
|
||||
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
|
||||
// Group exceptional cases into a single branch.
|
||||
if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) {
|
||||
if (LLVM_UNLIKELY(!OutBufStart)) {
|
||||
if (BufferMode == BufferKind::Unbuffered) {
|
||||
flush_tied_then_write(Ptr, Size);
|
||||
return *this;
|
||||
}
|
||||
// Set up a buffer and start over.
|
||||
SetBuffered();
|
||||
return write(Ptr, Size);
|
||||
}
|
||||
|
||||
size_t NumBytes = OutBufEnd - OutBufCur;
|
||||
|
||||
// If the buffer is empty at this point we have a string that is larger
|
||||
// than the buffer. Directly write the chunk that is a multiple of the
|
||||
// preferred buffer size and put the remainder in the buffer.
|
||||
if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
|
||||
assert(NumBytes != 0 && "undefined behavior");
|
||||
size_t BytesToWrite = Size - (Size % NumBytes);
|
||||
flush_tied_then_write(Ptr, BytesToWrite);
|
||||
size_t BytesRemaining = Size - BytesToWrite;
|
||||
if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) {
|
||||
// Too much left over to copy into our buffer.
|
||||
return write(Ptr + BytesToWrite, BytesRemaining);
|
||||
}
|
||||
copy_to_buffer(Ptr + BytesToWrite, BytesRemaining);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// We don't have enough space in the buffer to fit the string in. Insert as
|
||||
// much as possible, flush and start over with the remainder.
|
||||
copy_to_buffer(Ptr, NumBytes);
|
||||
flush_nonempty();
|
||||
return write(Ptr + NumBytes, Size - NumBytes);
|
||||
}
|
||||
|
||||
copy_to_buffer(Ptr, Size);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
|
||||
assert(Size <= size_t(OutBufEnd - OutBufCur) && "Buffer overrun!");
|
||||
|
||||
// Handle short strings specially, memcpy isn't very good at very short
|
||||
// strings.
|
||||
switch (Size) {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
OutBufCur += Size;
|
||||
}
|
||||
|
||||
void raw_ostream::flush_tied_then_write(const char *Ptr, size_t Size) {
|
||||
if (TiedStream)
|
||||
TiedStream->flush();
|
||||
write_impl(Ptr, Size);
|
||||
}
|
||||
|
||||
|
||||
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() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_fd_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static int getFD(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp, fs::FileAccess Access,
|
||||
fs::OpenFlags Flags) {
|
||||
assert((Access & fs::FA_Write) &&
|
||||
"Cannot make a raw_ostream from a read-only descriptor!");
|
||||
|
||||
// Handle "-" as stdout. Note that when we do this, we consider ourself
|
||||
// the owner of stdout and may set the "binary" flag globally based on Flags.
|
||||
if (Filename == "-") {
|
||||
EC = std::error_code();
|
||||
// Change stdout's text/binary mode based on the Flags.
|
||||
if (!(Flags & fs::OF_Text)) {
|
||||
#if defined(_WIN32)
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
}
|
||||
return STDOUT_FILENO;
|
||||
}
|
||||
|
||||
fs::file_t F;
|
||||
if (Access & fs::FA_Read)
|
||||
F = fs::OpenFileForReadWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
|
||||
else
|
||||
F = fs::OpenFileForWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
|
||||
if (EC)
|
||||
return -1;
|
||||
int FD = fs::FileToFd(F, EC, Flags);
|
||||
if (EC)
|
||||
return -1;
|
||||
|
||||
return FD;
|
||||
}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp)
|
||||
: raw_fd_ostream(Filename, EC, Disp, fs::FA_Write, fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::FileAccess Access)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, Access,
|
||||
fs::OF_None) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::OpenFlags Flags)
|
||||
: raw_fd_ostream(Filename, EC, fs::CD_CreateAlways, fs::FA_Write,
|
||||
Flags) {}
|
||||
|
||||
raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp,
|
||||
fs::FileAccess Access,
|
||||
fs::OpenFlags Flags)
|
||||
: raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {}
|
||||
|
||||
/// 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,
|
||||
OStreamKind K)
|
||||
: raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
|
||||
if (FD < 0 ) {
|
||||
ShouldClose = false;
|
||||
return;
|
||||
}
|
||||
|
||||
enable_colors(true);
|
||||
|
||||
// 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;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Check if this is a console device. This is not equivalent to isatty.
|
||||
IsWindowsConsole =
|
||||
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
|
||||
#endif
|
||||
|
||||
// Get the starting position.
|
||||
off_t loc = ::lseek(FD, 0, SEEK_CUR);
|
||||
#ifdef _WIN32
|
||||
SupportsSeeking = loc != (off_t)-1 && ::GetFileType(reinterpret_cast<HANDLE>(::_get_osfhandle(FD))) != FILE_TYPE_PIPE;
|
||||
#else
|
||||
SupportsSeeking = loc != (off_t)-1;
|
||||
#endif
|
||||
if (!SupportsSeeking)
|
||||
pos = 0;
|
||||
else
|
||||
pos = static_cast<uint64_t>(loc);
|
||||
}
|
||||
|
||||
raw_fd_ostream::~raw_fd_ostream() {
|
||||
if (FD >= 0) {
|
||||
flush();
|
||||
if (ShouldClose && ::close(FD) < 0)
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// On mingw, global dtors should not call exit().
|
||||
// report_fatal_error() invokes exit(). We know report_fatal_error()
|
||||
// might not write messages to stderr when any errors were detected
|
||||
// on FD == 2.
|
||||
if (FD == 2) return;
|
||||
#endif
|
||||
|
||||
// If there are any pending errors, report them now. Clients wishing
|
||||
// to avoid report_fatal_error calls should check for errors with
|
||||
// has_error() and clear the error flag with clear_error() before
|
||||
// destructing raw_ostream objects which may have errors.
|
||||
if (has_error())
|
||||
report_fatal_error("IO failure on output stream: " + error().message(),
|
||||
/*gen_crash_diag=*/false);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
// The most reliable way to print unicode in a Windows console is with
|
||||
// WriteConsoleW. To use that, first transcode from UTF-8 to UTF-16. This
|
||||
// assumes that LLVM programs always print valid UTF-8 to the console. The data
|
||||
// might not be UTF-8 for two major reasons:
|
||||
// 1. The program is printing binary (-filetype=obj -o -), in which case it
|
||||
// would have been gibberish anyway.
|
||||
// 2. The program is printing text in a semi-ascii compatible codepage like
|
||||
// shift-jis or cp1252.
|
||||
//
|
||||
// Most LLVM programs don't produce non-ascii text unless they are quoting
|
||||
// user source input. A well-behaved LLVM program should either validate that
|
||||
// the input is UTF-8 or transcode from the local codepage to UTF-8 before
|
||||
// quoting it. If they don't, this may mess up the encoding, but this is still
|
||||
// probably the best compromise we can make.
|
||||
static bool write_console_impl(int FD, std::string_view Data) {
|
||||
SmallVector<wchar_t, 256> WideText;
|
||||
|
||||
// Fall back to ::write if it wasn't valid UTF-8.
|
||||
if (auto EC = sys::windows::UTF8ToUTF16(Data, WideText))
|
||||
return false;
|
||||
|
||||
// On Windows 7 and earlier, WriteConsoleW has a low maximum amount of data
|
||||
// that can be written to the console at a time.
|
||||
size_t MaxWriteSize = WideText.size();
|
||||
if (!RunningWindows8OrGreater())
|
||||
MaxWriteSize = 32767;
|
||||
|
||||
size_t WCharsWritten = 0;
|
||||
do {
|
||||
size_t WCharsToWrite =
|
||||
std::min(MaxWriteSize, WideText.size() - WCharsWritten);
|
||||
DWORD ActuallyWritten;
|
||||
bool Success =
|
||||
::WriteConsoleW((HANDLE)::_get_osfhandle(FD), &WideText[WCharsWritten],
|
||||
WCharsToWrite, &ActuallyWritten,
|
||||
/*Reserved=*/nullptr);
|
||||
|
||||
// The most likely reason for WriteConsoleW to fail is that FD no longer
|
||||
// points to a console. Fall back to ::write. If this isn't the first loop
|
||||
// iteration, something is truly wrong.
|
||||
if (!Success)
|
||||
return false;
|
||||
|
||||
WCharsWritten += ActuallyWritten;
|
||||
} while (WCharsWritten != WideText.size());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
assert(FD >= 0 && "File already closed.");
|
||||
pos += Size;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// If this is a Windows console device, try re-encoding from UTF-8 to UTF-16
|
||||
// and using WriteConsoleW. If that fails, fall back to plain write().
|
||||
if (IsWindowsConsole)
|
||||
if (write_console_impl(FD, std::string_view(Ptr, Size)))
|
||||
return;
|
||||
#endif
|
||||
|
||||
// The maximum write size is limited to INT32_MAX. A write
|
||||
// greater than SSIZE_MAX is implementation-defined in POSIX,
|
||||
// and Windows _write requires 32 bit input.
|
||||
size_t MaxWriteSize = INT32_MAX;
|
||||
|
||||
#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;
|
||||
#endif
|
||||
|
||||
do {
|
||||
size_t ChunkSize = std::min(Size, MaxWriteSize);
|
||||
#ifdef _WIN32
|
||||
int ret = ::_write(FD, Ptr, ChunkSize);
|
||||
#else
|
||||
ssize_t ret = ::write(FD, Ptr, ChunkSize);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
// If it's a recoverable error, swallow it and retry the write.
|
||||
//
|
||||
// Ideally we wouldn't ever see EAGAIN or EWOULDBLOCK here, since
|
||||
// raw_ostream isn't designed to do non-blocking I/O. However, some
|
||||
// programs, such as old versions of bjam, have mistakenly used
|
||||
// O_NONBLOCK. For compatibility, emulate blocking semantics by
|
||||
// spinning until the write succeeds. If you don't want spinning,
|
||||
// don't use O_NONBLOCK file descriptors with raw_ostream.
|
||||
if (errno == EINTR || errno == EAGAIN
|
||||
#ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
// Otherwise it's a non-recoverable error. Note it and quit.
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
break;
|
||||
}
|
||||
|
||||
// The write may have written some or all of the data. Update the
|
||||
// size and buffer pointer to reflect the remainder that needs
|
||||
// to be written. If there are no bytes left, we're done.
|
||||
Ptr += ret;
|
||||
Size -= ret;
|
||||
} while (Size > 0);
|
||||
}
|
||||
|
||||
void raw_fd_ostream::close() {
|
||||
assert(ShouldClose);
|
||||
ShouldClose = false;
|
||||
flush();
|
||||
if (::close(FD) < 0)
|
||||
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(std::error_code(errno, std::generic_category()));
|
||||
return pos;
|
||||
}
|
||||
|
||||
void raw_fd_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
uint64_t Pos = tell();
|
||||
seek(Offset);
|
||||
write(Ptr, Size);
|
||||
seek(Pos);
|
||||
}
|
||||
|
||||
size_t raw_fd_ostream::preferred_buffer_size() const {
|
||||
#if defined(_WIN32)
|
||||
// Disable buffering for console devices. Console output is re-encoded from
|
||||
// UTF-8 to UTF-16 on Windows, and buffering it would require us to split the
|
||||
// buffer on a valid UTF-8 codepoint boundary. Terminal buffering is disabled
|
||||
// below on most other OSs, so do the same thing on Windows and avoid that
|
||||
// complexity.
|
||||
if (IsWindowsConsole)
|
||||
return 0;
|
||||
return raw_ostream::preferred_buffer_size();
|
||||
#elif !defined(__minix)
|
||||
// Minix has no st_blksize.
|
||||
assert(FD >= 0 && "File not yet open!");
|
||||
struct stat statbuf;
|
||||
if (fstat(FD, &statbuf) != 0)
|
||||
return 0;
|
||||
|
||||
// If this is a terminal, don't use buffering. Line buffering
|
||||
// would be a more traditional thing to do, but it's not worth
|
||||
// the complexity.
|
||||
if (S_ISCHR(statbuf.st_mode) && is_displayed())
|
||||
return 0;
|
||||
// Return the preferred block size.
|
||||
return statbuf.st_blksize;
|
||||
#else
|
||||
return raw_ostream::preferred_buffer_size();
|
||||
#endif
|
||||
}
|
||||
|
||||
void raw_fd_ostream::anchor() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// outs(), errs(), nulls()
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_fd_ostream &wpi::outs() {
|
||||
// Set buffer settings to model stdout behavior.
|
||||
std::error_code EC;
|
||||
static raw_fd_ostream* S = new raw_fd_ostream("-", EC, fs::OF_None);
|
||||
assert(!EC);
|
||||
return *S;
|
||||
}
|
||||
|
||||
raw_fd_ostream &wpi::errs() {
|
||||
// Set standard error to be unbuffered and tied to outs() by default.
|
||||
static raw_fd_ostream* S = new raw_fd_ostream(STDERR_FILENO, false, true);
|
||||
return *S;
|
||||
}
|
||||
|
||||
/// nulls() - This returns a reference to a raw_ostream which discards output.
|
||||
raw_ostream &wpi::nulls() {
|
||||
static raw_null_ostream S;
|
||||
return S;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_fd_stream::raw_fd_stream(std::string_view Filename, std::error_code &EC)
|
||||
: raw_fd_ostream(getFD(Filename, EC, fs::CD_CreateAlways,
|
||||
fs::FA_Write | fs::FA_Read,
|
||||
fs::OF_None),
|
||||
true, false, OStreamKind::OK_FDStream) {
|
||||
if (EC)
|
||||
return;
|
||||
|
||||
// Do not support non-seekable files.
|
||||
if (!supportsSeeking())
|
||||
EC = std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
bool raw_fd_stream::classof(const raw_ostream *OS) {
|
||||
return OS->get_kind() == OStreamKind::OK_FDStream;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_string_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_string_ostream::~raw_string_ostream() {
|
||||
flush();
|
||||
}
|
||||
|
||||
void raw_string_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.append(Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_svector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_svector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_svector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.append(Ptr, Ptr + Size);
|
||||
}
|
||||
|
||||
void raw_svector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_vector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_vector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_vector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.insert(OS.end(), Ptr, Ptr + Size);
|
||||
}
|
||||
|
||||
void raw_vector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_usvector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_usvector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_usvector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.append(reinterpret_cast<const uint8_t *>(Ptr),
|
||||
reinterpret_cast<const uint8_t *>(Ptr) + Size);
|
||||
}
|
||||
|
||||
void raw_usvector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_uvector_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
uint64_t raw_uvector_ostream::current_pos() const { return OS.size(); }
|
||||
|
||||
void raw_uvector_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
OS.insert(OS.end(), reinterpret_cast<const uint8_t *>(Ptr),
|
||||
reinterpret_cast<const uint8_t *>(Ptr) + Size);
|
||||
}
|
||||
|
||||
void raw_uvector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {
|
||||
memcpy(OS.data() + Offset, Ptr, Size);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_null_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
raw_null_ostream::~raw_null_ostream() {
|
||||
#ifndef NDEBUG
|
||||
// ~raw_ostream asserts that the buffer is empty. This isn't necessary
|
||||
// with raw_null_ostream, but it's better to have raw_null_ostream follow
|
||||
// the rules than to change the rules just for raw_null_ostream.
|
||||
flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
void raw_null_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
}
|
||||
|
||||
uint64_t raw_null_ostream::current_pos() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
||||
uint64_t Offset) {}
|
||||
|
||||
void raw_pwrite_stream::anchor() {}
|
||||
|
||||
void buffer_ostream::anchor() {}
|
||||
|
||||
void buffer_unique_ostream::anchor() {}
|
||||
34
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AlignOf.h
vendored
Normal file
34
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AlignOf.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the AlignedCharArrayUnion class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ALIGNOF_H
|
||||
#define WPIUTIL_WPI_ALIGNOF_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// A suitably aligned and sized character array member which can hold elements
|
||||
/// of any type.
|
||||
///
|
||||
/// This template is equivalent to std::aligned_union_t<1, ...>, but we cannot
|
||||
/// use it due to a bug in the MSVC x86 compiler:
|
||||
/// https://github.com/microsoft/STL/issues/1533
|
||||
/// Using `alignas` here works around the bug.
|
||||
template <typename T, typename... Ts> struct AlignedCharArrayUnion {
|
||||
using AlignedUnion = std::aligned_union_t<1, T, Ts...>;
|
||||
alignas(alignof(AlignedUnion)) char buffer[sizeof(AlignedUnion)];
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ALIGNOF_H
|
||||
103
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
vendored
Normal file
103
wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
//===- AllocatorBase.h - Simple memory allocation abstraction ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// This file defines MallocAllocator. MallocAllocator conforms to the LLVM
|
||||
/// "Allocator" concept which consists of an Allocate method accepting a size
|
||||
/// and alignment, and a Deallocate accepting a pointer and size. Further, the
|
||||
/// LLVM "Allocator" concept has overloads of Allocate and Deallocate for
|
||||
/// setting size and alignment based on the final type. These overloads are
|
||||
/// typically provided by a base class template \c AllocatorBase.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ALLOCATORBASE_H
|
||||
#define WPIUTIL_WPI_ALLOCATORBASE_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// CRTP base class providing obvious overloads for the core \c
|
||||
/// Allocate() methods of LLVM-style allocators.
|
||||
///
|
||||
/// This base class both documents the full public interface exposed by all
|
||||
/// LLVM-style allocators, and redirects all of the overloads to a single core
|
||||
/// set of methods which the derived class must define.
|
||||
template <typename DerivedT> class AllocatorBase {
|
||||
public:
|
||||
/// Allocate \a Size bytes of \a Alignment aligned memory. This method
|
||||
/// must be implemented by \c DerivedT.
|
||||
void *Allocate(size_t Size, size_t Alignment) {
|
||||
#ifdef __clang__
|
||||
static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>(
|
||||
&AllocatorBase::Allocate) !=
|
||||
static_cast<void *(DerivedT::*)(size_t, size_t)>(
|
||||
&DerivedT::Allocate),
|
||||
"Class derives from AllocatorBase without implementing the "
|
||||
"core Allocate(size_t, size_t) overload!");
|
||||
#endif
|
||||
return static_cast<DerivedT *>(this)->Allocate(Size, Alignment);
|
||||
}
|
||||
|
||||
/// Deallocate \a Ptr to \a Size bytes of memory allocated by this
|
||||
/// allocator.
|
||||
void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
|
||||
#ifdef __clang__
|
||||
static_assert(
|
||||
static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>(
|
||||
&AllocatorBase::Deallocate) !=
|
||||
static_cast<void (DerivedT::*)(const void *, size_t, size_t)>(
|
||||
&DerivedT::Deallocate),
|
||||
"Class derives from AllocatorBase without implementing the "
|
||||
"core Deallocate(void *) overload!");
|
||||
#endif
|
||||
return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment);
|
||||
}
|
||||
|
||||
// The rest of these methods are helpers that redirect to one of the above
|
||||
// core methods.
|
||||
|
||||
/// Allocate space for a sequence of objects without constructing them.
|
||||
template <typename T> T *Allocate(size_t Num = 1) {
|
||||
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
|
||||
}
|
||||
|
||||
/// Deallocate space for a sequence of objects without constructing them.
|
||||
template <typename T>
|
||||
std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void>
|
||||
Deallocate(T *Ptr, size_t Num = 1) {
|
||||
Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T));
|
||||
}
|
||||
};
|
||||
|
||||
class MallocAllocator : public AllocatorBase<MallocAllocator> {
|
||||
public:
|
||||
void Reset() {}
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) {
|
||||
return allocate_buffer(Size, Alignment);
|
||||
}
|
||||
|
||||
// Pull in base class overloads.
|
||||
using AllocatorBase<MallocAllocator>::Allocate;
|
||||
|
||||
void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
|
||||
deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment);
|
||||
}
|
||||
|
||||
// Pull in base class overloads.
|
||||
using AllocatorBase<MallocAllocator>::Deallocate;
|
||||
|
||||
void PrintStats() const {}
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ALLOCATORBASE_H
|
||||
62
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Chrono.h
vendored
Normal file
62
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Chrono.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_CHRONO_H
|
||||
#define WPIUTIL_WPI_CHRONO_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
namespace sys {
|
||||
|
||||
/// A time point on the system clock. This is provided for two reasons:
|
||||
/// - to insulate us against subtle differences in behavior to differences in
|
||||
/// system clock precision (which is implementation-defined and differs between
|
||||
/// platforms).
|
||||
/// - to shorten the type name
|
||||
/// The default precision is nanoseconds. If need a specific precision specify
|
||||
/// it explicitly. If unsure, use the default. If you need a time point on a
|
||||
/// clock other than the system_clock, use std::chrono directly.
|
||||
template <typename D = std::chrono::nanoseconds>
|
||||
using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
|
||||
|
||||
/// Convert a TimePoint to std::time_t
|
||||
inline std::time_t toTimeT(TimePoint<> TP) {
|
||||
using namespace std::chrono;
|
||||
return system_clock::to_time_t(
|
||||
time_point_cast<system_clock::time_point::duration>(TP));
|
||||
}
|
||||
|
||||
/// Convert a std::time_t to a TimePoint
|
||||
inline TimePoint<std::chrono::seconds>
|
||||
toTimePoint(std::time_t T) {
|
||||
using namespace std::chrono;
|
||||
return time_point_cast<seconds>(system_clock::from_time_t(T));
|
||||
}
|
||||
|
||||
/// Convert a std::time_t + nanoseconds to a TimePoint
|
||||
inline TimePoint<>
|
||||
toTimePoint(std::time_t T, uint32_t nsec) {
|
||||
using namespace std::chrono;
|
||||
return time_point_cast<nanoseconds>(system_clock::from_time_t(T))
|
||||
+ nanoseconds(nsec);
|
||||
}
|
||||
|
||||
} // namespace sys
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_CHRONO_H
|
||||
599
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
vendored
Normal file
599
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
vendored
Normal file
@@ -0,0 +1,599 @@
|
||||
//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines several macros, based on the current compiler. This allows
|
||||
// use of compiler-specific features in a way that remains portable. This header
|
||||
// can be included from either C or C++.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_COMPILER_H
|
||||
#define WPIUTIL_WPI_COMPILER_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <new>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_extension
|
||||
# define __has_extension(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
|
||||
// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
|
||||
#ifndef LLVM_HAS_CPP_ATTRIBUTE
|
||||
#if defined(__cplusplus) && defined(__has_cpp_attribute)
|
||||
# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
||||
#else
|
||||
# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_GNUC_PREREQ
|
||||
/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
|
||||
/// available.
|
||||
#ifndef LLVM_GNUC_PREREQ
|
||||
# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
|
||||
((maj) << 20) + ((min) << 10) + (patch))
|
||||
# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
|
||||
# else
|
||||
# define LLVM_GNUC_PREREQ(maj, min, patch) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_MSC_PREREQ
|
||||
/// Is the compiler MSVC of at least the specified version?
|
||||
/// The common \param version values to check for are:
|
||||
/// * 1910: VS2017, version 15.1 & 15.2
|
||||
/// * 1911: VS2017, version 15.3 & 15.4
|
||||
/// * 1912: VS2017, version 15.5
|
||||
/// * 1913: VS2017, version 15.6
|
||||
/// * 1914: VS2017, version 15.7
|
||||
/// * 1915: VS2017, version 15.8
|
||||
/// * 1916: VS2017, version 15.9
|
||||
/// * 1920: VS2019, version 16.0
|
||||
/// * 1921: VS2019, version 16.1
|
||||
#ifndef LLVM_MSC_PREREQ
|
||||
#ifdef _MSC_VER
|
||||
#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
|
||||
|
||||
// We require at least MSVC 2017.
|
||||
#if !LLVM_MSC_PREREQ(1910)
|
||||
#error LLVM requires at least MSVC 2017.
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define LLVM_MSC_PREREQ(version) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Does the compiler support ref-qualifiers for *this?
|
||||
///
|
||||
/// Sadly, this is separate from just rvalue reference support because GCC
|
||||
/// and MSVC implemented this later than everything else. This appears to be
|
||||
/// corrected in MSVC 2019 but not MSVC 2017.
|
||||
#ifndef LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1) || \
|
||||
LLVM_MSC_PREREQ(1920)
|
||||
#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
|
||||
#else
|
||||
#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Expands to '&' if ref-qualifiers for *this are supported.
|
||||
///
|
||||
/// This can be used to provide lvalue/rvalue overrides of member functions.
|
||||
/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#ifndef LLVM_LVALUE_FUNCTION
|
||||
#if LLVM_HAS_RVALUE_REFERENCE_THIS
|
||||
#define LLVM_LVALUE_FUNCTION &
|
||||
#else
|
||||
#define LLVM_LVALUE_FUNCTION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
|
||||
/// into a shared library, then the class should be private to the library and
|
||||
/// not accessible from outside it. Can also be used to mark variables and
|
||||
/// functions, making them private to any shared library they are linked into.
|
||||
/// On PE/COFF targets, library visibility is the default, so this isn't needed.
|
||||
///
|
||||
/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
|
||||
/// this attribute will be made public and visible outside of any shared library
|
||||
/// they are linked in to.
|
||||
#if (__has_attribute(visibility) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
|
||||
!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32)
|
||||
#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
|
||||
#define LLVM_EXTERNAL_VISIBILITY __attribute__ ((visibility("default")))
|
||||
#else
|
||||
#define LLVM_LIBRARY_VISIBILITY
|
||||
#define LLVM_EXTERNAL_VISIBILITY
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_PREFETCH
|
||||
#if defined(__GNUC__)
|
||||
#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
|
||||
#else
|
||||
#define LLVM_PREFETCH(addr, rw, locality)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_USED
|
||||
#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
|
||||
#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_NODISCARD - Warn if a type or return value is discarded.
|
||||
|
||||
// Use the 'nodiscard' attribute in C++17 or newer mode.
|
||||
#ifndef LLVM_NODISCARD
|
||||
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
|
||||
#define LLVM_NODISCARD [[nodiscard]]
|
||||
#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result)
|
||||
#define LLVM_NODISCARD [[clang::warn_unused_result]]
|
||||
// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also
|
||||
// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518).
|
||||
// Use the 'nodiscard' attribute in C++14 mode only with GCC.
|
||||
// TODO: remove this workaround when PR33518 is resolved.
|
||||
#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
|
||||
#define LLVM_NODISCARD [[nodiscard]]
|
||||
#else
|
||||
#define LLVM_NODISCARD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Indicate that a non-static, non-const C++ member function reinitializes
|
||||
// the entire object to a known state, independent of the previous state of
|
||||
// the object.
|
||||
//
|
||||
// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
|
||||
// marker that a moved-from object has left the indeterminate state and can be
|
||||
// reused.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes)
|
||||
#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_REINITIALIZES
|
||||
#endif
|
||||
|
||||
// Some compilers warn about unused functions. When a function is sometimes
|
||||
// used or not depending on build settings (e.g. a function only called from
|
||||
// within "assert"), this attribute can be used to suppress such warnings.
|
||||
//
|
||||
// However, it shouldn't be used for unused *variables*, as those have a much
|
||||
// more portable solution:
|
||||
// (void)unused_var_name;
|
||||
// Prefer cast-to-void wherever it is sufficient.
|
||||
#ifndef LLVM_ATTRIBUTE_UNUSED
|
||||
#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0)
|
||||
#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_UNUSED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// FIXME: Provide this for PE/COFF targets.
|
||||
#if (__has_attribute(weak) || LLVM_GNUC_PREREQ(4, 0, 0)) && \
|
||||
(!defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32))
|
||||
#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_WEAK
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_READNONE
|
||||
// Prior to clang 3.2, clang did not accept any spelling of
|
||||
// __has_attribute(const), so assume it is supported.
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
// aka 'CONST' but following LLVM Conventions.
|
||||
#define LLVM_READNONE __attribute__((__const__))
|
||||
#else
|
||||
#define LLVM_READNONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_READONLY
|
||||
#if __has_attribute(pure) || defined(__GNUC__)
|
||||
// aka 'PURE' but following LLVM Conventions.
|
||||
#define LLVM_READONLY __attribute__((__pure__))
|
||||
#else
|
||||
#define LLVM_READONLY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_LIKELY
|
||||
#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
|
||||
#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
|
||||
#else
|
||||
#define LLVM_LIKELY(EXPR) (EXPR)
|
||||
#define LLVM_UNLIKELY(EXPR) (EXPR)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
|
||||
/// mark a method "not for inlining".
|
||||
#ifndef LLVM_ATTRIBUTE_NOINLINE
|
||||
#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
|
||||
#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
|
||||
/// so, mark a method "always inline" because it is performance sensitive. GCC
|
||||
/// 3.4 supported this but is buggy in various cases and produces unimplemented
|
||||
/// errors, just use it in GCC 4.0 and later.
|
||||
#ifndef LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||
#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_NORETURN
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_NORETURN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
|
||||
/// pointer that does not alias any other valid pointer.
|
||||
#ifndef LLVM_ATTRIBUTE_RETURNS_NOALIAS
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
|
||||
#else
|
||||
#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
|
||||
#ifndef LLVM_FALLTHROUGH
|
||||
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[fallthrough]]
|
||||
#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
|
||||
#elif __has_attribute(fallthrough)
|
||||
#define LLVM_FALLTHROUGH __attribute__((fallthrough))
|
||||
#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
|
||||
#define LLVM_FALLTHROUGH [[clang::fallthrough]]
|
||||
#else
|
||||
#define LLVM_FALLTHROUGH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
|
||||
/// they are constant initialized.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
||||
#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \
|
||||
[[clang::require_constant_initialization]]
|
||||
#else
|
||||
#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
|
||||
#endif
|
||||
|
||||
/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable
|
||||
/// lifetime warnings.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner)
|
||||
#define LLVM_GSL_OWNER [[gsl::Owner]]
|
||||
#else
|
||||
#define LLVM_GSL_OWNER
|
||||
#endif
|
||||
|
||||
/// LLVM_GSL_POINTER - Apply this to non-owning classes like
|
||||
/// std::string_view to enable lifetime warnings.
|
||||
#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer)
|
||||
#define LLVM_GSL_POINTER [[gsl::Pointer]]
|
||||
#else
|
||||
#define LLVM_GSL_POINTER
|
||||
#endif
|
||||
|
||||
/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
|
||||
/// pedantic diagnostics.
|
||||
#ifndef LLVM_EXTENSION
|
||||
#ifdef __GNUC__
|
||||
#define LLVM_EXTENSION __extension__
|
||||
#else
|
||||
#define LLVM_EXTENSION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
|
||||
// This macro will be removed.
|
||||
// Use C++14's attribute instead: [[deprecated("message")]]
|
||||
#ifndef LLVM_ATTRIBUTE_DEPRECATED
|
||||
#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
|
||||
/// to an expression which states that it is undefined behavior for the
|
||||
/// compiler to reach this point. Otherwise is not defined.
|
||||
#ifndef LLVM_BUILTIN_UNREACHABLE
|
||||
#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
|
||||
#elif defined(_MSC_VER)
|
||||
# define LLVM_BUILTIN_UNREACHABLE __assume(false)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
|
||||
/// which causes the program to exit abnormally.
|
||||
#ifndef LLVM_BUILTIN_TRAP
|
||||
#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0)
|
||||
# define LLVM_BUILTIN_TRAP __builtin_trap()
|
||||
#elif defined(_MSC_VER)
|
||||
// The __debugbreak intrinsic is supported by MSVC, does not require forward
|
||||
// declarations involving platform-specific typedefs (unlike RaiseException),
|
||||
// results in a call to vectored exception handlers, and encodes to a short
|
||||
// instruction that still causes the trapping behavior we want.
|
||||
# define LLVM_BUILTIN_TRAP __debugbreak()
|
||||
#else
|
||||
# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
|
||||
/// an expression which causes the program to break while running
|
||||
/// under a debugger.
|
||||
#ifndef LLVM_BUILTIN_DEBUGTRAP
|
||||
#if __has_builtin(__builtin_debugtrap)
|
||||
# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
|
||||
#elif defined(_MSC_VER)
|
||||
// The __debugbreak intrinsic is supported by MSVC and breaks while
|
||||
// running under the debugger, and also supports invoking a debugger
|
||||
// when the OS is configured appropriately.
|
||||
# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
|
||||
#else
|
||||
// Just continue execution when built with compilers that have no
|
||||
// support. This is a debugging aid and not intended to force the
|
||||
// program to abort if encountered.
|
||||
# define LLVM_BUILTIN_DEBUGTRAP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ASSUME_ALIGNED
|
||||
/// Returns a pointer with an assumed alignment.
|
||||
#ifndef LLVM_ASSUME_ALIGNED
|
||||
#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
|
||||
#elif defined(LLVM_BUILTIN_UNREACHABLE)
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) \
|
||||
(((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
|
||||
#else
|
||||
# define LLVM_ASSUME_ALIGNED(p, a) (p)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PACKED
|
||||
/// Used to specify a packed structure.
|
||||
/// LLVM_PACKED(
|
||||
/// struct A {
|
||||
/// int i;
|
||||
/// int j;
|
||||
/// int k;
|
||||
/// long long l;
|
||||
/// });
|
||||
///
|
||||
/// LLVM_PACKED_START
|
||||
/// struct B {
|
||||
/// int i;
|
||||
/// int j;
|
||||
/// int k;
|
||||
/// long long l;
|
||||
/// };
|
||||
/// LLVM_PACKED_END
|
||||
#ifndef LLVM_PACKED
|
||||
#ifdef _MSC_VER
|
||||
# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
|
||||
# define LLVM_PACKED_START __pragma(pack(push, 1))
|
||||
# define LLVM_PACKED_END __pragma(pack(pop))
|
||||
#else
|
||||
# define LLVM_PACKED(d) d __attribute__((packed))
|
||||
# define LLVM_PACKED_START _Pragma("pack(push, 1)")
|
||||
# define LLVM_PACKED_END _Pragma("pack(pop)")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PTR_SIZE
|
||||
/// A constant integer equivalent to the value of sizeof(void*).
|
||||
/// Generally used in combination with alignas or when doing computation in the
|
||||
/// preprocessor.
|
||||
#ifndef LLVM_PTR_SIZE
|
||||
#ifdef __SIZEOF_POINTER__
|
||||
# define LLVM_PTR_SIZE __SIZEOF_POINTER__
|
||||
#elif defined(_WIN64)
|
||||
# define LLVM_PTR_SIZE 8
|
||||
#elif defined(_WIN32)
|
||||
# define LLVM_PTR_SIZE 4
|
||||
#elif defined(_MSC_VER)
|
||||
# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
|
||||
#else
|
||||
# define LLVM_PTR_SIZE sizeof(void *)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_MEMORY_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with MemorySanitizer instrumentation.
|
||||
#if __has_feature(memory_sanitizer)
|
||||
# define LLVM_MEMORY_SANITIZER_BUILD 1
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory))
|
||||
#else
|
||||
# define LLVM_MEMORY_SANITIZER_BUILD 0
|
||||
# define __msan_allocated_memory(p, size)
|
||||
# define __msan_unpoison(p, size)
|
||||
# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ADDRESS_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with AddressSanitizer instrumentation.
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
# define LLVM_ADDRESS_SANITIZER_BUILD 1
|
||||
# include <sanitizer/asan_interface.h>
|
||||
#else
|
||||
# define LLVM_ADDRESS_SANITIZER_BUILD 0
|
||||
# define __asan_poison_memory_region(p, size)
|
||||
# define __asan_unpoison_memory_region(p, size)
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_THREAD_SANITIZER_BUILD
|
||||
/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
|
||||
#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
|
||||
# define LLVM_THREAD_SANITIZER_BUILD 1
|
||||
#else
|
||||
# define LLVM_THREAD_SANITIZER_BUILD 0
|
||||
#endif
|
||||
|
||||
#if LLVM_THREAD_SANITIZER_BUILD
|
||||
// Thread Sanitizer is a tool that finds races in code.
|
||||
// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
|
||||
// tsan detects these exact functions by name.
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
|
||||
void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
|
||||
void AnnotateIgnoreWritesBegin(const char *file, int line);
|
||||
void AnnotateIgnoreWritesEnd(const char *file, int line);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// This marker is used to define a happens-before arc. The race detector will
|
||||
// infer an arc from the begin to the end when they share the same pointer
|
||||
// argument.
|
||||
# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
|
||||
|
||||
// This marker defines the destination of a happens-before arc.
|
||||
# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
|
||||
|
||||
// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
|
||||
# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
||||
|
||||
// Resume checking for racy writes.
|
||||
# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
||||
#else
|
||||
# define TsanHappensBefore(cv)
|
||||
# define TsanHappensAfter(cv)
|
||||
# define TsanIgnoreWritesBegin()
|
||||
# define TsanIgnoreWritesEnd()
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_NO_SANITIZE
|
||||
/// Disable a particular sanitizer for a function.
|
||||
#ifndef LLVM_NO_SANITIZE
|
||||
#if __has_attribute(no_sanitize)
|
||||
#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
|
||||
#else
|
||||
#define LLVM_NO_SANITIZE(KIND)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Mark debug helper function definitions like dump() that should not be
|
||||
/// stripped from debug builds.
|
||||
/// Note that you should also surround dump() functions with
|
||||
/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
|
||||
/// get stripped in release builds.
|
||||
// FIXME: Move this to a private config.h as it's not usable in public headers.
|
||||
#ifndef LLVM_DUMP_METHOD
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
|
||||
#else
|
||||
#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PRETTY_FUNCTION
|
||||
/// Gets a user-friendly looking function signature for the current scope
|
||||
/// using the best available method on each platform. The exact format of the
|
||||
/// resulting string is implementation specific and non-portable, so this should
|
||||
/// only be used, for example, for logging or diagnostics.
|
||||
#ifndef LLVM_PRETTY_FUNCTION
|
||||
#if defined(_MSC_VER)
|
||||
#define LLVM_PRETTY_FUNCTION __FUNCSIG__
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define LLVM_PRETTY_FUNCTION __func__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_THREAD_LOCAL
|
||||
/// A thread-local storage specifier which can be used with globals,
|
||||
/// extern globals, and static globals.
|
||||
///
|
||||
/// This is essentially an extremely restricted analog to C++11's thread_local
|
||||
/// support. It uses thread_local if available, falling back on gcc __thread
|
||||
/// if not. __thread doesn't support many of the C++11 thread_local's
|
||||
/// features. You should only use this for PODs that you can statically
|
||||
/// initialize to some constant value. In almost all circumstances this is most
|
||||
/// appropriate for use with a pointer, integer, or small aggregation of
|
||||
/// pointers and integers.
|
||||
#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
|
||||
#define LLVM_THREAD_LOCAL thread_local
|
||||
#else
|
||||
// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
|
||||
// we only need the restricted functionality that provides.
|
||||
#define LLVM_THREAD_LOCAL __thread
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_ENABLE_EXCEPTIONS
|
||||
/// Whether LLVM is built with exception support.
|
||||
#if __has_feature(cxx_exceptions)
|
||||
#define LLVM_ENABLE_EXCEPTIONS 1
|
||||
#elif defined(__GNUC__) && defined(__EXCEPTIONS)
|
||||
#define LLVM_ENABLE_EXCEPTIONS 1
|
||||
#elif defined(_MSC_VER) && defined(_CPPUNWIND)
|
||||
#define LLVM_ENABLE_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
307
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
vendored
Normal file
307
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
|
||||
*
|
||||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
* See https://llvm.org/LICENSE.txt for license information.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*
|
||||
*==------------------------------------------------------------------------==*/
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||
|
||||
Several funtions are included here, forming a complete set of
|
||||
conversions between the three formats. UTF-7 is not included
|
||||
here, but is handled in a separate source file.
|
||||
|
||||
Each of these routines takes pointers to input buffers and output
|
||||
buffers. The input buffers are const.
|
||||
|
||||
Each routine converts the text between *sourceStart and sourceEnd,
|
||||
putting the result into the buffer between *targetStart and
|
||||
targetEnd. Note: the end pointers are *after* the last item: e.g.
|
||||
*(sourceEnd - 1) is the last item.
|
||||
|
||||
The return result indicates whether the conversion was successful,
|
||||
and if not, whether the problem was in the source or target buffers.
|
||||
(Only the first encountered problem is indicated.)
|
||||
|
||||
After the conversion, *sourceStart and *targetStart are both
|
||||
updated to point to the end of last text successfully converted in
|
||||
the respective buffers.
|
||||
|
||||
Input parameters:
|
||||
sourceStart - pointer to a pointer to the source buffer.
|
||||
The contents of this are modified on return so that
|
||||
it points at the next thing to be converted.
|
||||
targetStart - similarly, pointer to pointer to the target buffer.
|
||||
sourceEnd, targetEnd - respectively pointers to the ends of the
|
||||
two buffers, for overflow checking only.
|
||||
|
||||
These conversion functions take a ConversionFlags argument. When this
|
||||
flag is set to strict, both irregular sequences and isolated surrogates
|
||||
will cause an error. When the flag is set to lenient, both irregular
|
||||
sequences and isolated surrogates are converted.
|
||||
|
||||
Whether the flag is strict or lenient, all illegal sequences will cause
|
||||
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
|
||||
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
|
||||
must check for illegal sequences.
|
||||
|
||||
When the flag is set to lenient, characters over 0x10FFFF are converted
|
||||
to the replacement character; otherwise (when the flag is set to strict)
|
||||
they constitute an error.
|
||||
|
||||
Output parameters:
|
||||
The value "sourceIllegal" is returned from some routines if the input
|
||||
sequence is malformed. When "sourceIllegal" is returned, the source
|
||||
value will point to the illegal value that caused the problem. E.g.,
|
||||
in UTF-8 when a sequence is malformed, it points to the start of the
|
||||
malformed sequence.
|
||||
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Fixes & updates, Sept 2001.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
#ifndef WPIUTIL_WPI_CONVERTUTF_H
|
||||
#define WPIUTIL_WPI_CONVERTUTF_H
|
||||
|
||||
#include "wpi/span.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
// Wrap everything in namespace wpi so that programs can link with llvm and
|
||||
// their own version of the unicode libraries.
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific.
|
||||
The C standard does not guarantee that wchar_t has at least
|
||||
16 bits, so wchar_t is no less portable than unsigned short!
|
||||
All should be unsigned values to avoid sign extension during
|
||||
bit mask & shift operations.
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
typedef unsigned int UTF32; /* at least 32 bits */
|
||||
typedef unsigned short UTF16; /* at least 16 bits */
|
||||
typedef unsigned char UTF8; /* typically 8 bits */
|
||||
typedef bool Boolean; /* 0 or 1 */
|
||||
|
||||
/* Some fundamental constants */
|
||||
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
||||
#define UNI_MAX_BMP (UTF32)0x0000FFFF
|
||||
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
|
||||
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
|
||||
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
|
||||
|
||||
#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4
|
||||
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF
|
||||
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE
|
||||
|
||||
typedef enum {
|
||||
conversionOK, /* conversion successful */
|
||||
sourceExhausted, /* partial character in source, but hit end */
|
||||
targetExhausted, /* insuff. room in target for conversion */
|
||||
sourceIllegal /* source sequence is illegal/malformed */
|
||||
} ConversionResult;
|
||||
|
||||
typedef enum {
|
||||
strictConversion = 0,
|
||||
lenientConversion
|
||||
} ConversionFlags;
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
/**
|
||||
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
|
||||
* incomplete code unit sequence, returns \c sourceExhausted.
|
||||
*/
|
||||
ConversionResult ConvertUTF8toUTF32Partial(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
/**
|
||||
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
|
||||
* incomplete code unit sequence, returns \c sourceIllegal.
|
||||
*/
|
||||
ConversionResult ConvertUTF8toUTF32(
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
|
||||
|
||||
unsigned getNumBytesForUTF8(UTF8 firstByte);
|
||||
|
||||
/*************************************************************************/
|
||||
/* Below are LLVM-specific wrappers of the functions above. */
|
||||
|
||||
template <typename T> class SmallVectorImpl;
|
||||
|
||||
/**
|
||||
* Convert an UTF8 string_view to UTF8, UTF16, or UTF32 depending on
|
||||
* WideCharWidth. The converted data is written to ResultPtr, which needs to
|
||||
* point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
|
||||
* ResultPtr will point one after the end of the copied string. On failure,
|
||||
* ResultPtr will not be changed, and ErrorPtr will be set to the location of
|
||||
* the first character which could not be converted.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
|
||||
char *&ResultPtr, const UTF8 *&ErrorPtr);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string_view to a std::wstring.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 C-string to a std::wstring.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool ConvertUTF8toWide(const char *Source, std::wstring &Result);
|
||||
|
||||
/**
|
||||
* Converts a std::wstring to a UTF-8 encoded std::string.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result);
|
||||
|
||||
|
||||
/**
|
||||
* Convert an Unicode code point to UTF8 sequence.
|
||||
*
|
||||
* \param Source a Unicode code point.
|
||||
* \param [in,out] ResultPtr pointer to the output buffer, needs to be at least
|
||||
* \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is
|
||||
* updated one past end of the converted sequence.
|
||||
*
|
||||
* \returns true on success.
|
||||
*/
|
||||
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
|
||||
|
||||
/**
|
||||
* Convert the first UTF8 sequence in the given source buffer to a UTF32
|
||||
* code point.
|
||||
*
|
||||
* \param [in,out] source A pointer to the source buffer. If the conversion
|
||||
* succeeds, this pointer will be updated to point to the byte just past the
|
||||
* end of the converted sequence.
|
||||
* \param sourceEnd A pointer just past the end of the source buffer.
|
||||
* \param [out] target The converted code
|
||||
* \param flags Whether the conversion is strict or lenient.
|
||||
*
|
||||
* \returns conversionOK on success
|
||||
*
|
||||
* \sa ConvertUTF8toUTF32
|
||||
*/
|
||||
inline ConversionResult convertUTF8Sequence(const UTF8 **source,
|
||||
const UTF8 *sourceEnd,
|
||||
UTF32 *target,
|
||||
ConversionFlags flags) {
|
||||
if (*source == sourceEnd)
|
||||
return sourceExhausted;
|
||||
unsigned size = getNumBytesForUTF8(**source);
|
||||
if ((ptrdiff_t)size > sourceEnd - *source)
|
||||
return sourceExhausted;
|
||||
return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a blob of text starts with a UTF-16 big or little endian byte
|
||||
* order mark.
|
||||
*/
|
||||
bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
|
||||
|
||||
/**
|
||||
* Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
|
||||
*
|
||||
* \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text.
|
||||
* \param [out] Out Converted UTF-8 is stored here on success.
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out);
|
||||
|
||||
/**
|
||||
* Converts a UTF16 string into a UTF8 std::string.
|
||||
*
|
||||
* \param [in] Src A buffer of UTF-16 encoded text.
|
||||
* \param [out] Out Converted UTF-8 is stored here on success.
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out);
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 string into a UTF-16 string with native endianness.
|
||||
*
|
||||
* \returns true on success
|
||||
*/
|
||||
bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
|
||||
SmallVectorImpl<UTF16> &DstUTF16);
|
||||
|
||||
#if defined(_WIN32)
|
||||
namespace sys {
|
||||
namespace windows {
|
||||
std::error_code UTF8ToUTF16(std::string_view utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
/// Convert to UTF16 from the current code page used in the system
|
||||
std::error_code CurCPToUTF16(std::string_view 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
|
||||
std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
|
||||
SmallVectorImpl<char> &utf8);
|
||||
} // namespace windows
|
||||
} // namespace sys
|
||||
#endif
|
||||
|
||||
} /* end namespace wpi */
|
||||
|
||||
#endif
|
||||
29
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
vendored
Normal file
29
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for the DJ Bernstein hash function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_DJB_H
|
||||
#define WPIUTIL_WPI_DJB_H
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// The Bernstein hash function used by the DWARF accelerator tables.
|
||||
inline uint32_t djbHash(std::string_view Buffer, uint32_t H = 5381) {
|
||||
for (unsigned char C : Buffer)
|
||||
H = (H << 5) + H + C;
|
||||
return H;
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_DJB_H
|
||||
1308
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
vendored
Normal file
1308
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
294
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
vendored
Normal file
294
wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines DenseMapInfo traits for DenseMap.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
#define WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
|
||||
#include "wpi/Hashing.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Simplistic combination of 32-bit hash values into 32-bit hash values.
|
||||
static inline unsigned combineHashValue(unsigned a, unsigned b) {
|
||||
uint64_t key = (uint64_t)a << 32 | (uint64_t)b;
|
||||
key += ~(key << 32);
|
||||
key ^= (key >> 22);
|
||||
key += ~(key << 13);
|
||||
key ^= (key >> 8);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 15);
|
||||
key += ~(key << 27);
|
||||
key ^= (key >> 31);
|
||||
return (unsigned)key;
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template<typename T>
|
||||
struct DenseMapInfo {
|
||||
//static inline T getEmptyKey();
|
||||
//static inline T getTombstoneKey();
|
||||
//static unsigned getHashValue(const T &Val);
|
||||
//static bool isEqual(const T &LHS, const T &RHS);
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all pointers. Come up with sentinel pointer values
|
||||
// that are aligned to alignof(T) bytes, but try to avoid requiring T to be
|
||||
// complete. This allows clients to instantiate DenseMap<T*, ...> with forward
|
||||
// declared key types. Assume that no pointer key type requires more than 4096
|
||||
// bytes of alignment.
|
||||
template<typename T>
|
||||
struct DenseMapInfo<T*> {
|
||||
// The following should hold, but it would require T to be complete:
|
||||
// static_assert(alignof(T) <= (1 << Log2MaxAlign),
|
||||
// "DenseMap does not support pointer keys requiring more than "
|
||||
// "Log2MaxAlign bits of alignment");
|
||||
static constexpr uintptr_t Log2MaxAlign = 12;
|
||||
|
||||
static inline T* getEmptyKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= Log2MaxAlign;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
|
||||
static inline T* getTombstoneKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||
Val <<= Log2MaxAlign;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const T *PtrVal) {
|
||||
return (unsigned((uintptr_t)PtrVal) >> 4) ^
|
||||
(unsigned((uintptr_t)PtrVal) >> 9);
|
||||
}
|
||||
|
||||
static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for chars.
|
||||
template<> struct DenseMapInfo<char> {
|
||||
static inline char getEmptyKey() { return ~0; }
|
||||
static inline char getTombstoneKey() { return ~0 - 1; }
|
||||
static unsigned getHashValue(const char& Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const char &LHS, const char &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned chars.
|
||||
template <> struct DenseMapInfo<unsigned char> {
|
||||
static inline unsigned char getEmptyKey() { return ~0; }
|
||||
static inline unsigned char getTombstoneKey() { return ~0 - 1; }
|
||||
static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned shorts.
|
||||
template <> struct DenseMapInfo<unsigned short> {
|
||||
static inline unsigned short getEmptyKey() { return 0xFFFF; }
|
||||
static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
|
||||
static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned ints.
|
||||
template<> struct DenseMapInfo<unsigned> {
|
||||
static inline unsigned getEmptyKey() { return ~0U; }
|
||||
static inline unsigned getTombstoneKey() { return ~0U - 1; }
|
||||
static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned longs.
|
||||
template<> struct DenseMapInfo<unsigned long> {
|
||||
static inline unsigned long getEmptyKey() { return ~0UL; }
|
||||
static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
|
||||
|
||||
static unsigned getHashValue(const unsigned long& Val) {
|
||||
return (unsigned)(Val * 37UL);
|
||||
}
|
||||
|
||||
static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned long longs.
|
||||
template<> struct DenseMapInfo<unsigned long long> {
|
||||
static inline unsigned long long getEmptyKey() { return ~0ULL; }
|
||||
static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
|
||||
|
||||
static unsigned getHashValue(const unsigned long long& Val) {
|
||||
return (unsigned)(Val * 37ULL);
|
||||
}
|
||||
|
||||
static bool isEqual(const unsigned long long& LHS,
|
||||
const unsigned long long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for shorts.
|
||||
template <> struct DenseMapInfo<short> {
|
||||
static inline short getEmptyKey() { return 0x7FFF; }
|
||||
static inline short getTombstoneKey() { return -0x7FFF - 1; }
|
||||
static unsigned getHashValue(const short &Val) { return Val * 37U; }
|
||||
static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for ints.
|
||||
template<> struct DenseMapInfo<int> {
|
||||
static inline int getEmptyKey() { return 0x7fffffff; }
|
||||
static inline int getTombstoneKey() { return -0x7fffffff - 1; }
|
||||
static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
|
||||
|
||||
static bool isEqual(const int& LHS, const int& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for longs.
|
||||
template<> struct DenseMapInfo<long> {
|
||||
static inline long getEmptyKey() {
|
||||
return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
|
||||
}
|
||||
|
||||
static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
|
||||
|
||||
static unsigned getHashValue(const long& Val) {
|
||||
return (unsigned)(Val * 37UL);
|
||||
}
|
||||
|
||||
static bool isEqual(const long& LHS, const long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for long longs.
|
||||
template<> struct DenseMapInfo<long long> {
|
||||
static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
|
||||
static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
|
||||
|
||||
static unsigned getHashValue(const long long& Val) {
|
||||
return (unsigned)(Val * 37ULL);
|
||||
}
|
||||
|
||||
static bool isEqual(const long long& LHS,
|
||||
const long long& RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all pairs whose members have info.
|
||||
template<typename T, typename U>
|
||||
struct DenseMapInfo<std::pair<T, U>> {
|
||||
using Pair = std::pair<T, U>;
|
||||
using FirstInfo = DenseMapInfo<T>;
|
||||
using SecondInfo = DenseMapInfo<U>;
|
||||
|
||||
static inline Pair getEmptyKey() {
|
||||
return std::make_pair(FirstInfo::getEmptyKey(),
|
||||
SecondInfo::getEmptyKey());
|
||||
}
|
||||
|
||||
static inline Pair getTombstoneKey() {
|
||||
return std::make_pair(FirstInfo::getTombstoneKey(),
|
||||
SecondInfo::getTombstoneKey());
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const Pair& PairVal) {
|
||||
return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first),
|
||||
SecondInfo::getHashValue(PairVal.second));
|
||||
}
|
||||
|
||||
static bool isEqual(const Pair &LHS, const Pair &RHS) {
|
||||
return FirstInfo::isEqual(LHS.first, RHS.first) &&
|
||||
SecondInfo::isEqual(LHS.second, RHS.second);
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for all tuples whose members have info.
|
||||
template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
|
||||
using Tuple = std::tuple<Ts...>;
|
||||
|
||||
static inline Tuple getEmptyKey() {
|
||||
return Tuple(DenseMapInfo<Ts>::getEmptyKey()...);
|
||||
}
|
||||
|
||||
static inline Tuple getTombstoneKey() {
|
||||
return Tuple(DenseMapInfo<Ts>::getTombstoneKey()...);
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static unsigned getHashValueImpl(const Tuple &values, std::false_type) {
|
||||
using EltType = typename std::tuple_element<I, Tuple>::type;
|
||||
std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
|
||||
return detail::combineHashValue(
|
||||
DenseMapInfo<EltType>::getHashValue(std::get<I>(values)),
|
||||
getHashValueImpl<I + 1>(values, atEnd));
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static unsigned getHashValueImpl(const Tuple &, std::true_type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const std::tuple<Ts...> &values) {
|
||||
std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
|
||||
return getHashValueImpl<0>(values, atEnd);
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static bool isEqualImpl(const Tuple &lhs, const Tuple &rhs, std::false_type) {
|
||||
using EltType = typename std::tuple_element<I, Tuple>::type;
|
||||
std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
|
||||
return DenseMapInfo<EltType>::isEqual(std::get<I>(lhs), std::get<I>(rhs)) &&
|
||||
isEqualImpl<I + 1>(lhs, rhs, atEnd);
|
||||
}
|
||||
|
||||
template <unsigned I>
|
||||
static bool isEqualImpl(const Tuple &, const Tuple &, std::true_type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isEqual(const Tuple &lhs, const Tuple &rhs) {
|
||||
std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
|
||||
return isEqualImpl<0>(lhs, rhs, atEnd);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct DenseMapInfo<hash_code> {
|
||||
static inline hash_code getEmptyKey() { return hash_code(-1); }
|
||||
static inline hash_code getTombstoneKey() { return hash_code(-2); }
|
||||
static unsigned getHashValue(hash_code val) { return static_cast<unsigned>(val); }
|
||||
static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_DENSEMAPINFO_H
|
||||
429
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Endian.h
vendored
Normal file
429
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Endian.h
vendored
Normal file
@@ -0,0 +1,429 @@
|
||||
//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares generic functions to read and write endian specific data.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ENDIAN_H
|
||||
#define WPIUTIL_WPI_ENDIAN_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/SwapByteOrder.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
namespace support {
|
||||
|
||||
enum endianness {big, little, native};
|
||||
|
||||
// These are named values for common alignments.
|
||||
enum {aligned = 0, unaligned = 1};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// ::value is either alignment, or alignof(T) if alignment is 0.
|
||||
template<class T, int alignment>
|
||||
struct PickAlignment {
|
||||
enum { value = alignment == 0 ? alignof(T) : alignment };
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
namespace endian {
|
||||
|
||||
constexpr endianness system_endianness() {
|
||||
return sys::IsBigEndianHost ? big : little;
|
||||
}
|
||||
|
||||
template <typename value_type>
|
||||
inline value_type byte_swap(value_type value, endianness endian) {
|
||||
if ((endian != native) && (endian != system_endianness()))
|
||||
sys::swapByteOrder(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Swap the bytes of value to match the given endianness.
|
||||
template<typename value_type, endianness endian>
|
||||
inline value_type byte_swap(value_type value) {
|
||||
if constexpr ((endian != native) && (endian != system_endianness()))
|
||||
sys::swapByteOrder(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Read a value of a particular endianness from memory.
|
||||
template <typename value_type, std::size_t alignment>
|
||||
inline value_type read(const void *memory, endianness endian) {
|
||||
value_type ret;
|
||||
|
||||
memcpy(&ret,
|
||||
LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
sizeof(value_type));
|
||||
return byte_swap<value_type>(ret, endian);
|
||||
}
|
||||
|
||||
template<typename value_type,
|
||||
endianness endian,
|
||||
std::size_t alignment>
|
||||
inline value_type read(const void *memory) {
|
||||
return read<value_type, alignment>(memory, endian);
|
||||
}
|
||||
|
||||
/// Read a value of a particular endianness from a buffer, and increment the
|
||||
/// buffer past that value.
|
||||
template <typename value_type, std::size_t alignment, typename CharT>
|
||||
inline value_type readNext(const CharT *&memory, endianness endian) {
|
||||
value_type ret = read<value_type, alignment>(memory, endian);
|
||||
memory += sizeof(value_type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename value_type, endianness endian, std::size_t alignment,
|
||||
typename CharT>
|
||||
inline value_type readNext(const CharT *&memory) {
|
||||
return readNext<value_type, alignment, CharT>(memory, endian);
|
||||
}
|
||||
|
||||
/// Write a value to memory with a particular endianness.
|
||||
template <typename value_type, std::size_t alignment>
|
||||
inline void write(void *memory, value_type value, endianness endian) {
|
||||
value = byte_swap<value_type>(value, endian);
|
||||
memcpy(LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
&value, sizeof(value_type));
|
||||
}
|
||||
|
||||
template<typename value_type,
|
||||
endianness endian,
|
||||
std::size_t alignment>
|
||||
inline void write(void *memory, value_type value) {
|
||||
write<value_type, alignment>(memory, value, endian);
|
||||
}
|
||||
|
||||
template <typename value_type>
|
||||
using make_unsigned_t = std::make_unsigned_t<value_type>;
|
||||
|
||||
/// Read a value of a particular endianness from memory, for a location
|
||||
/// that starts at the given bit offset within the first byte.
|
||||
template <typename value_type, endianness endian, std::size_t alignment>
|
||||
inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
|
||||
assert(startBit < 8);
|
||||
if (startBit == 0)
|
||||
return read<value_type, endian, alignment>(memory);
|
||||
else {
|
||||
// Read two values and compose the result from them.
|
||||
value_type val[2];
|
||||
memcpy(&val[0],
|
||||
LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
sizeof(value_type) * 2);
|
||||
val[0] = byte_swap<value_type, endian>(val[0]);
|
||||
val[1] = byte_swap<value_type, endian>(val[1]);
|
||||
|
||||
// Shift bits from the lower value into place.
|
||||
make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
|
||||
// Mask off upper bits after right shift in case of signed type.
|
||||
make_unsigned_t<value_type> numBitsFirstVal =
|
||||
(sizeof(value_type) * 8) - startBit;
|
||||
lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
|
||||
|
||||
// Get the bits from the upper value.
|
||||
make_unsigned_t<value_type> upperVal =
|
||||
val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
|
||||
// Shift them in to place.
|
||||
upperVal <<= numBitsFirstVal;
|
||||
|
||||
return lowerVal | upperVal;
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a value to memory with a particular endianness, for a location
|
||||
/// that starts at the given bit offset within the first byte.
|
||||
template <typename value_type, endianness endian, std::size_t alignment>
|
||||
inline void writeAtBitAlignment(void *memory, value_type value,
|
||||
uint64_t startBit) {
|
||||
assert(startBit < 8);
|
||||
if (startBit == 0)
|
||||
write<value_type, endian, alignment>(memory, value);
|
||||
else {
|
||||
// Read two values and shift the result into them.
|
||||
value_type val[2];
|
||||
memcpy(&val[0],
|
||||
LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
sizeof(value_type) * 2);
|
||||
val[0] = byte_swap<value_type, endian>(val[0]);
|
||||
val[1] = byte_swap<value_type, endian>(val[1]);
|
||||
|
||||
// Mask off any existing bits in the upper part of the lower value that
|
||||
// we want to replace.
|
||||
val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
|
||||
make_unsigned_t<value_type> numBitsFirstVal =
|
||||
(sizeof(value_type) * 8) - startBit;
|
||||
make_unsigned_t<value_type> lowerVal = value;
|
||||
if (startBit > 0) {
|
||||
// Mask off the upper bits in the new value that are not going to go into
|
||||
// the lower value. This avoids a left shift of a negative value, which
|
||||
// is undefined behavior.
|
||||
lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
|
||||
// Now shift the new bits into place
|
||||
lowerVal <<= startBit;
|
||||
}
|
||||
val[0] |= lowerVal;
|
||||
|
||||
// Mask off any existing bits in the lower part of the upper value that
|
||||
// we want to replace.
|
||||
val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
|
||||
// Next shift the bits that go into the upper value into position.
|
||||
make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
|
||||
// Mask off upper bits after right shift in case of signed type.
|
||||
upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
|
||||
val[1] |= upperVal;
|
||||
|
||||
// Finally, rewrite values.
|
||||
val[0] = byte_swap<value_type, endian>(val[0]);
|
||||
val[1] = byte_swap<value_type, endian>(val[1]);
|
||||
memcpy(LLVM_ASSUME_ALIGNED(
|
||||
memory, (detail::PickAlignment<value_type, alignment>::value)),
|
||||
&val[0], sizeof(value_type) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace endian
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename ValueType, endianness Endian, std::size_t Alignment,
|
||||
std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
|
||||
struct packed_endian_specific_integral {
|
||||
using value_type = ValueType;
|
||||
static constexpr endianness endian = Endian;
|
||||
static constexpr std::size_t alignment = Alignment;
|
||||
|
||||
packed_endian_specific_integral() = default;
|
||||
|
||||
explicit packed_endian_specific_integral(value_type val) { *this = val; }
|
||||
|
||||
operator value_type() const {
|
||||
return endian::read<value_type, endian, alignment>(
|
||||
(const void*)Value.buffer);
|
||||
}
|
||||
|
||||
void operator=(value_type newValue) {
|
||||
endian::write<value_type, endian, alignment>(
|
||||
(void*)Value.buffer, newValue);
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator+=(value_type newValue) {
|
||||
*this = *this + newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator-=(value_type newValue) {
|
||||
*this = *this - newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator|=(value_type newValue) {
|
||||
*this = *this | newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
packed_endian_specific_integral &operator&=(value_type newValue) {
|
||||
*this = *this & newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
struct {
|
||||
alignas(ALIGN) char buffer[sizeof(value_type)];
|
||||
} Value;
|
||||
|
||||
public:
|
||||
struct ref {
|
||||
explicit ref(void *Ptr) : Ptr(Ptr) {}
|
||||
|
||||
operator value_type() const {
|
||||
return endian::read<value_type, endian, alignment>(Ptr);
|
||||
}
|
||||
|
||||
void operator=(value_type NewValue) {
|
||||
endian::write<value_type, endian, alignment>(Ptr, NewValue);
|
||||
}
|
||||
|
||||
private:
|
||||
void *Ptr;
|
||||
};
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
using ulittle16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, little, unaligned>;
|
||||
using ulittle32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, little, unaligned>;
|
||||
using ulittle64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, little, unaligned>;
|
||||
|
||||
using little16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, little, unaligned>;
|
||||
using little32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, little, unaligned>;
|
||||
using little64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, little, unaligned>;
|
||||
|
||||
using aligned_ulittle16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, little, aligned>;
|
||||
using aligned_ulittle32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, little, aligned>;
|
||||
using aligned_ulittle64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, little, aligned>;
|
||||
|
||||
using aligned_little16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, little, aligned>;
|
||||
using aligned_little32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, little, aligned>;
|
||||
using aligned_little64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, little, aligned>;
|
||||
|
||||
using ubig16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, big, unaligned>;
|
||||
using ubig32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, big, unaligned>;
|
||||
using ubig64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, big, unaligned>;
|
||||
|
||||
using big16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, big, unaligned>;
|
||||
using big32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, big, unaligned>;
|
||||
using big64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, big, unaligned>;
|
||||
|
||||
using aligned_ubig16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, big, aligned>;
|
||||
using aligned_ubig32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, big, aligned>;
|
||||
using aligned_ubig64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, big, aligned>;
|
||||
|
||||
using aligned_big16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, big, aligned>;
|
||||
using aligned_big32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, big, aligned>;
|
||||
using aligned_big64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, big, aligned>;
|
||||
|
||||
using unaligned_uint16_t =
|
||||
detail::packed_endian_specific_integral<uint16_t, native, unaligned>;
|
||||
using unaligned_uint32_t =
|
||||
detail::packed_endian_specific_integral<uint32_t, native, unaligned>;
|
||||
using unaligned_uint64_t =
|
||||
detail::packed_endian_specific_integral<uint64_t, native, unaligned>;
|
||||
|
||||
using unaligned_int16_t =
|
||||
detail::packed_endian_specific_integral<int16_t, native, unaligned>;
|
||||
using unaligned_int32_t =
|
||||
detail::packed_endian_specific_integral<int32_t, native, unaligned>;
|
||||
using unaligned_int64_t =
|
||||
detail::packed_endian_specific_integral<int64_t, native, unaligned>;
|
||||
|
||||
template <typename T>
|
||||
using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
|
||||
template <typename T>
|
||||
using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
|
||||
|
||||
template <typename T>
|
||||
using aligned_little_t =
|
||||
detail::packed_endian_specific_integral<T, little, aligned>;
|
||||
template <typename T>
|
||||
using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
|
||||
|
||||
namespace endian {
|
||||
|
||||
template <typename T> inline T read(const void *P, endianness E) {
|
||||
return read<T, unaligned>(P, E);
|
||||
}
|
||||
|
||||
template <typename T, endianness E> inline T read(const void *P) {
|
||||
return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
|
||||
}
|
||||
|
||||
inline uint16_t read16(const void *P, endianness E) {
|
||||
return read<uint16_t>(P, E);
|
||||
}
|
||||
inline uint32_t read32(const void *P, endianness E) {
|
||||
return read<uint32_t>(P, E);
|
||||
}
|
||||
inline uint64_t read64(const void *P, endianness E) {
|
||||
return read<uint64_t>(P, E);
|
||||
}
|
||||
|
||||
template <endianness E> inline uint16_t read16(const void *P) {
|
||||
return read<uint16_t, E>(P);
|
||||
}
|
||||
template <endianness E> inline uint32_t read32(const void *P) {
|
||||
return read<uint32_t, E>(P);
|
||||
}
|
||||
template <endianness E> inline uint64_t read64(const void *P) {
|
||||
return read<uint64_t, E>(P);
|
||||
}
|
||||
|
||||
inline uint16_t read16le(const void *P) { return read16<little>(P); }
|
||||
inline uint32_t read32le(const void *P) { return read32<little>(P); }
|
||||
inline uint64_t read64le(const void *P) { return read64<little>(P); }
|
||||
inline uint16_t read16be(const void *P) { return read16<big>(P); }
|
||||
inline uint32_t read32be(const void *P) { return read32<big>(P); }
|
||||
inline uint64_t read64be(const void *P) { return read64<big>(P); }
|
||||
|
||||
template <typename T> inline void write(void *P, T V, endianness E) {
|
||||
write<T, unaligned>(P, V, E);
|
||||
}
|
||||
|
||||
template <typename T, endianness E> inline void write(void *P, T V) {
|
||||
*(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
|
||||
}
|
||||
|
||||
inline void write16(void *P, uint16_t V, endianness E) {
|
||||
write<uint16_t>(P, V, E);
|
||||
}
|
||||
inline void write32(void *P, uint32_t V, endianness E) {
|
||||
write<uint32_t>(P, V, E);
|
||||
}
|
||||
inline void write64(void *P, uint64_t V, endianness E) {
|
||||
write<uint64_t>(P, V, E);
|
||||
}
|
||||
|
||||
template <endianness E> inline void write16(void *P, uint16_t V) {
|
||||
write<uint16_t, E>(P, V);
|
||||
}
|
||||
template <endianness E> inline void write32(void *P, uint32_t V) {
|
||||
write<uint32_t, E>(P, V);
|
||||
}
|
||||
template <endianness E> inline void write64(void *P, uint64_t V) {
|
||||
write<uint64_t, E>(P, V);
|
||||
}
|
||||
|
||||
inline void write16le(void *P, uint16_t V) { write16<little>(P, V); }
|
||||
inline void write32le(void *P, uint32_t V) { write32<little>(P, V); }
|
||||
inline void write64le(void *P, uint64_t V) { write64<little>(P, V); }
|
||||
inline void write16be(void *P, uint16_t V) { write16<big>(P, V); }
|
||||
inline void write32be(void *P, uint32_t V) { write32<big>(P, V); }
|
||||
inline void write64be(void *P, uint64_t V) { write64<big>(P, V); }
|
||||
|
||||
} // end namespace endian
|
||||
|
||||
} // end namespace support
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ENDIAN_H
|
||||
97
wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
vendored
Normal file
97
wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes.
|
||||
// These can be used to write iterators that are fail-fast when LLVM is built
|
||||
// with asserts enabled.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_EPOCHTRACKER_H
|
||||
#define WPIUTIL_WPI_EPOCHTRACKER_H
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#ifndef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
|
||||
/// A base class for data structure classes wishing to make iterators
|
||||
/// ("handles") pointing into themselves fail-fast. When building without
|
||||
/// asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// DebugEpochBase does not by itself track handles pointing into itself. The
|
||||
/// expectation is that routines touching the handles will poll on
|
||||
/// isHandleInSync at appropriate points to assert that the handle they're using
|
||||
/// is still valid.
|
||||
///
|
||||
class DebugEpochBase {
|
||||
uint64_t Epoch;
|
||||
|
||||
public:
|
||||
DebugEpochBase() : Epoch(0) {}
|
||||
|
||||
/// Calling incrementEpoch invalidates all handles pointing into the
|
||||
/// calling instance.
|
||||
void incrementEpoch() { ++Epoch; }
|
||||
|
||||
/// The destructor calls incrementEpoch to make use-after-free bugs
|
||||
/// more likely to crash deterministically.
|
||||
~DebugEpochBase() { incrementEpoch(); }
|
||||
|
||||
/// A base class for iterator classes ("handles") that wish to poll for
|
||||
/// iterator invalidating modifications in the underlying data structure.
|
||||
/// When LLVM is built without asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// HandleBase does not track the parent data structure by itself. It expects
|
||||
/// the routines modifying the data structure to call incrementEpoch when they
|
||||
/// make an iterator-invalidating modification.
|
||||
///
|
||||
class HandleBase {
|
||||
const uint64_t *EpochAddress;
|
||||
uint64_t EpochAtCreation;
|
||||
|
||||
public:
|
||||
HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
|
||||
|
||||
explicit HandleBase(const DebugEpochBase *Parent)
|
||||
: EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
|
||||
|
||||
/// Returns true if the DebugEpochBase this Handle is linked to has
|
||||
/// not called incrementEpoch on itself since the creation of this
|
||||
/// HandleBase instance.
|
||||
bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
|
||||
|
||||
/// Returns a pointer to the epoch word stored in the data structure
|
||||
/// this handle points into. Can be used to check if two iterators point
|
||||
/// into the same data structure.
|
||||
const void *getEpochAddress() const { return EpochAddress; }
|
||||
};
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class DebugEpochBase {
|
||||
public:
|
||||
void incrementEpoch() {}
|
||||
|
||||
class HandleBase {
|
||||
public:
|
||||
HandleBase() = default;
|
||||
explicit HandleBase(const DebugEpochBase *) {}
|
||||
bool isHandleInSync() const { return true; }
|
||||
const void *getEpochAddress() const { return nullptr; }
|
||||
};
|
||||
};
|
||||
|
||||
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif
|
||||
86
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errc.h
vendored
Normal file
86
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errc.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
//===- llvm/Support/Errc.h - Defines the wpi::errc enum --------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// While std::error_code works OK on all platforms we use, there are some
|
||||
// some problems with std::errc that can be avoided by using our own
|
||||
// enumeration:
|
||||
//
|
||||
// * std::errc is a namespace in some implementations. That means that ADL
|
||||
// doesn't work and it is sometimes necessary to write std::make_error_code
|
||||
// or in templates:
|
||||
// using std::make_error_code;
|
||||
// make_error_code(...);
|
||||
//
|
||||
// with this enum it is safe to always just use make_error_code.
|
||||
//
|
||||
// * Some implementations define fewer names than others. This header has
|
||||
// the intersection of all the ones we support.
|
||||
//
|
||||
// * std::errc is just marked with is_error_condition_enum. This means that
|
||||
// common patterns like AnErrorCode == errc::no_such_file_or_directory take
|
||||
// 4 virtual calls instead of two comparisons.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERRC_H
|
||||
#define WPIUTIL_WPI_ERRC_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace wpi {
|
||||
enum class errc {
|
||||
argument_list_too_long = int(std::errc::argument_list_too_long),
|
||||
argument_out_of_domain = int(std::errc::argument_out_of_domain),
|
||||
bad_address = int(std::errc::bad_address),
|
||||
bad_file_descriptor = int(std::errc::bad_file_descriptor),
|
||||
broken_pipe = int(std::errc::broken_pipe),
|
||||
device_or_resource_busy = int(std::errc::device_or_resource_busy),
|
||||
directory_not_empty = int(std::errc::directory_not_empty),
|
||||
executable_format_error = int(std::errc::executable_format_error),
|
||||
file_exists = int(std::errc::file_exists),
|
||||
file_too_large = int(std::errc::file_too_large),
|
||||
filename_too_long = int(std::errc::filename_too_long),
|
||||
function_not_supported = int(std::errc::function_not_supported),
|
||||
illegal_byte_sequence = int(std::errc::illegal_byte_sequence),
|
||||
inappropriate_io_control_operation =
|
||||
int(std::errc::inappropriate_io_control_operation),
|
||||
interrupted = int(std::errc::interrupted),
|
||||
invalid_argument = int(std::errc::invalid_argument),
|
||||
invalid_seek = int(std::errc::invalid_seek),
|
||||
io_error = int(std::errc::io_error),
|
||||
is_a_directory = int(std::errc::is_a_directory),
|
||||
no_child_process = int(std::errc::no_child_process),
|
||||
no_lock_available = int(std::errc::no_lock_available),
|
||||
no_space_on_device = int(std::errc::no_space_on_device),
|
||||
no_such_device_or_address = int(std::errc::no_such_device_or_address),
|
||||
no_such_device = int(std::errc::no_such_device),
|
||||
no_such_file_or_directory = int(std::errc::no_such_file_or_directory),
|
||||
no_such_process = int(std::errc::no_such_process),
|
||||
not_a_directory = int(std::errc::not_a_directory),
|
||||
not_enough_memory = int(std::errc::not_enough_memory),
|
||||
not_supported = int(std::errc::not_supported),
|
||||
operation_not_permitted = int(std::errc::operation_not_permitted),
|
||||
permission_denied = int(std::errc::permission_denied),
|
||||
read_only_file_system = int(std::errc::read_only_file_system),
|
||||
resource_deadlock_would_occur = int(std::errc::resource_deadlock_would_occur),
|
||||
resource_unavailable_try_again =
|
||||
int(std::errc::resource_unavailable_try_again),
|
||||
result_out_of_range = int(std::errc::result_out_of_range),
|
||||
too_many_files_open_in_system = int(std::errc::too_many_files_open_in_system),
|
||||
too_many_files_open = int(std::errc::too_many_files_open),
|
||||
too_many_links = int(std::errc::too_many_links)
|
||||
};
|
||||
|
||||
inline std::error_code make_error_code(errc E) {
|
||||
return std::error_code(static_cast<int>(E), std::generic_category());
|
||||
}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <> struct is_error_code_enum<wpi::errc> : std::true_type {};
|
||||
}
|
||||
#endif
|
||||
37
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
vendored
Normal file
37
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares some portable and convenient functions to deal with errno.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERRNO_H
|
||||
#define WPIUTIL_WPI_ERRNO_H
|
||||
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
namespace sys {
|
||||
|
||||
template <typename FailT, typename Fun, typename... Args>
|
||||
inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F,
|
||||
const Args &... As) {
|
||||
decltype(F(As...)) Res;
|
||||
do {
|
||||
errno = 0;
|
||||
Res = F(As...);
|
||||
} while (Res == Fail && errno == EINTR);
|
||||
return Res;
|
||||
}
|
||||
|
||||
} // namespace sys
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ERRNO_H
|
||||
141
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
vendored
Normal file
141
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines an API used to indicate fatal error conditions. Non-fatal
|
||||
// errors (most of them) should be handled through LLVMContext.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ERRORHANDLING_H
|
||||
#define WPIUTIL_WPI_ERRORHANDLING_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// An error handler callback.
|
||||
typedef void (*fatal_error_handler_t)(void *user_data,
|
||||
const std::string& reason,
|
||||
bool gen_crash_diag);
|
||||
|
||||
/// install_fatal_error_handler - Installs a new error handler to be used
|
||||
/// whenever a serious (non-recoverable) error is encountered by LLVM.
|
||||
///
|
||||
/// If no error handler is installed the default is to print the error message
|
||||
/// to stderr, and call exit(1). If an error handler is installed then it is
|
||||
/// the handler's responsibility to log the message, it will no longer be
|
||||
/// printed to stderr. If the error handler returns, then exit(1) will be
|
||||
/// called.
|
||||
///
|
||||
/// It is dangerous to naively use an error handler which throws an exception.
|
||||
/// Even though some applications desire to gracefully recover from arbitrary
|
||||
/// faults, blindly throwing exceptions through unfamiliar code isn't a way to
|
||||
/// achieve this.
|
||||
///
|
||||
/// \param user_data - An argument which will be passed to the install error
|
||||
/// handler.
|
||||
void install_fatal_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data = nullptr);
|
||||
|
||||
/// Restores default error handling behavior.
|
||||
void remove_fatal_error_handler();
|
||||
|
||||
/// ScopedFatalErrorHandler - This is a simple helper class which just
|
||||
/// calls install_fatal_error_handler in its constructor and
|
||||
/// remove_fatal_error_handler in its destructor.
|
||||
struct ScopedFatalErrorHandler {
|
||||
explicit ScopedFatalErrorHandler(fatal_error_handler_t handler,
|
||||
void *user_data = nullptr) {
|
||||
install_fatal_error_handler(handler, user_data);
|
||||
}
|
||||
|
||||
~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
|
||||
};
|
||||
|
||||
/// Reports a serious error, calling any installed error handler. These
|
||||
/// functions are intended to be used for error conditions which are outside
|
||||
/// the control of the compiler (I/O errors, invalid user input, etc.)
|
||||
///
|
||||
/// If no error handler is installed the default is to print the message to
|
||||
/// standard error, followed by a newline.
|
||||
/// After the error handler is called this function will call abort(), it
|
||||
/// does not return.
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason,
|
||||
bool gen_crash_diag = true);
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const std::string &reason,
|
||||
bool gen_crash_diag = true);
|
||||
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(std::string_view reason,
|
||||
bool gen_crash_diag = true);
|
||||
|
||||
/// Installs a new bad alloc error handler that should be used whenever a
|
||||
/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
|
||||
///
|
||||
/// The user can install a bad alloc handler, in order to define the behavior
|
||||
/// in case of failing allocations, e.g. throwing an exception. Note that this
|
||||
/// handler must not trigger any additional allocations itself.
|
||||
///
|
||||
/// If no error handler is installed the default is to print the error message
|
||||
/// to stderr, and call exit(1). If an error handler is installed then it is
|
||||
/// the handler's responsibility to log the message, it will no longer be
|
||||
/// printed to stderr. If the error handler returns, then exit(1) will be
|
||||
/// called.
|
||||
///
|
||||
///
|
||||
/// \param user_data - An argument which will be passed to the installed error
|
||||
/// handler.
|
||||
void install_bad_alloc_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data = nullptr);
|
||||
|
||||
/// Restores default bad alloc error handling behavior.
|
||||
void remove_bad_alloc_error_handler();
|
||||
|
||||
void install_out_of_memory_new_handler();
|
||||
|
||||
/// Reports a bad alloc error, calling any user defined bad alloc
|
||||
/// error handler. In contrast to the generic 'report_fatal_error'
|
||||
/// functions, this function might not terminate, e.g. the user
|
||||
/// defined error handler throws an exception, but it won't return.
|
||||
///
|
||||
/// Note: When throwing an exception in the bad alloc handler, make sure that
|
||||
/// the following unwind succeeds, e.g. do not trigger additional allocations
|
||||
/// in the unwind chain.
|
||||
///
|
||||
/// If no error handler is installed (default), throws a bad_alloc exception
|
||||
/// if LLVM is compiled with exception support. Otherwise prints the error
|
||||
/// to standard error and calls abort().
|
||||
LLVM_ATTRIBUTE_NORETURN void report_bad_alloc_error(const char *Reason,
|
||||
bool GenCrashDiag = true);
|
||||
|
||||
/// This function calls abort(), and prints the optional message to stderr.
|
||||
/// Use the wpi_unreachable macro (that adds location info), instead of
|
||||
/// calling this function directly.
|
||||
LLVM_ATTRIBUTE_NORETURN void
|
||||
wpi_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
|
||||
unsigned line = 0);
|
||||
}
|
||||
|
||||
/// Marks that the current location is not supposed to be reachable.
|
||||
/// In !NDEBUG builds, prints the message and location info to stderr.
|
||||
/// In NDEBUG builds, becomes an optimizer hint that the current location
|
||||
/// is not supposed to be reachable. On compilers that don't support
|
||||
/// such hints, prints a reduced message instead and aborts the program.
|
||||
///
|
||||
/// Use this instead of assert(0). It conveys intent more clearly and
|
||||
/// allows compilers to omit some unnecessary code.
|
||||
#ifndef NDEBUG
|
||||
#define wpi_unreachable(msg) \
|
||||
::wpi::wpi_unreachable_internal(msg, __FILE__, __LINE__)
|
||||
#elif defined(LLVM_BUILTIN_UNREACHABLE)
|
||||
#define wpi_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
|
||||
#else
|
||||
#define wpi_unreachable(msg) ::wpi::wpi_unreachable_internal()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
420
wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
vendored
Normal file
420
wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
//===- FunctionExtras.h - Function type erasure utilities -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file provides a collection of function (or more generally, callable)
|
||||
/// type erasure utilities supplementing those provided by the standard library
|
||||
/// in `<function>`.
|
||||
///
|
||||
/// It provides `unique_function`, which works like `std::function` but supports
|
||||
/// move-only callable objects and const-qualification.
|
||||
///
|
||||
/// Future plans:
|
||||
/// - Add a `function` that provides ref-qualified support, which doesn't work
|
||||
/// with `std::function`.
|
||||
/// - Provide support for specifying multiple signatures to type erase callable
|
||||
/// objects with an overload set, such as those produced by generic lambdas.
|
||||
/// - Expand to include a copyable utility that directly replaces std::function
|
||||
/// but brings the above improvements.
|
||||
///
|
||||
/// Note that LLVM's utilities are greatly simplified by not supporting
|
||||
/// allocators.
|
||||
///
|
||||
/// If the standard library ever begins to provide comparable facilities we can
|
||||
/// consider switching to those.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_FUNCTIONEXTRAS_H
|
||||
#define WPIUTIL_WPI_FUNCTIONEXTRAS_H
|
||||
|
||||
#include "wpi/PointerIntPair.h"
|
||||
#include "wpi/PointerUnion.h"
|
||||
#include "wpi/STLForwardCompat.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// unique_function is a type-erasing functor similar to std::function.
|
||||
///
|
||||
/// It can hold move-only function objects, like lambdas capturing unique_ptrs.
|
||||
/// Accordingly, it is movable but not copyable.
|
||||
///
|
||||
/// It supports const-qualification:
|
||||
/// - unique_function<int() const> has a const operator().
|
||||
/// It can only hold functions which themselves have a const operator().
|
||||
/// - unique_function<int()> has a non-const operator().
|
||||
/// It can hold functions with a non-const operator(), like mutable lambdas.
|
||||
template <typename FunctionT> class unique_function;
|
||||
|
||||
// GCC warns on OutOfLineStorage
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using EnableIfTrivial =
|
||||
std::enable_if_t<wpi::is_trivially_move_constructible<T>::value &&
|
||||
std::is_trivially_destructible<T>::value>;
|
||||
template <typename CallableT, typename ThisT>
|
||||
using EnableUnlessSameType =
|
||||
std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>::value>;
|
||||
template <typename CallableT, typename Ret, typename... Params>
|
||||
using EnableIfCallable =
|
||||
std::enable_if_t<std::is_void<Ret>::value ||
|
||||
std::is_convertible<decltype(std::declval<CallableT>()(
|
||||
std::declval<Params>()...)),
|
||||
Ret>::value>;
|
||||
|
||||
template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
|
||||
protected:
|
||||
static constexpr size_t InlineStorageSize = sizeof(void *) * 4;
|
||||
|
||||
template <typename T, class = void>
|
||||
struct IsSizeLessThanThresholdT : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsSizeLessThanThresholdT<
|
||||
T, std::enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
|
||||
|
||||
// Provide a type function to map parameters that won't observe extra copies
|
||||
// or moves and which are small enough to likely pass in register to values
|
||||
// and all other types to l-value reference types. We use this to compute the
|
||||
// types used in our erased call utility to minimize copies and moves unless
|
||||
// doing so would force things unnecessarily into memory.
|
||||
//
|
||||
// The heuristic used is related to common ABI register passing conventions.
|
||||
// It doesn't have to be exact though, and in one way it is more strict
|
||||
// because we want to still be able to observe either moves *or* copies.
|
||||
template <typename T> struct AdjustedParamTBase {
|
||||
static_assert(!std::is_reference<T>::value,
|
||||
"references should be handled by template specialization");
|
||||
using type = typename std::conditional<
|
||||
wpi::is_trivially_copy_constructible<T>::value &&
|
||||
wpi::is_trivially_move_constructible<T>::value &&
|
||||
IsSizeLessThanThresholdT<T>::value,
|
||||
T, T &>::type;
|
||||
};
|
||||
|
||||
// This specialization ensures that 'AdjustedParam<V<T>&>' or
|
||||
// 'AdjustedParam<V<T>&&>' does not trigger a compile-time error when 'T' is
|
||||
// an incomplete type and V a templated type.
|
||||
template <typename T> struct AdjustedParamTBase<T &> { using type = T &; };
|
||||
template <typename T> struct AdjustedParamTBase<T &&> { using type = T &; };
|
||||
|
||||
template <typename T>
|
||||
using AdjustedParamT = typename AdjustedParamTBase<T>::type;
|
||||
|
||||
// The type of the erased function pointer we use as a callback to dispatch to
|
||||
// the stored callable when it is trivial to move and destroy.
|
||||
using CallPtrT = ReturnT (*)(void *CallableAddr,
|
||||
AdjustedParamT<ParamTs>... Params);
|
||||
using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
|
||||
using DestroyPtrT = void (*)(void *CallableAddr);
|
||||
|
||||
/// A struct to hold a single trivial callback with sufficient alignment for
|
||||
/// our bitpacking.
|
||||
struct alignas(8) TrivialCallback {
|
||||
CallPtrT CallPtr;
|
||||
};
|
||||
|
||||
/// A struct we use to aggregate three callbacks when we need full set of
|
||||
/// operations.
|
||||
struct alignas(8) NonTrivialCallbacks {
|
||||
CallPtrT CallPtr;
|
||||
MovePtrT MovePtr;
|
||||
DestroyPtrT DestroyPtr;
|
||||
};
|
||||
|
||||
// Create a pointer union between either a pointer to a static trivial call
|
||||
// pointer in a struct or a pointer to a static struct of the call, move, and
|
||||
// destroy pointers.
|
||||
using CallbackPointerUnionT =
|
||||
PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
|
||||
|
||||
// The main storage buffer. This will either have a pointer to out-of-line
|
||||
// storage or an inline buffer storing the callable.
|
||||
union StorageUnionT {
|
||||
// For out-of-line storage we keep a pointer to the underlying storage and
|
||||
// the size. This is enough to deallocate the memory.
|
||||
struct OutOfLineStorageT {
|
||||
void *StoragePtr;
|
||||
size_t Size;
|
||||
size_t Alignment;
|
||||
} OutOfLineStorage;
|
||||
static_assert(
|
||||
sizeof(OutOfLineStorageT) <= InlineStorageSize,
|
||||
"Should always use all of the out-of-line storage for inline storage!");
|
||||
|
||||
// For in-line storage, we just provide an aligned character buffer. We
|
||||
// provide four pointers worth of storage here.
|
||||
// This is mutable as an inlined `const unique_function<void() const>` may
|
||||
// still modify its own mutable members.
|
||||
mutable
|
||||
typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
|
||||
InlineStorage;
|
||||
} StorageUnion;
|
||||
|
||||
// A compressed pointer to either our dispatching callback or our table of
|
||||
// dispatching callbacks and the flag for whether the callable itself is
|
||||
// stored inline or not.
|
||||
PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
|
||||
|
||||
bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
|
||||
|
||||
bool isTrivialCallback() const {
|
||||
return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
|
||||
}
|
||||
|
||||
CallPtrT getTrivialCallback() const {
|
||||
return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
|
||||
}
|
||||
|
||||
NonTrivialCallbacks *getNonTrivialCallbacks() const {
|
||||
return CallbackAndInlineFlag.getPointer()
|
||||
.template get<NonTrivialCallbacks *>();
|
||||
}
|
||||
|
||||
CallPtrT getCallPtr() const {
|
||||
return isTrivialCallback() ? getTrivialCallback()
|
||||
: getNonTrivialCallbacks()->CallPtr;
|
||||
}
|
||||
|
||||
// These three functions are only const in the narrow sense. They return
|
||||
// mutable pointers to function state.
|
||||
// This allows unique_function<T const>::operator() to be const, even if the
|
||||
// underlying functor may be internally mutable.
|
||||
//
|
||||
// const callers must ensure they're only used in const-correct ways.
|
||||
void *getCalleePtr() const {
|
||||
return isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
|
||||
}
|
||||
void *getInlineStorage() const { return &StorageUnion.InlineStorage; }
|
||||
void *getOutOfLineStorage() const {
|
||||
return StorageUnion.OutOfLineStorage.StoragePtr;
|
||||
}
|
||||
|
||||
size_t getOutOfLineStorageSize() const {
|
||||
return StorageUnion.OutOfLineStorage.Size;
|
||||
}
|
||||
size_t getOutOfLineStorageAlignment() const {
|
||||
return StorageUnion.OutOfLineStorage.Alignment;
|
||||
}
|
||||
|
||||
void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
|
||||
StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
|
||||
}
|
||||
|
||||
template <typename CalledAsT>
|
||||
static ReturnT CallImpl(void *CallableAddr,
|
||||
AdjustedParamT<ParamTs>... Params) {
|
||||
auto &Func = *reinterpret_cast<CalledAsT *>(CallableAddr);
|
||||
return Func(std::forward<ParamTs>(Params)...);
|
||||
}
|
||||
|
||||
template <typename CallableT>
|
||||
static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
|
||||
new (LHSCallableAddr)
|
||||
CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
|
||||
}
|
||||
|
||||
template <typename CallableT>
|
||||
static void DestroyImpl(void *CallableAddr) noexcept {
|
||||
reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
|
||||
}
|
||||
|
||||
// The pointers to call/move/destroy functions are determined for each
|
||||
// callable type (and called-as type, which determines the overload chosen).
|
||||
// (definitions are out-of-line).
|
||||
|
||||
// By default, we need an object that contains all the different
|
||||
// type erased behaviors needed. Create a static instance of the struct type
|
||||
// here and each instance will contain a pointer to it.
|
||||
// Wrap in a struct to avoid https://gcc.gnu.org/PR71954
|
||||
template <typename CallableT, typename CalledAs, typename Enable = void>
|
||||
struct CallbacksHolder {
|
||||
static NonTrivialCallbacks Callbacks;
|
||||
};
|
||||
// See if we can create a trivial callback. We need the callable to be
|
||||
// trivially moved and trivially destroyed so that we don't have to store
|
||||
// type erased callbacks for those operations.
|
||||
template <typename CallableT, typename CalledAs>
|
||||
struct CallbacksHolder<CallableT, CalledAs, EnableIfTrivial<CallableT>> {
|
||||
static TrivialCallback Callbacks;
|
||||
};
|
||||
|
||||
// A simple tag type so the call-as type to be passed to the constructor.
|
||||
template <typename T> struct CalledAs {};
|
||||
|
||||
// Essentially the "main" unique_function constructor, but subclasses
|
||||
// provide the qualified type to be used for the call.
|
||||
// (We always store a T, even if the call will use a pointer to const T).
|
||||
template <typename CallableT, typename CalledAsT>
|
||||
UniqueFunctionBase(CallableT Callable, CalledAs<CalledAsT>) {
|
||||
bool IsInlineStorage = true;
|
||||
void *CallableAddr = getInlineStorage();
|
||||
if (sizeof(CallableT) > InlineStorageSize ||
|
||||
alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
|
||||
IsInlineStorage = false;
|
||||
// Allocate out-of-line storage. FIXME: Use an explicit alignment
|
||||
// parameter in C++17 mode.
|
||||
auto Size = sizeof(CallableT);
|
||||
auto Alignment = alignof(CallableT);
|
||||
CallableAddr = allocate_buffer(Size, Alignment);
|
||||
setOutOfLineStorage(CallableAddr, Size, Alignment);
|
||||
}
|
||||
|
||||
// Now move into the storage.
|
||||
new (CallableAddr) CallableT(std::move(Callable));
|
||||
CallbackAndInlineFlag.setPointerAndInt(
|
||||
&CallbacksHolder<CallableT, CalledAsT>::Callbacks, IsInlineStorage);
|
||||
}
|
||||
|
||||
~UniqueFunctionBase() {
|
||||
if (!CallbackAndInlineFlag.getPointer())
|
||||
return;
|
||||
|
||||
// Cache this value so we don't re-check it after type-erased operations.
|
||||
bool IsInlineStorage = isInlineStorage();
|
||||
|
||||
if (!isTrivialCallback())
|
||||
getNonTrivialCallbacks()->DestroyPtr(
|
||||
IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
|
||||
|
||||
if (!IsInlineStorage)
|
||||
deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
|
||||
getOutOfLineStorageAlignment());
|
||||
}
|
||||
|
||||
UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept {
|
||||
// Copy the callback and inline flag.
|
||||
CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
|
||||
|
||||
// If the RHS is empty, just copying the above is sufficient.
|
||||
if (!RHS)
|
||||
return;
|
||||
|
||||
if (!isInlineStorage()) {
|
||||
// The out-of-line case is easiest to move.
|
||||
StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
|
||||
} else if (isTrivialCallback()) {
|
||||
// Move is trivial, just memcpy the bytes across.
|
||||
memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
|
||||
} else {
|
||||
// Non-trivial move, so dispatch to a type-erased implementation.
|
||||
getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
|
||||
RHS.getInlineStorage());
|
||||
}
|
||||
|
||||
// Clear the old callback and inline flag to get back to as-if-null.
|
||||
RHS.CallbackAndInlineFlag = {};
|
||||
|
||||
#ifndef NDEBUG
|
||||
// In debug builds, we also scribble across the rest of the storage.
|
||||
memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
UniqueFunctionBase &operator=(UniqueFunctionBase &&RHS) noexcept {
|
||||
if (this == &RHS)
|
||||
return *this;
|
||||
|
||||
// Because we don't try to provide any exception safety guarantees we can
|
||||
// implement move assignment very simply by first destroying the current
|
||||
// object and then move-constructing over top of it.
|
||||
this->~UniqueFunctionBase();
|
||||
new (this) UniqueFunctionBase(std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
UniqueFunctionBase() = default;
|
||||
|
||||
public:
|
||||
explicit operator bool() const {
|
||||
return (bool)CallbackAndInlineFlag.getPointer();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename... P>
|
||||
template <typename CallableT, typename CalledAsT, typename Enable>
|
||||
typename UniqueFunctionBase<R, P...>::NonTrivialCallbacks UniqueFunctionBase<
|
||||
R, P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
|
||||
&CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
|
||||
|
||||
template <typename R, typename... P>
|
||||
template <typename CallableT, typename CalledAsT>
|
||||
typename UniqueFunctionBase<R, P...>::TrivialCallback
|
||||
UniqueFunctionBase<R, P...>::CallbacksHolder<
|
||||
CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
|
||||
&CallImpl<CalledAsT>};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename R, typename... P>
|
||||
class unique_function<R(P...)> : public detail::UniqueFunctionBase<R, P...> {
|
||||
using Base = detail::UniqueFunctionBase<R, P...>;
|
||||
|
||||
public:
|
||||
unique_function() = default;
|
||||
unique_function(std::nullptr_t) {}
|
||||
unique_function(unique_function &&) = default;
|
||||
unique_function(const unique_function &) = delete;
|
||||
unique_function &operator=(unique_function &&) = default;
|
||||
unique_function &operator=(const unique_function &) = delete;
|
||||
|
||||
template <typename CallableT>
|
||||
unique_function(
|
||||
CallableT Callable,
|
||||
detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
|
||||
detail::EnableIfCallable<CallableT, R, P...> * = nullptr)
|
||||
: Base(std::forward<CallableT>(Callable),
|
||||
typename Base::template CalledAs<CallableT>{}) {}
|
||||
|
||||
R operator()(P... Params) {
|
||||
return this->getCallPtr()(this->getCalleePtr(), Params...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename... P>
|
||||
class unique_function<R(P...) const>
|
||||
: public detail::UniqueFunctionBase<R, P...> {
|
||||
using Base = detail::UniqueFunctionBase<R, P...>;
|
||||
|
||||
public:
|
||||
unique_function() = default;
|
||||
unique_function(std::nullptr_t) {}
|
||||
unique_function(unique_function &&) = default;
|
||||
unique_function(const unique_function &) = delete;
|
||||
unique_function &operator=(unique_function &&) = default;
|
||||
unique_function &operator=(const unique_function &) = delete;
|
||||
|
||||
template <typename CallableT>
|
||||
unique_function(
|
||||
CallableT Callable,
|
||||
detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
|
||||
detail::EnableIfCallable<const CallableT, R, P...> * = nullptr)
|
||||
: Base(std::forward<CallableT>(Callable),
|
||||
typename Base::template CalledAs<const CallableT>{}) {}
|
||||
|
||||
R operator()(P... Params) const {
|
||||
return this->getCallPtr()(this->getCalleePtr(), Params...);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_FUNCTIONEXTRAS_H
|
||||
690
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
vendored
Normal file
690
wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
vendored
Normal file
@@ -0,0 +1,690 @@
|
||||
//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the newly proposed standard C++ interfaces for hashing
|
||||
// arbitrary data and building hash functions for user-defined types. This
|
||||
// interface was originally proposed in N3333[1] and is currently under review
|
||||
// for inclusion in a future TR and/or standard.
|
||||
//
|
||||
// The primary interfaces provide are comprised of one type and three functions:
|
||||
//
|
||||
// -- 'hash_code' class is an opaque type representing the hash code for some
|
||||
// data. It is the intended product of hashing, and can be used to implement
|
||||
// hash tables, checksumming, and other common uses of hashes. It is not an
|
||||
// integer type (although it can be converted to one) because it is risky
|
||||
// to assume much about the internals of a hash_code. In particular, each
|
||||
// execution of the program has a high probability of producing a different
|
||||
// hash_code for a given input. Thus their values are not stable to save or
|
||||
// persist, and should only be used during the execution for the
|
||||
// construction of hashing datastructures.
|
||||
//
|
||||
// -- 'hash_value' is a function designed to be overloaded for each
|
||||
// user-defined type which wishes to be used within a hashing context. It
|
||||
// should be overloaded within the user-defined type's namespace and found
|
||||
// via ADL. Overloads for primitive types are provided by this library.
|
||||
//
|
||||
// -- 'hash_combine' and 'hash_combine_range' are functions designed to aid
|
||||
// programmers in easily and intuitively combining a set of data into
|
||||
// a single hash_code for their object. They should only logically be used
|
||||
// within the implementation of a 'hash_value' routine or similar context.
|
||||
//
|
||||
// Note that 'hash_combine_range' contains very special logic for hashing
|
||||
// a contiguous array of integers or pointers. This logic is *extremely* fast,
|
||||
// on a modern Intel "Gainestown" Xeon (Nehalem uarch) @2.2 GHz, these were
|
||||
// benchmarked at over 6.5 GiB/s for large keys, and <20 cycles/hash for keys
|
||||
// under 32-bytes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_HASHING_H
|
||||
#define WPIUTIL_WPI_HASHING_H
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SwapByteOrder.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26495)
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// An opaque object representing a hash code.
|
||||
///
|
||||
/// This object represents the result of hashing some entity. It is intended to
|
||||
/// be used to implement hashtables or other hashing-based data structures.
|
||||
/// While it wraps and exposes a numeric value, this value should not be
|
||||
/// trusted to be stable or predictable across processes or executions.
|
||||
///
|
||||
/// In order to obtain the hash_code for an object 'x':
|
||||
/// \code
|
||||
/// using wpi::hash_value;
|
||||
/// wpi::hash_code code = hash_value(x);
|
||||
/// \endcode
|
||||
class hash_code {
|
||||
size_t value;
|
||||
|
||||
public:
|
||||
/// Default construct a hash_code.
|
||||
/// Note that this leaves the value uninitialized.
|
||||
hash_code() = default;
|
||||
|
||||
/// Form a hash code directly from a numerical value.
|
||||
hash_code(size_t value) : value(value) {}
|
||||
|
||||
/// Convert the hash code to its numerical value for use.
|
||||
/*explicit*/ operator size_t() const { return value; }
|
||||
|
||||
friend bool operator==(const hash_code &lhs, const hash_code &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
friend bool operator!=(const hash_code &lhs, const hash_code &rhs) {
|
||||
return lhs.value != rhs.value;
|
||||
}
|
||||
|
||||
/// Allow a hash_code to be directly run through hash_value.
|
||||
friend size_t hash_value(const hash_code &code) { return code.value; }
|
||||
};
|
||||
|
||||
/// Compute a hash_code for any integer value.
|
||||
///
|
||||
/// Note that this function is intended to compute the same hash_code for
|
||||
/// a particular value without regard to the pre-promotion type. This is in
|
||||
/// contrast to hash_combine which may produce different hash_codes for
|
||||
/// differing argument types even if they would implicit promote to a common
|
||||
/// type without changing the value.
|
||||
template <typename T>
|
||||
std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value);
|
||||
|
||||
/// Compute a hash_code for a pointer's address.
|
||||
///
|
||||
/// N.B.: This hashes the *address*. Not the value and not the type.
|
||||
template <typename T> hash_code hash_value(const T *ptr);
|
||||
|
||||
/// Compute a hash_code for a pair of objects.
|
||||
template <typename T, typename U>
|
||||
hash_code hash_value(const std::pair<T, U> &arg);
|
||||
|
||||
/// Compute a hash_code for a tuple.
|
||||
template <typename... Ts>
|
||||
hash_code hash_value(const std::tuple<Ts...> &arg);
|
||||
|
||||
/// Compute a hash_code for a standard string.
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string<T> &arg);
|
||||
|
||||
|
||||
/// Override the execution seed with a fixed value.
|
||||
///
|
||||
/// This hashing library uses a per-execution seed designed to change on each
|
||||
/// run with high probability in order to ensure that the hash codes are not
|
||||
/// attackable and to ensure that output which is intended to be stable does
|
||||
/// not rely on the particulars of the hash codes produced.
|
||||
///
|
||||
/// That said, there are use cases where it is important to be able to
|
||||
/// reproduce *exactly* a specific behavior. To that end, we provide a function
|
||||
/// which will forcibly set the seed to a fixed value. This must be done at the
|
||||
/// start of the program, before any hashes are computed. Also, it cannot be
|
||||
/// undone. This makes it thread-hostile and very hard to use outside of
|
||||
/// immediately on start of a simple program designed for reproducible
|
||||
/// behavior.
|
||||
void set_fixed_execution_hash_seed(uint64_t fixed_value);
|
||||
|
||||
|
||||
// All of the implementation details of actually computing the various hash
|
||||
// code values are held within this namespace. These routines are included in
|
||||
// the header file mainly to allow inlining and constant propagation.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
inline uint64_t fetch64(const char *p) {
|
||||
uint64_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
if (sys::IsBigEndianHost)
|
||||
sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint32_t fetch32(const char *p) {
|
||||
uint32_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
if (sys::IsBigEndianHost)
|
||||
sys::swapByteOrder(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Some primes between 2^63 and 2^64 for various uses.
|
||||
static constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL;
|
||||
static constexpr uint64_t k1 = 0xb492b66fbe98f273ULL;
|
||||
static constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL;
|
||||
static constexpr uint64_t k3 = 0xc949d7c7509e6557ULL;
|
||||
|
||||
/// Bitwise right rotate.
|
||||
/// Normally this will compile to a single instruction, especially if the
|
||||
/// shift is a manifest constant.
|
||||
inline uint64_t rotate(uint64_t val, size_t shift) {
|
||||
// Avoid shifting by 64: doing so yields an undefined result.
|
||||
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
|
||||
}
|
||||
|
||||
inline uint64_t shift_mix(uint64_t val) {
|
||||
return val ^ (val >> 47);
|
||||
}
|
||||
|
||||
inline uint64_t hash_16_bytes(uint64_t low, uint64_t high) {
|
||||
// Murmur-inspired hashing.
|
||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||
uint64_t a = (low ^ high) * kMul;
|
||||
a ^= (a >> 47);
|
||||
uint64_t b = (high ^ a) * kMul;
|
||||
b ^= (b >> 47);
|
||||
b *= kMul;
|
||||
return b;
|
||||
}
|
||||
|
||||
inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint8_t a = s[0];
|
||||
uint8_t b = s[len >> 1];
|
||||
uint8_t c = s[len - 1];
|
||||
uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
|
||||
uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
|
||||
return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
|
||||
}
|
||||
|
||||
inline uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch32(s);
|
||||
return hash_16_bytes(len + (a << 3), seed ^ fetch32(s + len - 4));
|
||||
}
|
||||
|
||||
inline uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch64(s);
|
||||
uint64_t b = fetch64(s + len - 8);
|
||||
return hash_16_bytes(seed ^ a, rotate(b + len, len)) ^ b;
|
||||
}
|
||||
|
||||
inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t a = fetch64(s) * k1;
|
||||
uint64_t b = fetch64(s + 8);
|
||||
uint64_t c = fetch64(s + len - 8) * k2;
|
||||
uint64_t d = fetch64(s + len - 16) * k0;
|
||||
return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d,
|
||||
a + rotate(b ^ k3, 20) - c + len + seed);
|
||||
}
|
||||
|
||||
inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) {
|
||||
uint64_t z = fetch64(s + 24);
|
||||
uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0;
|
||||
uint64_t b = rotate(a + z, 52);
|
||||
uint64_t c = rotate(a, 37);
|
||||
a += fetch64(s + 8);
|
||||
c += rotate(a, 7);
|
||||
a += fetch64(s + 16);
|
||||
uint64_t vf = a + z;
|
||||
uint64_t vs = b + rotate(a, 31) + c;
|
||||
a = fetch64(s + 16) + fetch64(s + len - 32);
|
||||
z = fetch64(s + len - 8);
|
||||
b = rotate(a + z, 52);
|
||||
c = rotate(a, 37);
|
||||
a += fetch64(s + len - 24);
|
||||
c += rotate(a, 7);
|
||||
a += fetch64(s + len - 16);
|
||||
uint64_t wf = a + z;
|
||||
uint64_t ws = b + rotate(a, 31) + c;
|
||||
uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
|
||||
return shift_mix((seed ^ (r * k0)) + vs) * k2;
|
||||
}
|
||||
|
||||
inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
|
||||
if (length >= 4 && length <= 8)
|
||||
return hash_4to8_bytes(s, length, seed);
|
||||
if (length > 8 && length <= 16)
|
||||
return hash_9to16_bytes(s, length, seed);
|
||||
if (length > 16 && length <= 32)
|
||||
return hash_17to32_bytes(s, length, seed);
|
||||
if (length > 32)
|
||||
return hash_33to64_bytes(s, length, seed);
|
||||
if (length != 0)
|
||||
return hash_1to3_bytes(s, length, seed);
|
||||
|
||||
return k2 ^ seed;
|
||||
}
|
||||
|
||||
/// The intermediate state used during hashing.
|
||||
/// Currently, the algorithm for computing hash codes is based on CityHash and
|
||||
/// keeps 56 bytes of arbitrary state.
|
||||
struct hash_state {
|
||||
uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0;
|
||||
|
||||
/// Create a new hash_state structure and initialize it based on the
|
||||
/// seed and the first 64-byte chunk.
|
||||
/// This effectively performs the initial mix.
|
||||
static hash_state create(const char *s, uint64_t seed) {
|
||||
hash_state state = {
|
||||
0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
|
||||
seed * k1, shift_mix(seed), 0 };
|
||||
state.h6 = hash_16_bytes(state.h4, state.h5);
|
||||
state.mix(s);
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Mix 32-bytes from the input sequence into the 16-bytes of 'a'
|
||||
/// and 'b', including whatever is already in 'a' and 'b'.
|
||||
static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
|
||||
a += fetch64(s);
|
||||
uint64_t c = fetch64(s + 24);
|
||||
b = rotate(b + a + c, 21);
|
||||
uint64_t d = a;
|
||||
a += fetch64(s + 8) + fetch64(s + 16);
|
||||
b += rotate(a, 44) + d;
|
||||
a += c;
|
||||
}
|
||||
|
||||
/// Mix in a 64-byte buffer of data.
|
||||
/// We mix all 64 bytes even when the chunk length is smaller, but we
|
||||
/// record the actual length.
|
||||
void mix(const char *s) {
|
||||
h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
|
||||
h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1;
|
||||
h0 ^= h6;
|
||||
h1 += h3 + fetch64(s + 40);
|
||||
h2 = rotate(h2 + h5, 33) * k1;
|
||||
h3 = h4 * k1;
|
||||
h4 = h0 + h5;
|
||||
mix_32_bytes(s, h3, h4);
|
||||
h5 = h2 + h6;
|
||||
h6 = h1 + fetch64(s + 16);
|
||||
mix_32_bytes(s + 32, h5, h6);
|
||||
std::swap(h2, h0);
|
||||
}
|
||||
|
||||
/// Compute the final 64-bit hash code value based on the current
|
||||
/// state and the length of bytes hashed.
|
||||
uint64_t finalize(size_t length) {
|
||||
return hash_16_bytes(hash_16_bytes(h3, h5) + shift_mix(h1) * k1 + h2,
|
||||
hash_16_bytes(h4, h6) + shift_mix(length) * k1 + h0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// A global, fixed seed-override variable.
|
||||
///
|
||||
/// This variable can be set using the \see wpi::set_fixed_execution_seed
|
||||
/// function. See that function for details. Do not, under any circumstances,
|
||||
/// set or read this variable.
|
||||
extern uint64_t fixed_seed_override;
|
||||
|
||||
inline uint64_t get_execution_seed() {
|
||||
// FIXME: This needs to be a per-execution seed. This is just a placeholder
|
||||
// implementation. Switching to a per-execution seed is likely to flush out
|
||||
// instability bugs and so will happen as its own commit.
|
||||
//
|
||||
// However, if there is a fixed seed override set the first time this is
|
||||
// called, return that instead of the per-execution seed.
|
||||
const uint64_t seed_prime = 0xff51afd7ed558ccdULL;
|
||||
static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime;
|
||||
return seed;
|
||||
}
|
||||
|
||||
|
||||
/// Trait to indicate whether a type's bits can be hashed directly.
|
||||
///
|
||||
/// A type trait which is true if we want to combine values for hashing by
|
||||
/// reading the underlying data. It is false if values of this type must
|
||||
/// first be passed to hash_value, and the resulting hash_codes combined.
|
||||
//
|
||||
// FIXME: We want to replace is_integral_or_enum and is_pointer here with
|
||||
// a predicate which asserts that comparing the underlying storage of two
|
||||
// values of the type for equality is equivalent to comparing the two values
|
||||
// for equality. For all the platforms we care about, this holds for integers
|
||||
// and pointers, but there are platforms where it doesn't and we would like to
|
||||
// support user-defined types which happen to satisfy this property.
|
||||
template <typename T> struct is_hashable_data
|
||||
: std::integral_constant<bool, ((is_integral_or_enum<T>::value ||
|
||||
std::is_pointer<T>::value) &&
|
||||
64 % sizeof(T) == 0)> {};
|
||||
|
||||
// Special case std::pair to detect when both types are viable and when there
|
||||
// is no alignment-derived padding in the pair. This is a bit of a lie because
|
||||
// std::pair isn't truly POD, but it's close enough in all reasonable
|
||||
// implementations for our use case of hashing the underlying data.
|
||||
template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
|
||||
: std::integral_constant<bool, (is_hashable_data<T>::value &&
|
||||
is_hashable_data<U>::value &&
|
||||
(sizeof(T) + sizeof(U)) ==
|
||||
sizeof(std::pair<T, U>))> {};
|
||||
|
||||
/// Helper to get the hashable data representation for a type.
|
||||
/// This variant is enabled when the type itself can be used.
|
||||
template <typename T>
|
||||
std::enable_if_t<is_hashable_data<T>::value, T>
|
||||
get_hashable_data(const T &value) {
|
||||
return value;
|
||||
}
|
||||
/// Helper to get the hashable data representation for a type.
|
||||
/// This variant is enabled when we must first call hash_value and use the
|
||||
/// result as our data.
|
||||
template <typename T>
|
||||
std::enable_if_t<!is_hashable_data<T>::value, size_t>
|
||||
get_hashable_data(const T &value) {
|
||||
using ::wpi::hash_value;
|
||||
return hash_value(value);
|
||||
}
|
||||
|
||||
/// Helper to store data from a value into a buffer and advance the
|
||||
/// pointer into that buffer.
|
||||
///
|
||||
/// This routine first checks whether there is enough space in the provided
|
||||
/// buffer, and if not immediately returns false. If there is space, it
|
||||
/// copies the underlying bytes of value into the buffer, advances the
|
||||
/// buffer_ptr past the copied bytes, and returns true.
|
||||
template <typename T>
|
||||
bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
|
||||
size_t offset = 0) {
|
||||
size_t store_size = sizeof(value) - offset;
|
||||
if (buffer_ptr + store_size > buffer_end)
|
||||
return false;
|
||||
const char *value_data = reinterpret_cast<const char *>(&value);
|
||||
memcpy(buffer_ptr, value_data + offset, store_size);
|
||||
buffer_ptr += store_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Implement the combining of integral values into a hash_code.
|
||||
///
|
||||
/// This overload is selected when the value type of the iterator is
|
||||
/// integral. Rather than computing a hash_code for each object and then
|
||||
/// combining them, this (as an optimization) directly combines the integers.
|
||||
template <typename InputIteratorT>
|
||||
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
|
||||
const uint64_t seed = get_execution_seed();
|
||||
char buffer[64], *buffer_ptr = buffer;
|
||||
char *const buffer_end = std::end(buffer);
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
get_hashable_data(*first)))
|
||||
++first;
|
||||
if (first == last)
|
||||
return hash_short(buffer, buffer_ptr - buffer, seed);
|
||||
assert(buffer_ptr == buffer_end);
|
||||
|
||||
hash_state state = state.create(buffer, seed);
|
||||
size_t length = 64;
|
||||
while (first != last) {
|
||||
// Fill up the buffer. We don't clear it, which re-mixes the last round
|
||||
// when only a partial 64-byte chunk is left.
|
||||
buffer_ptr = buffer;
|
||||
while (first != last && store_and_advance(buffer_ptr, buffer_end,
|
||||
get_hashable_data(*first)))
|
||||
++first;
|
||||
|
||||
// Rotate the buffer if we did a partial fill in order to simulate doing
|
||||
// a mix of the last 64-bytes. That is how the algorithm works when we
|
||||
// have a contiguous byte sequence, and we want to emulate that here.
|
||||
std::rotate(buffer, buffer_ptr, buffer_end);
|
||||
|
||||
// Mix this chunk into the current state.
|
||||
state.mix(buffer);
|
||||
length += buffer_ptr - buffer;
|
||||
};
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
|
||||
/// Implement the combining of integral values into a hash_code.
|
||||
///
|
||||
/// This overload is selected when the value type of the iterator is integral
|
||||
/// and when the input iterator is actually a pointer. Rather than computing
|
||||
/// a hash_code for each object and then combining them, this (as an
|
||||
/// optimization) directly combines the integers. Also, because the integers
|
||||
/// are stored in contiguous memory, this routine avoids copying each value
|
||||
/// and directly reads from the underlying memory.
|
||||
template <typename ValueT>
|
||||
std::enable_if_t<is_hashable_data<ValueT>::value, hash_code>
|
||||
hash_combine_range_impl(ValueT *first, ValueT *last) {
|
||||
const uint64_t seed = get_execution_seed();
|
||||
const char *s_begin = reinterpret_cast<const char *>(first);
|
||||
const char *s_end = reinterpret_cast<const char *>(last);
|
||||
const size_t length = std::distance(s_begin, s_end);
|
||||
if (length <= 64)
|
||||
return hash_short(s_begin, length, seed);
|
||||
|
||||
const char *s_aligned_end = s_begin + (length & ~63);
|
||||
hash_state state = state.create(s_begin, seed);
|
||||
s_begin += 64;
|
||||
while (s_begin != s_aligned_end) {
|
||||
state.mix(s_begin);
|
||||
s_begin += 64;
|
||||
}
|
||||
if (length & 63)
|
||||
state.mix(s_end - 64);
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
|
||||
/// Compute a hash_code for a sequence of values.
|
||||
///
|
||||
/// This hashes a sequence of values. It produces the same hash_code as
|
||||
/// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences
|
||||
/// and is significantly faster given pointers and types which can be hashed as
|
||||
/// a sequence of bytes.
|
||||
template <typename InputIteratorT>
|
||||
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
|
||||
return ::wpi::hashing::detail::hash_combine_range_impl(first, last);
|
||||
}
|
||||
|
||||
|
||||
// Implementation details for hash_combine.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// Helper class to manage the recursive combining of hash_combine
|
||||
/// arguments.
|
||||
///
|
||||
/// This class exists to manage the state and various calls involved in the
|
||||
/// recursive combining of arguments used in hash_combine. It is particularly
|
||||
/// useful at minimizing the code in the recursive calls to ease the pain
|
||||
/// caused by a lack of variadic functions.
|
||||
struct hash_combine_recursive_helper {
|
||||
char buffer[64] = {};
|
||||
hash_state state;
|
||||
const uint64_t seed;
|
||||
|
||||
public:
|
||||
/// Construct a recursive hash combining helper.
|
||||
///
|
||||
/// This sets up the state for a recursive hash combine, including getting
|
||||
/// the seed and buffer setup.
|
||||
hash_combine_recursive_helper()
|
||||
: seed(get_execution_seed()) {}
|
||||
|
||||
/// Combine one chunk of data into the current in-flight hash.
|
||||
///
|
||||
/// This merges one chunk of data into the hash. First it tries to buffer
|
||||
/// the data. If the buffer is full, it hashes the buffer into its
|
||||
/// hash_state, empties it, and then merges the new chunk in. This also
|
||||
/// handles cases where the data straddles the end of the buffer.
|
||||
template <typename T>
|
||||
char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) {
|
||||
if (!store_and_advance(buffer_ptr, buffer_end, data)) {
|
||||
// Check for skew which prevents the buffer from being packed, and do
|
||||
// a partial store into the buffer to fill it. This is only a concern
|
||||
// with the variadic combine because that formation can have varying
|
||||
// argument types.
|
||||
size_t partial_store_size = buffer_end - buffer_ptr;
|
||||
memcpy(buffer_ptr, &data, partial_store_size);
|
||||
|
||||
// If the store fails, our buffer is full and ready to hash. We have to
|
||||
// either initialize the hash state (on the first full buffer) or mix
|
||||
// this buffer into the existing hash state. Length tracks the *hashed*
|
||||
// length, not the buffered length.
|
||||
if (length == 0) {
|
||||
state = state.create(buffer, seed);
|
||||
length = 64;
|
||||
} else {
|
||||
// Mix this chunk into the current state and bump length up by 64.
|
||||
state.mix(buffer);
|
||||
length += 64;
|
||||
}
|
||||
// Reset the buffer_ptr to the head of the buffer for the next chunk of
|
||||
// data.
|
||||
buffer_ptr = buffer;
|
||||
|
||||
// Try again to store into the buffer -- this cannot fail as we only
|
||||
// store types smaller than the buffer.
|
||||
if (!store_and_advance(buffer_ptr, buffer_end, data,
|
||||
partial_store_size))
|
||||
wpi_unreachable("buffer smaller than stored type");
|
||||
}
|
||||
return buffer_ptr;
|
||||
}
|
||||
|
||||
/// Recursive, variadic combining method.
|
||||
///
|
||||
/// This function recurses through each argument, combining that argument
|
||||
/// into a single hash.
|
||||
template <typename T, typename ...Ts>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T &arg, const Ts &...args) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg));
|
||||
|
||||
// Recurse to the next argument.
|
||||
return combine(length, buffer_ptr, buffer_end, args...);
|
||||
}
|
||||
|
||||
/// Base case for recursive, variadic combining.
|
||||
///
|
||||
/// The base case when combining arguments recursively is reached when all
|
||||
/// arguments have been handled. It flushes the remaining buffer and
|
||||
/// constructs a hash_code.
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) {
|
||||
// Check whether the entire set of values fit in the buffer. If so, we'll
|
||||
// use the optimized short hashing routine and skip state entirely.
|
||||
if (length == 0)
|
||||
return hash_short(buffer, buffer_ptr - buffer, seed);
|
||||
|
||||
// Mix the final buffer, rotating it if we did a partial fill in order to
|
||||
// simulate doing a mix of the last 64-bytes. That is how the algorithm
|
||||
// works when we have a contiguous byte sequence, and we want to emulate
|
||||
// that here.
|
||||
std::rotate(buffer, buffer_ptr, buffer_end);
|
||||
|
||||
// Mix this chunk into the current state.
|
||||
state.mix(buffer);
|
||||
length += buffer_ptr - buffer;
|
||||
|
||||
return state.finalize(length);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
/// Combine values into a single hash_code.
|
||||
///
|
||||
/// This routine accepts a varying number of arguments of any type. It will
|
||||
/// attempt to combine them into a single hash_code. For user-defined types it
|
||||
/// attempts to call a \see hash_value overload (via ADL) for the type. For
|
||||
/// integer and pointer types it directly combines their data into the
|
||||
/// resulting hash_code.
|
||||
///
|
||||
/// The result is suitable for returning from a user's hash_value
|
||||
/// *implementation* for their user-defined type. Consumers of a type should
|
||||
/// *not* call this routine, they should instead call 'hash_value'.
|
||||
template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
|
||||
// Recursively hash each argument using a helper class.
|
||||
::wpi::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64, args...);
|
||||
}
|
||||
|
||||
// Implementation details for implementations of hash_value overloads provided
|
||||
// here.
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
/// Helper to hash the value of a single integer.
|
||||
///
|
||||
/// Overloads for smaller integer types are not provided to ensure consistent
|
||||
/// behavior in the presence of integral promotions. Essentially,
|
||||
/// "hash_value('4')" and "hash_value('0' + 4)" should be the same.
|
||||
inline hash_code hash_integer_value(uint64_t value) {
|
||||
// Similar to hash_4to8_bytes but using a seed instead of length.
|
||||
const uint64_t seed = get_execution_seed();
|
||||
const char *s = reinterpret_cast<const char *>(&value);
|
||||
const uint64_t a = fetch32(s);
|
||||
return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T>
|
||||
std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value) {
|
||||
return ::wpi::hashing::detail::hash_integer_value(
|
||||
static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T> hash_code hash_value(const T *ptr) {
|
||||
return ::wpi::hashing::detail::hash_integer_value(
|
||||
reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T, typename U>
|
||||
hash_code hash_value(const std::pair<T, U> &arg) {
|
||||
return hash_combine(arg.first, arg.second);
|
||||
}
|
||||
|
||||
// Implementation details for the hash_value overload for std::tuple<...>(...).
|
||||
namespace hashing {
|
||||
namespace detail {
|
||||
|
||||
template <typename... Ts, std::size_t... Indices>
|
||||
hash_code hash_value_tuple_helper(const std::tuple<Ts...> &arg,
|
||||
std::index_sequence<Indices...>) {
|
||||
return hash_combine(std::get<Indices>(arg)...);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
template <typename... Ts>
|
||||
hash_code hash_value(const std::tuple<Ts...> &arg) {
|
||||
// TODO: Use std::apply when LLVM starts using C++17.
|
||||
return ::wpi::hashing::detail::hash_value_tuple_helper(
|
||||
arg, typename std::index_sequence_for<Ts...>());
|
||||
}
|
||||
|
||||
// Declared and documented above, but defined here so that any of the hashing
|
||||
// infrastructure is available.
|
||||
template <typename T>
|
||||
hash_code hash_value(const std::basic_string<T> &arg) {
|
||||
return hash_combine_range(arg.begin(), arg.end());
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
125
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ManagedStatic.h
vendored
Normal file
125
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ManagedStatic.h
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
//===-- llvm/Support/ManagedStatic.h - Static Global wrapper ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ManagedStatic class and the wpi_shutdown() function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MANAGEDSTATIC_H
|
||||
#define WPIUTIL_WPI_MANAGEDSTATIC_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// object_creator - Helper method for ManagedStatic.
|
||||
template <class C> struct object_creator {
|
||||
static void *call() { return new C(); }
|
||||
};
|
||||
|
||||
/// object_deleter - Helper method for ManagedStatic.
|
||||
///
|
||||
template <typename T> struct object_deleter {
|
||||
static void call(void *Ptr) { delete (T *)Ptr; }
|
||||
};
|
||||
template <typename T, size_t N> struct object_deleter<T[N]> {
|
||||
static void call(void *Ptr) { delete[](T *)Ptr; }
|
||||
};
|
||||
|
||||
// ManagedStatic must be initialized to zero, and it must *not* have a dynamic
|
||||
// initializer because managed statics are often created while running other
|
||||
// dynamic initializers. In standard C++11, the best way to accomplish this is
|
||||
// with a constexpr default constructor. However, different versions of the
|
||||
// Visual C++ compiler have had bugs where, even though the constructor may be
|
||||
// constexpr, a dynamic initializer may be emitted depending on optimization
|
||||
// settings. For the affected versions of MSVC, use the old linker
|
||||
// initialization pattern of not providing a constructor and leaving the fields
|
||||
// uninitialized. See http://llvm.org/PR41367 for details.
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1925) || defined(__clang__)
|
||||
#define LLVM_USE_CONSTEXPR_CTOR
|
||||
#endif
|
||||
|
||||
/// ManagedStaticBase - Common base class for ManagedStatic instances.
|
||||
class ManagedStaticBase {
|
||||
protected:
|
||||
#ifdef LLVM_USE_CONSTEXPR_CTOR
|
||||
mutable std::atomic<void *> Ptr{};
|
||||
mutable void (*DeleterFn)(void *) = nullptr;
|
||||
mutable const ManagedStaticBase *Next = nullptr;
|
||||
#else
|
||||
// This should only be used as a static variable, which guarantees that this
|
||||
// will be zero initialized.
|
||||
mutable std::atomic<void *> Ptr;
|
||||
mutable void (*DeleterFn)(void *);
|
||||
mutable const ManagedStaticBase *Next;
|
||||
#endif
|
||||
|
||||
void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
|
||||
|
||||
public:
|
||||
#ifdef LLVM_USE_CONSTEXPR_CTOR
|
||||
constexpr ManagedStaticBase() = default;
|
||||
#endif
|
||||
|
||||
/// isConstructed - Return true if this object has not been created yet.
|
||||
bool isConstructed() const { return Ptr != nullptr; }
|
||||
|
||||
void destroy() const;
|
||||
};
|
||||
|
||||
/// ManagedStatic - This transparently changes the behavior of global statics to
|
||||
/// be lazily constructed on demand (good for reducing startup times of dynamic
|
||||
/// libraries that link in LLVM components) and for making destruction be
|
||||
/// explicit through the wpi_shutdown() function call.
|
||||
///
|
||||
template <class C, class Creator = object_creator<C>,
|
||||
class Deleter = object_deleter<C>>
|
||||
class ManagedStatic : public ManagedStaticBase {
|
||||
public:
|
||||
// Accessors.
|
||||
C &operator*() {
|
||||
void *Tmp = Ptr.load(std::memory_order_acquire);
|
||||
if (!Tmp)
|
||||
RegisterManagedStatic(Creator::call, Deleter::call);
|
||||
|
||||
return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
C *operator->() { return &**this; }
|
||||
|
||||
const C &operator*() const {
|
||||
void *Tmp = Ptr.load(std::memory_order_acquire);
|
||||
if (!Tmp)
|
||||
RegisterManagedStatic(Creator::call, Deleter::call);
|
||||
|
||||
return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
const C *operator->() const { return &**this; }
|
||||
|
||||
// Extract the instance, leaving the ManagedStatic uninitialized. The
|
||||
// user is then responsible for the lifetime of the returned instance.
|
||||
C *claim() {
|
||||
return static_cast<C *>(Ptr.exchange(nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
|
||||
void wpi_shutdown();
|
||||
|
||||
/// wpi_shutdown_obj - This is a simple helper class that calls
|
||||
/// wpi_shutdown() when it is destroyed.
|
||||
struct wpi_shutdown_obj {
|
||||
wpi_shutdown_obj() = default;
|
||||
~wpi_shutdown_obj() { wpi_shutdown(); }
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_MANAGEDSTATIC_H
|
||||
239
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
vendored
Normal file
239
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a map that provides insertion order iteration. The
|
||||
// interface is purposefully minimal. The key is assumed to be cheap to copy
|
||||
// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in
|
||||
// a std::vector.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MAPVECTOR_H
|
||||
#define WPIUTIL_WPI_MAPVECTOR_H
|
||||
|
||||
#include "wpi/DenseMap.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// This class implements a map that also provides access to all stored values
|
||||
/// in a deterministic order. The values are kept in a std::vector and the
|
||||
/// mapping is done with DenseMap from Keys to indexes in that vector.
|
||||
template<typename KeyT, typename ValueT,
|
||||
typename MapType = DenseMap<KeyT, unsigned>,
|
||||
typename VectorType = std::vector<std::pair<KeyT, ValueT>>>
|
||||
class MapVector {
|
||||
MapType Map;
|
||||
VectorType Vector;
|
||||
|
||||
static_assert(
|
||||
std::is_integral<typename MapType::mapped_type>::value,
|
||||
"The mapped_type of the specified Map must be an integral type");
|
||||
|
||||
public:
|
||||
using value_type = typename VectorType::value_type;
|
||||
using size_type = typename VectorType::size_type;
|
||||
|
||||
using iterator = typename VectorType::iterator;
|
||||
using const_iterator = typename VectorType::const_iterator;
|
||||
using reverse_iterator = typename VectorType::reverse_iterator;
|
||||
using const_reverse_iterator = typename VectorType::const_reverse_iterator;
|
||||
|
||||
/// Clear the MapVector and return the underlying vector.
|
||||
VectorType takeVector() {
|
||||
Map.clear();
|
||||
return std::move(Vector);
|
||||
}
|
||||
|
||||
size_type size() const { return Vector.size(); }
|
||||
|
||||
/// Grow the MapVector so that it can contain at least \p NumEntries items
|
||||
/// before resizing again.
|
||||
void reserve(size_type NumEntries) {
|
||||
Map.reserve(NumEntries);
|
||||
Vector.reserve(NumEntries);
|
||||
}
|
||||
|
||||
iterator begin() { return Vector.begin(); }
|
||||
const_iterator begin() const { return Vector.begin(); }
|
||||
iterator end() { return Vector.end(); }
|
||||
const_iterator end() const { return Vector.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Vector.rbegin(); }
|
||||
const_reverse_iterator rbegin() const { return Vector.rbegin(); }
|
||||
reverse_iterator rend() { return Vector.rend(); }
|
||||
const_reverse_iterator rend() const { return Vector.rend(); }
|
||||
|
||||
bool empty() const {
|
||||
return Vector.empty();
|
||||
}
|
||||
|
||||
std::pair<KeyT, ValueT> &front() { return Vector.front(); }
|
||||
const std::pair<KeyT, ValueT> &front() const { return Vector.front(); }
|
||||
std::pair<KeyT, ValueT> &back() { return Vector.back(); }
|
||||
const std::pair<KeyT, ValueT> &back() const { return Vector.back(); }
|
||||
|
||||
void clear() {
|
||||
Map.clear();
|
||||
Vector.clear();
|
||||
}
|
||||
|
||||
void swap(MapVector &RHS) {
|
||||
std::swap(Map, RHS.Map);
|
||||
std::swap(Vector, RHS.Vector);
|
||||
}
|
||||
|
||||
ValueT &operator[](const KeyT &Key) {
|
||||
std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(Key, 0);
|
||||
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
|
||||
auto &I = Result.first->second;
|
||||
if (Result.second) {
|
||||
Vector.push_back(std::make_pair(Key, ValueT()));
|
||||
I = Vector.size() - 1;
|
||||
}
|
||||
return Vector[I].second;
|
||||
}
|
||||
|
||||
// Returns a copy of the value. Only allowed if ValueT is copyable.
|
||||
ValueT lookup(const KeyT &Key) const {
|
||||
static_assert(std::is_copy_constructible<ValueT>::value,
|
||||
"Cannot call lookup() if ValueT is not copyable.");
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? ValueT() : Vector[Pos->second].second;
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
|
||||
std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0);
|
||||
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
|
||||
auto &I = Result.first->second;
|
||||
if (Result.second) {
|
||||
Vector.push_back(std::make_pair(KV.first, KV.second));
|
||||
I = Vector.size() - 1;
|
||||
return std::make_pair(std::prev(end()), true);
|
||||
}
|
||||
return std::make_pair(begin() + I, false);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
|
||||
// Copy KV.first into the map, then move it into the vector.
|
||||
std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0);
|
||||
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
|
||||
auto &I = Result.first->second;
|
||||
if (Result.second) {
|
||||
Vector.push_back(std::move(KV));
|
||||
I = Vector.size() - 1;
|
||||
return std::make_pair(std::prev(end()), true);
|
||||
}
|
||||
return std::make_pair(begin() + I, false);
|
||||
}
|
||||
|
||||
size_type count(const KeyT &Key) const {
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? 0 : 1;
|
||||
}
|
||||
|
||||
iterator find(const KeyT &Key) {
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? Vector.end() :
|
||||
(Vector.begin() + Pos->second);
|
||||
}
|
||||
|
||||
const_iterator find(const KeyT &Key) const {
|
||||
typename MapType::const_iterator Pos = Map.find(Key);
|
||||
return Pos == Map.end()? Vector.end() :
|
||||
(Vector.begin() + Pos->second);
|
||||
}
|
||||
|
||||
/// Remove the last element from the vector.
|
||||
void pop_back() {
|
||||
typename MapType::iterator Pos = Map.find(Vector.back().first);
|
||||
Map.erase(Pos);
|
||||
Vector.pop_back();
|
||||
}
|
||||
|
||||
/// Remove the element given by Iterator.
|
||||
///
|
||||
/// Returns an iterator to the element following the one which was removed,
|
||||
/// which may be end().
|
||||
///
|
||||
/// \note This is a deceivingly expensive operation (linear time). It's
|
||||
/// usually better to use \a remove_if() if possible.
|
||||
typename VectorType::iterator erase(typename VectorType::iterator Iterator) {
|
||||
Map.erase(Iterator->first);
|
||||
auto Next = Vector.erase(Iterator);
|
||||
if (Next == Vector.end())
|
||||
return Next;
|
||||
|
||||
// Update indices in the map.
|
||||
size_t Index = Next - Vector.begin();
|
||||
for (auto &I : Map) {
|
||||
assert(I.second != Index && "Index was already erased!");
|
||||
if (I.second > Index)
|
||||
--I.second;
|
||||
}
|
||||
return Next;
|
||||
}
|
||||
|
||||
/// Remove all elements with the key value Key.
|
||||
///
|
||||
/// Returns the number of elements removed.
|
||||
size_type erase(const KeyT &Key) {
|
||||
auto Iterator = find(Key);
|
||||
if (Iterator == end())
|
||||
return 0;
|
||||
erase(Iterator);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Remove the elements that match the predicate.
|
||||
///
|
||||
/// Erase all elements that match \c Pred in a single pass. Takes linear
|
||||
/// time.
|
||||
template <class Predicate> void remove_if(Predicate Pred);
|
||||
};
|
||||
|
||||
template <typename KeyT, typename ValueT, typename MapType, typename VectorType>
|
||||
template <class Function>
|
||||
void MapVector<KeyT, ValueT, MapType, VectorType>::remove_if(Function Pred) {
|
||||
auto O = Vector.begin();
|
||||
for (auto I = O, E = Vector.end(); I != E; ++I) {
|
||||
if (Pred(*I)) {
|
||||
// Erase from the map.
|
||||
Map.erase(I->first);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (I != O) {
|
||||
// Move the value and update the index in the map.
|
||||
*O = std::move(*I);
|
||||
Map[O->first] = O - Vector.begin();
|
||||
}
|
||||
++O;
|
||||
}
|
||||
// Erase trailing entries in the vector.
|
||||
Vector.erase(O, Vector.end());
|
||||
}
|
||||
|
||||
/// A MapVector that performs no allocations if smaller than a certain
|
||||
/// size.
|
||||
template <typename KeyT, typename ValueT, unsigned N>
|
||||
struct SmallMapVector
|
||||
: MapVector<KeyT, ValueT, SmallDenseMap<KeyT, unsigned, N>,
|
||||
SmallVector<std::pair<KeyT, ValueT>, N>> {
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_MAPVECTOR_H
|
||||
955
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
vendored
Normal file
955
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
vendored
Normal file
@@ -0,0 +1,955 @@
|
||||
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some functions that are useful for math stuff.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MATHEXTRAS_H
|
||||
#define WPIUTIL_WPI_MATHEXTRAS_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef __ANDROID_NDK__
|
||||
#include <android/api-level.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Declare these intrinsics manually rather including intrin.h. It's very
|
||||
// expensive, and MathExtras.h is popular.
|
||||
// #include <intrin.h>
|
||||
extern "C" {
|
||||
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
|
||||
unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
|
||||
unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// The behavior an operation has on an input of 0.
|
||||
enum ZeroBehavior {
|
||||
/// The returned value is undefined.
|
||||
ZB_Undefined,
|
||||
/// The returned value is numeric_limits<T>::max()
|
||||
ZB_Max,
|
||||
/// The returned value is numeric_limits<T>::digits
|
||||
ZB_Width
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
|
||||
static unsigned count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
if (Val & 0x1)
|
||||
return 0;
|
||||
|
||||
// Bisection method.
|
||||
unsigned ZeroBits = 0;
|
||||
T Shift = std::numeric_limits<T>::digits >> 1;
|
||||
T Mask = (std::numeric_limits<T>::max)() >> Shift;
|
||||
while (Shift) {
|
||||
if ((Val & Mask) == 0) {
|
||||
Val >>= Shift;
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
Shift >>= 1;
|
||||
Mask >>= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
template <typename T> struct TrailingZerosCounter<T, 4> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
|
||||
return __builtin_ctz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct TrailingZerosCounter<T, 8> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
|
||||
return __builtin_ctzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward64(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the least significant bit to the most
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return wpi::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
|
||||
static unsigned count(T Val, ZeroBehavior) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
|
||||
// Bisection method.
|
||||
unsigned ZeroBits = 0;
|
||||
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
|
||||
T Tmp = Val >> Shift;
|
||||
if (Tmp)
|
||||
Val = Tmp;
|
||||
else
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
template <typename T> struct LeadingZerosCounter<T, 4> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_clz) || defined(__GNUC__)
|
||||
return __builtin_clz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse(&Index, Val);
|
||||
return Index ^ 31;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T> struct LeadingZerosCounter<T, 8> {
|
||||
static unsigned count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
|
||||
return __builtin_clzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse64(&Index, Val);
|
||||
return Index ^ 63;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the most significant bit to the least
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return wpi::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
/// Get the index of the first set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
|
||||
return countTrailingZeros(Val, ZB_Undefined);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskTrailingOnes(unsigned N) {
|
||||
static_assert(std::is_unsigned<T>::value, "Invalid type!");
|
||||
const unsigned Bits = CHAR_BIT * sizeof(T);
|
||||
assert(N <= Bits && "Invalid bit index");
|
||||
return N == 0 ? 0 : (T(-1) >> (Bits - N));
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskLeadingOnes(unsigned N) {
|
||||
return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T> T maskTrailingZeros(unsigned N) {
|
||||
return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T> T maskLeadingZeros(unsigned N) {
|
||||
return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Get the index of the last set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
|
||||
// Use ^ instead of - because both gcc and llvm can remove the associated ^
|
||||
// in the __builtin_clz intrinsic on x86.
|
||||
return countLeadingZeros(Val, ZB_Undefined) ^
|
||||
(std::numeric_limits<T>::digits - 1);
|
||||
}
|
||||
|
||||
/// Macro compressed bit reversal table for 256 bits.
|
||||
///
|
||||
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
|
||||
static const unsigned char BitReverseTable256[256] = {
|
||||
#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
|
||||
#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16)
|
||||
#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4)
|
||||
R6(0), R6(2), R6(1), R6(3)
|
||||
#undef R2
|
||||
#undef R4
|
||||
#undef R6
|
||||
};
|
||||
|
||||
/// Reverse the bits in \p Val.
|
||||
template <typename T>
|
||||
T reverseBits(T Val) {
|
||||
unsigned char in[sizeof(Val)];
|
||||
unsigned char out[sizeof(Val)];
|
||||
std::memcpy(in, &Val, sizeof(Val));
|
||||
for (unsigned i = 0; i < sizeof(Val); ++i)
|
||||
out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
|
||||
std::memcpy(&Val, out, sizeof(Val));
|
||||
return Val;
|
||||
}
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse8)
|
||||
template<>
|
||||
inline uint8_t reverseBits<uint8_t>(uint8_t Val) {
|
||||
return __builtin_bitreverse8(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse16)
|
||||
template<>
|
||||
inline uint16_t reverseBits<uint16_t>(uint16_t Val) {
|
||||
return __builtin_bitreverse16(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse32)
|
||||
template<>
|
||||
inline uint32_t reverseBits<uint32_t>(uint32_t Val) {
|
||||
return __builtin_bitreverse32(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_bitreverse64)
|
||||
template<>
|
||||
inline uint64_t reverseBits<uint64_t>(uint64_t Val) {
|
||||
return __builtin_bitreverse64(Val);
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOTE: The following support functions use the _32/_64 extensions instead of
|
||||
// type overloading so that signed and unsigned integers can be used without
|
||||
// ambiguity.
|
||||
|
||||
/// Return the high 32 bits of a 64 bit value.
|
||||
constexpr inline uint32_t Hi_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value >> 32);
|
||||
}
|
||||
|
||||
/// Return the low 32 bits of a 64 bit value.
|
||||
constexpr inline uint32_t Lo_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value);
|
||||
}
|
||||
|
||||
/// Make a 64-bit integer from a high / low pair of 32-bit integers.
|
||||
constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
|
||||
return ((uint64_t)High << 32) | (uint64_t)Low;
|
||||
}
|
||||
|
||||
/// Checks if an integer fits into the given bit width.
|
||||
template <unsigned N> constexpr inline bool isInt(int64_t x) {
|
||||
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
|
||||
}
|
||||
// Template specializations to get better code for common cases.
|
||||
template <> constexpr inline bool isInt<8>(int64_t x) {
|
||||
return static_cast<int8_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isInt<16>(int64_t x) {
|
||||
return static_cast<int16_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isInt<32>(int64_t x) {
|
||||
return static_cast<int32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// Checks if a signed integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedInt(int64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
|
||||
static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
|
||||
return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
|
||||
}
|
||||
|
||||
/// Checks if an unsigned integer fits into the given bit width.
|
||||
///
|
||||
/// This is written as two functions rather than as simply
|
||||
///
|
||||
/// return N >= 64 || X < (UINT64_C(1) << N);
|
||||
///
|
||||
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
|
||||
/// left too many places.
|
||||
template <unsigned N>
|
||||
constexpr inline std::enable_if_t<(N < 64), bool> isUInt(uint64_t X) {
|
||||
static_assert(N > 0, "isUInt<0> doesn't make sense");
|
||||
return X < (UINT64_C(1) << (N));
|
||||
}
|
||||
template <unsigned N>
|
||||
constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Template specializations to get better code for common cases.
|
||||
template <> constexpr inline bool isUInt<8>(uint64_t x) {
|
||||
return static_cast<uint8_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isUInt<16>(uint64_t x) {
|
||||
return static_cast<uint16_t>(x) == x;
|
||||
}
|
||||
template <> constexpr inline bool isUInt<32>(uint64_t x) {
|
||||
return static_cast<uint32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// Checks if a unsigned integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedUInt(uint64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
|
||||
static_assert(N + S <= 64,
|
||||
"isShiftedUInt<N, S> with N + S > 64 is too wide.");
|
||||
// Per the two static_asserts above, S must be strictly less than 64. So
|
||||
// 1 << S is not undefined behavior.
|
||||
return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
|
||||
}
|
||||
|
||||
/// Gets the maximum value for a N-bit unsigned integer.
|
||||
inline uint64_t maxUIntN(uint64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
// uint64_t(1) << 64 is undefined behavior, so we can't do
|
||||
// (uint64_t(1) << N) - 1
|
||||
// without checking first that N != 64. But this works and doesn't have a
|
||||
// branch.
|
||||
return UINT64_MAX >> (64 - N);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
#endif
|
||||
|
||||
/// Gets the minimum value for a N-bit signed integer.
|
||||
inline int64_t minIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/// Gets the maximum value for a N-bit signed integer.
|
||||
inline int64_t maxIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
// This relies on two's complement wraparound when N == 64, so we convert to
|
||||
// int64_t only at the very end to avoid UB.
|
||||
return (UINT64_C(1) << (N - 1)) - 1;
|
||||
}
|
||||
|
||||
/// Checks if an unsigned integer fits into the given (dynamic) bit width.
|
||||
inline bool isUIntN(unsigned N, uint64_t x) {
|
||||
return N >= 64 || x <= maxUIntN(N);
|
||||
}
|
||||
|
||||
/// Checks if an signed integer fits into the given (dynamic) bit width.
|
||||
inline bool isIntN(unsigned N, int64_t x) {
|
||||
return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
|
||||
}
|
||||
|
||||
/// Return true if the argument is a non-empty sequence of ones starting at the
|
||||
/// least significant bit with the remainder zero (32 bit version).
|
||||
/// Ex. isMask_32(0x0000FFFFU) == true.
|
||||
constexpr inline bool isMask_32(uint32_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// Return true if the argument is a non-empty sequence of ones starting at the
|
||||
/// least significant bit with the remainder zero (64 bit version).
|
||||
constexpr inline bool isMask_64(uint64_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
|
||||
constexpr inline bool isShiftedMask_32(uint32_t Value) {
|
||||
return Value && isMask_32((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (64 bit version.)
|
||||
constexpr inline bool isShiftedMask_64(uint64_t Value) {
|
||||
return Value && isMask_64((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument is a power of two > 0.
|
||||
/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
|
||||
constexpr inline bool isPowerOf2_32(uint32_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// Return true if the argument is a power of two > 0 (64 bit edition.)
|
||||
constexpr inline bool isPowerOf2_64(uint64_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// Count the number of ones from the most significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countLeadingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
/// Count the number of ones from the least significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. countTrailingOnes(0x00FF00FF) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
unsigned countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countTrailingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT> struct PopulationCounter {
|
||||
static unsigned count(T Value) {
|
||||
// Generic version, forward to 32 bits.
|
||||
static_assert(SizeOfT <= 4, "Not implemented!");
|
||||
#if defined(__GNUC__)
|
||||
return __builtin_popcount(Value);
|
||||
#else
|
||||
uint32_t v = Value;
|
||||
v = v - ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct PopulationCounter<T, 8> {
|
||||
static unsigned count(T Value) {
|
||||
#if defined(__GNUC__)
|
||||
return __builtin_popcountll(Value);
|
||||
#else
|
||||
uint64_t v = Value;
|
||||
v = v - ((v >> 1) & 0x5555555555555555ULL);
|
||||
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
|
||||
v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// Count the number of set bits in a value.
|
||||
/// Ex. countPopulation(0xF000F000) = 8
|
||||
/// Returns 0 if the word is zero.
|
||||
template <typename T>
|
||||
inline unsigned countPopulation(T Value) {
|
||||
static_assert(std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
|
||||
}
|
||||
|
||||
/// Compile time Log2.
|
||||
/// Valid only for positive powers of two.
|
||||
template <size_t kValue> constexpr inline size_t CTLog2() {
|
||||
static_assert(kValue > 0 && wpi::isPowerOf2_64(kValue),
|
||||
"Value is not a valid power of 2");
|
||||
return 1 + CTLog2<kValue / 2>();
|
||||
}
|
||||
|
||||
template <> constexpr inline size_t CTLog2<1>() { return 0; }
|
||||
|
||||
/// Return the log base 2 of the specified value.
|
||||
inline double Log2(double Value) {
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
|
||||
return __builtin_log(Value) / __builtin_log(2.0);
|
||||
#else
|
||||
return std::log2(Value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (32 bit edition.)
|
||||
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
|
||||
inline unsigned Log2_32(uint32_t Value) {
|
||||
return static_cast<unsigned>(31 - countLeadingZeros(Value));
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64(uint64_t Value) {
|
||||
return static_cast<unsigned>(63 - countLeadingZeros(Value));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
|
||||
/// (32 bit edition).
|
||||
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
|
||||
inline unsigned Log2_32_Ceil(uint32_t Value) {
|
||||
return static_cast<unsigned>(32 - countLeadingZeros(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64_Ceil(uint64_t Value) {
|
||||
return static_cast<unsigned>(64 - countLeadingZeros(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the greatest common divisor of the values using Euclid's algorithm.
|
||||
template <typename T>
|
||||
inline T greatestCommonDivisor(T A, T B) {
|
||||
while (B) {
|
||||
T Tmp = B;
|
||||
B = A % B;
|
||||
A = Tmp;
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
|
||||
return greatestCommonDivisor<uint64_t>(A, B);
|
||||
}
|
||||
|
||||
/// This function takes a 64-bit integer and returns the bit equivalent double.
|
||||
inline double BitsToDouble(uint64_t Bits) {
|
||||
double D;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&D, &Bits, sizeof(Bits));
|
||||
return D;
|
||||
}
|
||||
|
||||
/// This function takes a 32-bit integer and returns the bit equivalent float.
|
||||
inline float BitsToFloat(uint32_t Bits) {
|
||||
float F;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&F, &Bits, sizeof(Bits));
|
||||
return F;
|
||||
}
|
||||
|
||||
/// This function takes a double and returns the bit equivalent 64-bit integer.
|
||||
/// Note that copying doubles around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint64_t DoubleToBits(double Double) {
|
||||
uint64_t Bits;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Double, sizeof(Double));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// This function takes a float and returns the bit equivalent 32-bit integer.
|
||||
/// Note that copying floats around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint32_t FloatToBits(float Float) {
|
||||
uint32_t Bits;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Float, sizeof(Float));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// A and B are either alignments or offsets. Return the minimum alignment that
|
||||
/// may be assumed after adding the two together.
|
||||
constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
|
||||
// The largest power of 2 that divides both A and B.
|
||||
//
|
||||
// Replace "-Value" by "1+~Value" in the following commented code to avoid
|
||||
// MSVC warning C4146
|
||||
// return (A | B) & -(A | B);
|
||||
return (A | B) & (1 + ~(A | B));
|
||||
}
|
||||
|
||||
/// Returns the next power of two (in 64-bits) that is strictly greater than A.
|
||||
/// Returns zero on overflow.
|
||||
inline uint64_t NextPowerOf2(uint64_t A) {
|
||||
A |= (A >> 1);
|
||||
A |= (A >> 2);
|
||||
A |= (A >> 4);
|
||||
A |= (A >> 8);
|
||||
A |= (A >> 16);
|
||||
A |= (A >> 32);
|
||||
return A + 1;
|
||||
}
|
||||
|
||||
/// Returns the power of two which is less than or equal to the given value.
|
||||
/// Essentially, it is a floor operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Floor(uint64_t A) {
|
||||
if (!A) return 0;
|
||||
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
|
||||
}
|
||||
|
||||
/// Returns the power of two which is greater than or equal to the given value.
|
||||
/// Essentially, it is a ceil operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Ceil(uint64_t A) {
|
||||
if (!A)
|
||||
return 0;
|
||||
return NextPowerOf2(A - 1);
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
|
||||
///
|
||||
/// If non-zero \p Skew is specified, the return value will be a minimal
|
||||
/// integer that is greater than or equal to \p Value and equal to
|
||||
/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
|
||||
/// \p Align, its value is adjusted to '\p Skew mod \p Align'.
|
||||
///
|
||||
/// Examples:
|
||||
/// \code
|
||||
/// alignTo(5, 8) = 8
|
||||
/// alignTo(17, 8) = 24
|
||||
/// alignTo(~0LL, 8) = 0
|
||||
/// alignTo(321, 255) = 510
|
||||
///
|
||||
/// alignTo(5, 8, 7) = 7
|
||||
/// alignTo(17, 8, 1) = 17
|
||||
/// alignTo(~0LL, 8, 3) = 3
|
||||
/// alignTo(321, 255, 42) = 552
|
||||
/// \endcode
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value + Align - 1 - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
|
||||
template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
|
||||
static_assert(Align != 0u, "Align must be non-zero");
|
||||
return (Value + Align - 1) / Align * Align;
|
||||
}
|
||||
|
||||
/// Returns the integer ceil(Numerator / Denominator).
|
||||
inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
|
||||
return alignTo(Numerator, Denominator) / Denominator;
|
||||
}
|
||||
|
||||
/// Returns the integer nearest(Numerator / Denominator).
|
||||
inline uint64_t divideNearest(uint64_t Numerator, uint64_t Denominator) {
|
||||
return (Numerator + (Denominator / 2)) / Denominator;
|
||||
}
|
||||
|
||||
/// Returns the largest uint64_t less than or equal to \p Value and is
|
||||
/// \p Skew mod \p Align. \p Align must be non-zero
|
||||
inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B <= 32.
|
||||
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 32, "Bit width out of range.");
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B <= 32.
|
||||
inline int32_t SignExtend32(uint32_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 32 && "Bit width out of range.");
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B <= 64.
|
||||
template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 64, "Bit width out of range.");
|
||||
return int64_t(x << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B <= 64.
|
||||
inline int64_t SignExtend64(uint64_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 64 && "Bit width out of range.");
|
||||
return int64_t(X << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
|
||||
/// value of the result.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
|
||||
return X > Y ? (X - Y) : (Y - X);
|
||||
}
|
||||
|
||||
/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow. ResultOverflowed indicates if
|
||||
/// the result is larger than the maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T>
|
||||
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
// Hacker's Delight, p. 29
|
||||
T Z = X + Y;
|
||||
Overflowed = (Z < X || Z < Y);
|
||||
if (Overflowed)
|
||||
return (std::numeric_limits<T>::max)();
|
||||
else
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow. ResultOverflowed indicates if
|
||||
/// the result is larger than the maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T>
|
||||
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
// Hacker's Delight, p. 30 has a different algorithm, but we don't use that
|
||||
// because it fails for uint16_t (where multiplication can have undefined
|
||||
// behavior due to promotion to int), and requires a division in addition
|
||||
// to the multiplication.
|
||||
|
||||
Overflowed = false;
|
||||
|
||||
// Log2(Z) would be either Log2Z or Log2Z + 1.
|
||||
// Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
|
||||
// will necessarily be less than Log2Max as desired.
|
||||
int Log2Z = Log2_64(X) + Log2_64(Y);
|
||||
const T Max = (std::numeric_limits<T>::max)();
|
||||
int Log2Max = Log2_64(Max);
|
||||
if (Log2Z < Log2Max) {
|
||||
return X * Y;
|
||||
}
|
||||
if (Log2Z > Log2Max) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
|
||||
// We're going to use the top bit, and maybe overflow one
|
||||
// bit past it. Multiply all but the bottom bit then add
|
||||
// that on at the end.
|
||||
T Z = (X >> 1) * Y;
|
||||
if (Z & ~(Max >> 1)) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
Z <<= 1;
|
||||
if (X & 1)
|
||||
return SaturatingAdd(Z, Y, ResultOverflowed);
|
||||
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
|
||||
/// the product. Clamp the result to the maximum representable value of T on
|
||||
/// overflow. ResultOverflowed indicates if the result is larger than the
|
||||
/// maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, T>
|
||||
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
T Product = SaturatingMultiply(X, Y, &Overflowed);
|
||||
if (Overflowed)
|
||||
return Product;
|
||||
|
||||
return SaturatingAdd(A, Product, &Overflowed);
|
||||
}
|
||||
|
||||
/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
|
||||
extern const float huge_valf;
|
||||
|
||||
|
||||
/// Add two signed integers, computing the two's complement truncated result,
|
||||
/// returning true if overflow occured.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
|
||||
#if __has_builtin(__builtin_add_overflow)
|
||||
return __builtin_add_overflow(X, Y, &Result);
|
||||
#else
|
||||
// Perform the unsigned addition.
|
||||
using U = std::make_unsigned_t<T>;
|
||||
const U UX = static_cast<U>(X);
|
||||
const U UY = static_cast<U>(Y);
|
||||
const U UResult = UX + UY;
|
||||
|
||||
// Convert to signed.
|
||||
Result = static_cast<T>(UResult);
|
||||
|
||||
// Adding two positive numbers should result in a positive number.
|
||||
if (X > 0 && Y > 0)
|
||||
return Result <= 0;
|
||||
// Adding two negatives should result in a negative number.
|
||||
if (X < 0 && Y < 0)
|
||||
return Result >= 0;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Subtract two signed integers, computing the two's complement truncated
|
||||
/// result, returning true if an overflow ocurred.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) {
|
||||
#if __has_builtin(__builtin_sub_overflow)
|
||||
return __builtin_sub_overflow(X, Y, &Result);
|
||||
#else
|
||||
// Perform the unsigned addition.
|
||||
using U = std::make_unsigned_t<T>;
|
||||
const U UX = static_cast<U>(X);
|
||||
const U UY = static_cast<U>(Y);
|
||||
const U UResult = UX - UY;
|
||||
|
||||
// Convert to signed.
|
||||
Result = static_cast<T>(UResult);
|
||||
|
||||
// Subtracting a positive number from a negative results in a negative number.
|
||||
if (X <= 0 && Y > 0)
|
||||
return Result >= 0;
|
||||
// Subtracting a negative number from a positive results in a positive number.
|
||||
if (X >= 0 && Y < 0)
|
||||
return Result <= 0;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Multiply two signed integers, computing the two's complement truncated
|
||||
/// result, returning true if an overflow ocurred.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) {
|
||||
// Perform the unsigned multiplication on absolute values.
|
||||
using U = std::make_unsigned_t<T>;
|
||||
const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
|
||||
const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
|
||||
const U UResult = UX * UY;
|
||||
|
||||
// Convert to signed.
|
||||
const bool IsNegative = (X < 0) ^ (Y < 0);
|
||||
Result = IsNegative ? (0 - UResult) : UResult;
|
||||
|
||||
// If any of the args was 0, result is 0 and no overflow occurs.
|
||||
if (UX == 0 || UY == 0)
|
||||
return false;
|
||||
|
||||
// UX and UY are in [1, 2^n], where n is the number of digits.
|
||||
// Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
|
||||
// positive) divided by an argument compares to the other.
|
||||
if (IsNegative)
|
||||
return UX > (static_cast<U>((std::numeric_limits<T>::max)()) + U(1)) / UY;
|
||||
else
|
||||
return UX > (static_cast<U>((std::numeric_limits<T>::max)())) / UY;
|
||||
}
|
||||
|
||||
// Typesafe implementation of the signum function.
|
||||
// Returns -1 if negative, 1 if positive, 0 if 0.
|
||||
template <typename T>
|
||||
constexpr int sgn(T val) {
|
||||
return (T(0) < val) - (val < T(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly interpolates between two values.
|
||||
*
|
||||
* @param startValue The start value.
|
||||
* @param endValue The end value.
|
||||
* @param t The fraction for interpolation.
|
||||
*
|
||||
* @return The interpolated value.
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr T Lerp(const T& startValue, const T& endValue, double t) {
|
||||
return startValue + (endValue - startValue) * t;
|
||||
}
|
||||
} // End wpi namespace
|
||||
|
||||
#endif
|
||||
100
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemAlloc.h
vendored
Normal file
100
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemAlloc.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// This file defines counterparts of C library allocation functions defined in
|
||||
/// the namespace 'std'. The new allocation functions crash on allocation
|
||||
/// failure instead of returning null pointer.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_MEMALLOC_H
|
||||
#define WPIUTIL_WPI_MEMALLOC_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
// Warning on NONNULL, report is not known to abort
|
||||
#pragma warning(disable : 6387)
|
||||
#pragma warning(disable : 28196)
|
||||
#pragma warning(disable : 28183)
|
||||
#endif
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
|
||||
void *Result = std::malloc(Sz);
|
||||
if (Result == nullptr) {
|
||||
// It is implementation-defined whether allocation occurs if the space
|
||||
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
|
||||
// non-zero, if the space requested was zero.
|
||||
if (Sz == 0)
|
||||
return safe_malloc(1);
|
||||
report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
|
||||
size_t Sz) {
|
||||
void *Result = std::calloc(Count, Sz);
|
||||
if (Result == nullptr) {
|
||||
// It is implementation-defined whether allocation occurs if the space
|
||||
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
|
||||
// non-zero, if the space requested was zero.
|
||||
if (Count == 0 || Sz == 0)
|
||||
return safe_malloc(1);
|
||||
report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
|
||||
void *Result = std::realloc(Ptr, Sz);
|
||||
if (Result == nullptr) {
|
||||
// It is implementation-defined whether allocation occurs if the space
|
||||
// requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
|
||||
// non-zero, if the space requested was zero.
|
||||
if (Sz == 0)
|
||||
return safe_malloc(1);
|
||||
report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Allocate a buffer of memory with the given size and alignment.
|
||||
///
|
||||
/// When the compiler supports aligned operator new, this will use it to to
|
||||
/// handle even over-aligned allocations.
|
||||
///
|
||||
/// However, this doesn't make any attempt to leverage the fancier techniques
|
||||
/// like posix_memalign due to portability. It is mostly intended to allow
|
||||
/// compatibility with platforms that, after aligned allocation was added, use
|
||||
/// reduced default alignment.
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
|
||||
allocate_buffer(size_t Size, size_t Alignment);
|
||||
|
||||
/// Deallocate a buffer of memory with the given size and alignment.
|
||||
///
|
||||
/// If supported, this will used the sized delete operator. Also if supported,
|
||||
/// this will pass the alignment to the delete operator.
|
||||
///
|
||||
/// The pointer must have been allocated with the corresponding new operator,
|
||||
/// most likely using the above helper.
|
||||
void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
240
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h
vendored
Normal file
240
wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
//===--- MemoryBuffer.h - Memory Buffer Interface ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the MemoryBuffer interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
#include "wpi/span.h"
|
||||
|
||||
// Duplicated from fs.h to avoid a dependency
|
||||
namespace fs {
|
||||
#if defined(_WIN32)
|
||||
// A Win32 HANDLE is a typedef of void*
|
||||
using file_t = void*;
|
||||
#else
|
||||
using file_t = int;
|
||||
#endif
|
||||
} // namespace fs
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class MemoryBufferRef;
|
||||
|
||||
/// This interface provides simple read-only access to a block of memory, and
|
||||
/// provides simple methods for reading files and standard input into a memory
|
||||
/// buffer.
|
||||
class MemoryBuffer {
|
||||
const uint8_t* m_bufferStart; // Start of the buffer.
|
||||
const uint8_t* m_bufferEnd; // End of the buffer.
|
||||
|
||||
protected:
|
||||
MemoryBuffer() = default;
|
||||
|
||||
void Init(const uint8_t* bufStart, const uint8_t* bufEnd);
|
||||
|
||||
public:
|
||||
MemoryBuffer(const MemoryBuffer&) = delete;
|
||||
MemoryBuffer& operator=(const MemoryBuffer&) = delete;
|
||||
virtual ~MemoryBuffer();
|
||||
|
||||
const uint8_t* begin() const { return m_bufferStart; }
|
||||
const uint8_t* end() const { return m_bufferEnd; }
|
||||
size_t size() const { return m_bufferEnd - m_bufferStart; }
|
||||
|
||||
span<const uint8_t> GetBuffer() const { return {begin(), end()}; }
|
||||
|
||||
/// Return an identifier for this buffer, typically the filename it was read
|
||||
/// from.
|
||||
virtual std::string_view GetBufferIdentifier() const {
|
||||
return "Unknown buffer";
|
||||
}
|
||||
|
||||
/// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
|
||||
/// if successful, otherwise returning null. If FileSize is specified, this
|
||||
/// means that the client knows that the file exists and that it has the
|
||||
/// specified size.
|
||||
static std::unique_ptr<MemoryBuffer> GetFile(std::string_view filename,
|
||||
std::error_code& ec,
|
||||
int64_t fileSize = -1);
|
||||
|
||||
/// Read all of the specified file into a MemoryBuffer as a stream
|
||||
/// (i.e. until EOF reached). This is useful for special files that
|
||||
/// look like a regular file but have 0 size (e.g. /proc/cpuinfo on Linux).
|
||||
static std::unique_ptr<MemoryBuffer> GetFileAsStream(
|
||||
std::string_view filename, std::error_code& ec);
|
||||
|
||||
/// Given an already-open file descriptor, map some slice of it into a
|
||||
/// MemoryBuffer. The slice is specified by an \p Offset and \p MapSize.
|
||||
static std::unique_ptr<MemoryBuffer> GetOpenFileSlice(
|
||||
fs::file_t f, std::string_view filename, std::error_code& ec,
|
||||
uint64_t mapSize, int64_t offset);
|
||||
|
||||
/// Given an already-open file descriptor, read the file and return a
|
||||
/// MemoryBuffer.
|
||||
static std::unique_ptr<MemoryBuffer> GetOpenFile(fs::file_t f,
|
||||
std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t fileSize);
|
||||
|
||||
/// Open the specified memory range as a MemoryBuffer.
|
||||
static std::unique_ptr<MemoryBuffer> GetMemBuffer(
|
||||
span<const uint8_t> inputData, std::string_view bufferName = "");
|
||||
|
||||
static std::unique_ptr<MemoryBuffer> GetMemBuffer(MemoryBufferRef ref);
|
||||
|
||||
/// Open the specified memory range as a MemoryBuffer, copying the contents
|
||||
/// and taking ownership of it.
|
||||
static std::unique_ptr<MemoryBuffer> GetMemBufferCopy(
|
||||
span<const uint8_t> inputData, std::string_view bufferName = "");
|
||||
|
||||
/// Map a subrange of the specified file as a MemoryBuffer.
|
||||
static std::unique_ptr<MemoryBuffer> GetFileSlice(std::string_view filename,
|
||||
std::error_code& ec,
|
||||
uint64_t mapSize,
|
||||
uint64_t offset);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Provided for performance analysis.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// The kind of memory backing used to support the MemoryBuffer.
|
||||
enum BufferKind { MemoryBuffer_Malloc, MemoryBuffer_MMap };
|
||||
|
||||
/// Return information on the memory mechanism used to support the
|
||||
/// MemoryBuffer.
|
||||
virtual BufferKind GetBufferKind() const = 0;
|
||||
|
||||
MemoryBufferRef GetMemBufferRef() const;
|
||||
};
|
||||
|
||||
/// This class is an extension of MemoryBuffer, which allows copy-on-write
|
||||
/// access to the underlying contents. It only supports creation methods that
|
||||
/// are guaranteed to produce a writable buffer. For example, mapping a file
|
||||
/// read-only is not supported.
|
||||
class WritableMemoryBuffer : public MemoryBuffer {
|
||||
protected:
|
||||
WritableMemoryBuffer() = default;
|
||||
|
||||
public:
|
||||
using MemoryBuffer::begin;
|
||||
using MemoryBuffer::end;
|
||||
using MemoryBuffer::GetBuffer;
|
||||
using MemoryBuffer::size;
|
||||
|
||||
// const_cast is well-defined here, because the underlying buffer is
|
||||
// guaranteed to have been initialized with a mutable buffer.
|
||||
uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
|
||||
uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
|
||||
span<uint8_t> GetBuffer() { return {begin(), end()}; }
|
||||
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
|
||||
|
||||
/// Map a subrange of the specified file as a WritableMemoryBuffer.
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetFileSlice(
|
||||
std::string_view filename, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset);
|
||||
|
||||
/// Allocate a new MemoryBuffer of the specified size that is not initialized.
|
||||
/// Note that the caller should initialize the memory allocated by this
|
||||
/// method. The memory is owned by the MemoryBuffer object.
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetNewUninitMemBuffer(
|
||||
size_t size, std::string_view bufferName = "");
|
||||
|
||||
/// Allocate a new zero-initialized MemoryBuffer of the specified size. Note
|
||||
/// that the caller need not initialize the memory allocated by this method.
|
||||
/// The memory is owned by the MemoryBuffer object.
|
||||
static std::unique_ptr<WritableMemoryBuffer> GetNewMemBuffer(
|
||||
size_t size, std::string_view bufferName = "");
|
||||
|
||||
private:
|
||||
// Hide these base class factory function so one can't write
|
||||
// WritableMemoryBuffer::getXXX()
|
||||
// and be surprised that they got a read-only Buffer.
|
||||
using MemoryBuffer::GetFileAsStream;
|
||||
using MemoryBuffer::GetMemBuffer;
|
||||
using MemoryBuffer::GetMemBufferCopy;
|
||||
using MemoryBuffer::GetOpenFile;
|
||||
using MemoryBuffer::GetOpenFileSlice;
|
||||
};
|
||||
|
||||
/// This class is an extension of MemoryBuffer, which allows write access to
|
||||
/// the underlying contents and committing those changes to the original source.
|
||||
/// It only supports creation methods that are guaranteed to produce a writable
|
||||
/// buffer. For example, mapping a file read-only is not supported.
|
||||
class WriteThroughMemoryBuffer : public MemoryBuffer {
|
||||
protected:
|
||||
WriteThroughMemoryBuffer() = default;
|
||||
|
||||
public:
|
||||
using MemoryBuffer::begin;
|
||||
using MemoryBuffer::end;
|
||||
using MemoryBuffer::GetBuffer;
|
||||
using MemoryBuffer::size;
|
||||
|
||||
// const_cast is well-defined here, because the underlying buffer is
|
||||
// guaranteed to have been initialized with a mutable buffer.
|
||||
uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
|
||||
uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
|
||||
span<uint8_t> GetBuffer() { return {begin(), end()}; }
|
||||
|
||||
static std::unique_ptr<WriteThroughMemoryBuffer> GetFile(
|
||||
std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
|
||||
|
||||
/// Map a subrange of the specified file as a ReadWriteMemoryBuffer.
|
||||
static std::unique_ptr<WriteThroughMemoryBuffer> GetFileSlice(
|
||||
std::string_view filename, std::error_code& ec, uint64_t mapSize,
|
||||
uint64_t offset);
|
||||
|
||||
private:
|
||||
// Hide these base class factory function so one can't write
|
||||
// WritableMemoryBuffer::getXXX()
|
||||
// and be surprised that they got a read-only Buffer.
|
||||
using MemoryBuffer::GetFileAsStream;
|
||||
using MemoryBuffer::GetMemBuffer;
|
||||
using MemoryBuffer::GetMemBufferCopy;
|
||||
using MemoryBuffer::GetOpenFile;
|
||||
using MemoryBuffer::GetOpenFileSlice;
|
||||
};
|
||||
|
||||
class MemoryBufferRef {
|
||||
span<const uint8_t> m_buffer;
|
||||
std::string_view m_id;
|
||||
|
||||
public:
|
||||
MemoryBufferRef() = default;
|
||||
MemoryBufferRef(MemoryBuffer& buffer) // NOLINT
|
||||
: m_buffer(buffer.GetBuffer()), m_id(buffer.GetBufferIdentifier()) {}
|
||||
MemoryBufferRef(span<const uint8_t> buffer, std::string_view id)
|
||||
: m_buffer(buffer), m_id(id) {}
|
||||
|
||||
span<const uint8_t> GetBuffer() const { return m_buffer; }
|
||||
|
||||
std::string_view GetBufferIdentifier() const { return m_id; }
|
||||
|
||||
const uint8_t* begin() const { return m_buffer.begin(); }
|
||||
const uint8_t* end() const { return m_buffer.end(); }
|
||||
size_t size() const { return m_buffer.size(); }
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
232
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
vendored
Normal file
232
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerIntPair class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_POINTERINTPAIR_H
|
||||
#define WPIUTIL_WPI_POINTERINTPAIR_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T> struct DenseMapInfo;
|
||||
template <typename PointerT, unsigned IntBits, typename PtrTraits>
|
||||
struct PointerIntPairInfo;
|
||||
|
||||
/// PointerIntPair - This class implements a pair of a pointer and small
|
||||
/// integer. It is designed to represent this in the space required by one
|
||||
/// pointer by bitmangling the integer into the low part of the pointer. This
|
||||
/// can only be done for small integers: typically up to 3 bits, but it depends
|
||||
/// on the number of bits available according to PointerLikeTypeTraits for the
|
||||
/// type.
|
||||
///
|
||||
/// Note that PointerIntPair always puts the IntVal part in the highest bits
|
||||
/// possible. For example, PointerIntPair<void*, 1, bool> will put the bit for
|
||||
/// the bool into bit #2, not bit #0, which allows the low two bits to be used
|
||||
/// for something else. For example, this allows:
|
||||
/// PointerIntPair<PointerIntPair<void*, 1, bool>, 1, bool>
|
||||
/// ... and the two bools will land in different bits.
|
||||
template <typename PointerTy, unsigned IntBits, typename IntType = unsigned,
|
||||
typename PtrTraits = PointerLikeTypeTraits<PointerTy>,
|
||||
typename Info = PointerIntPairInfo<PointerTy, IntBits, PtrTraits>>
|
||||
class PointerIntPair {
|
||||
// Used by MSVC visualizer and generally helpful for debugging/visualizing.
|
||||
using InfoTy = Info;
|
||||
intptr_t Value = 0;
|
||||
|
||||
public:
|
||||
constexpr PointerIntPair() = default;
|
||||
|
||||
PointerIntPair(PointerTy PtrVal, IntType IntVal) {
|
||||
setPointerAndInt(PtrVal, IntVal);
|
||||
}
|
||||
|
||||
explicit PointerIntPair(PointerTy PtrVal) { initWithPointer(PtrVal); }
|
||||
|
||||
PointerTy getPointer() const { return Info::getPointer(Value); }
|
||||
|
||||
IntType getInt() const { return (IntType)Info::getInt(Value); }
|
||||
|
||||
void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updatePointer(Value, PtrVal);
|
||||
}
|
||||
|
||||
void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updatePointer(0, PtrVal);
|
||||
}
|
||||
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
|
||||
static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
PointerTy const *getAddrOfPointer() const {
|
||||
return const_cast<PointerIntPair *>(this)->getAddrOfPointer();
|
||||
}
|
||||
|
||||
PointerTy *getAddrOfPointer() {
|
||||
assert(Value == reinterpret_cast<intptr_t>(getPointer()) &&
|
||||
"Can only return the address if IntBits is cleared and "
|
||||
"PtrTraits doesn't change the pointer");
|
||||
return reinterpret_cast<PointerTy *>(&Value);
|
||||
}
|
||||
|
||||
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
|
||||
|
||||
void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
|
||||
Value = reinterpret_cast<intptr_t>(Val);
|
||||
}
|
||||
|
||||
static PointerIntPair getFromOpaqueValue(void *V) {
|
||||
PointerIntPair P;
|
||||
P.setFromOpaqueValue(V);
|
||||
return P;
|
||||
}
|
||||
|
||||
// Allow PointerIntPairs to be created from const void * if and only if the
|
||||
// pointer type could be created from a const void *.
|
||||
static PointerIntPair getFromOpaqueValue(const void *V) {
|
||||
(void)PtrTraits::getFromVoidPointer(V);
|
||||
return getFromOpaqueValue(const_cast<void *>(V));
|
||||
}
|
||||
|
||||
bool operator==(const PointerIntPair &RHS) const {
|
||||
return Value == RHS.Value;
|
||||
}
|
||||
|
||||
bool operator!=(const PointerIntPair &RHS) const {
|
||||
return Value != RHS.Value;
|
||||
}
|
||||
|
||||
bool operator<(const PointerIntPair &RHS) const { return Value < RHS.Value; }
|
||||
bool operator>(const PointerIntPair &RHS) const { return Value > RHS.Value; }
|
||||
|
||||
bool operator<=(const PointerIntPair &RHS) const {
|
||||
return Value <= RHS.Value;
|
||||
}
|
||||
|
||||
bool operator>=(const PointerIntPair &RHS) const {
|
||||
return Value >= RHS.Value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename PointerT, unsigned IntBits, typename PtrTraits>
|
||||
struct PointerIntPairInfo {
|
||||
static_assert(PtrTraits::NumLowBitsAvailable <
|
||||
std::numeric_limits<uintptr_t>::digits,
|
||||
"cannot use a pointer type that has all bits free");
|
||||
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
|
||||
"PointerIntPair with integer size too large for pointer");
|
||||
enum MaskAndShiftConstants : uintptr_t {
|
||||
/// PointerBitMask - The bits that come from the pointer.
|
||||
PointerBitMask =
|
||||
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1),
|
||||
|
||||
/// IntShift - The number of low bits that we reserve for other uses, and
|
||||
/// keep zero.
|
||||
IntShift = (uintptr_t)PtrTraits::NumLowBitsAvailable - IntBits,
|
||||
|
||||
/// IntMask - This is the unshifted mask for valid bits of the int type.
|
||||
IntMask = (uintptr_t)(((intptr_t)1 << IntBits) - 1),
|
||||
|
||||
// ShiftedIntMask - This is the bits for the integer shifted in place.
|
||||
ShiftedIntMask = (uintptr_t)(IntMask << IntShift)
|
||||
};
|
||||
|
||||
static PointerT getPointer(intptr_t Value) {
|
||||
return PtrTraits::getFromVoidPointer(
|
||||
reinterpret_cast<void *>(Value & PointerBitMask));
|
||||
}
|
||||
|
||||
static intptr_t getInt(intptr_t Value) {
|
||||
return (Value >> IntShift) & IntMask;
|
||||
}
|
||||
|
||||
static intptr_t updatePointer(intptr_t OrigValue, PointerT Ptr) {
|
||||
intptr_t PtrWord =
|
||||
reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(Ptr));
|
||||
assert((PtrWord & ~PointerBitMask) == 0 &&
|
||||
"Pointer is not sufficiently aligned");
|
||||
// Preserve all low bits, just update the pointer.
|
||||
return PtrWord | (OrigValue & ~PointerBitMask);
|
||||
}
|
||||
|
||||
static intptr_t updateInt(intptr_t OrigValue, intptr_t Int) {
|
||||
intptr_t IntWord = static_cast<intptr_t>(Int);
|
||||
assert((IntWord & ~IntMask) == 0 && "Integer too large for field");
|
||||
|
||||
// Preserve all bits other than the ones we are updating.
|
||||
return (OrigValue & ~ShiftedIntMask) | IntWord << IntShift;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide specialization of DenseMapInfo for PointerIntPair.
|
||||
template <typename PointerTy, unsigned IntBits, typename IntType>
|
||||
struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>> {
|
||||
using Ty = PointerIntPair<PointerTy, IntBits, IntType>;
|
||||
|
||||
static Ty getEmptyKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= PointerLikeTypeTraits<Ty>::NumLowBitsAvailable;
|
||||
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||
}
|
||||
|
||||
static Ty getTombstoneKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||
Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable;
|
||||
return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(Ty V) {
|
||||
uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue());
|
||||
return unsigned(IV) ^ unsigned(IV >> 9);
|
||||
}
|
||||
|
||||
static bool isEqual(const Ty &LHS, const Ty &RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Teach SmallPtrSet that PointerIntPair is "basically a pointer".
|
||||
template <typename PointerTy, unsigned IntBits, typename IntType,
|
||||
typename PtrTraits>
|
||||
struct PointerLikeTypeTraits<
|
||||
PointerIntPair<PointerTy, IntBits, IntType, PtrTraits>> {
|
||||
static inline void *
|
||||
getAsVoidPointer(const PointerIntPair<PointerTy, IntBits, IntType> &P) {
|
||||
return P.getOpaqueValue();
|
||||
}
|
||||
|
||||
static inline PointerIntPair<PointerTy, IntBits, IntType>
|
||||
getFromVoidPointer(void *P) {
|
||||
return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
static inline PointerIntPair<PointerTy, IntBits, IntType>
|
||||
getFromVoidPointer(const void *P) {
|
||||
return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
static constexpr int NumLowBitsAvailable =
|
||||
PtrTraits::NumLowBitsAvailable - IntBits;
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_POINTERINTPAIR_H
|
||||
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerLikeTypeTraits.h
vendored
Normal file
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerLikeTypeTraits.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerLikeTypeTraits class. This allows data
|
||||
// structures to reason about pointers and other things that are pointer sized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
|
||||
#define WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// A traits type that is used to handle pointer types and things that are just
|
||||
/// wrappers for pointers as a uniform entity.
|
||||
template <typename T> struct PointerLikeTypeTraits;
|
||||
|
||||
namespace detail {
|
||||
/// A tiny meta function to compute the log2 of a compile time constant.
|
||||
template <size_t N>
|
||||
struct ConstantLog2
|
||||
: std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
|
||||
template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
|
||||
|
||||
// Provide a trait to check if T is pointer-like.
|
||||
template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
// sizeof(T) is valid only for a complete T.
|
||||
template <typename T>
|
||||
struct HasPointerLikeTypeTraits<
|
||||
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename T> struct IsPointerLike {
|
||||
static const bool value = HasPointerLikeTypeTraits<T>::value;
|
||||
};
|
||||
|
||||
template <typename T> struct IsPointerLike<T *> {
|
||||
static const bool value = true;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// Provide PointerLikeTypeTraits for non-cvr pointers.
|
||||
template <typename T> struct PointerLikeTypeTraits<T *> {
|
||||
static inline void *getAsVoidPointer(T *P) { return P; }
|
||||
static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
|
||||
|
||||
static constexpr int NumLowBitsAvailable =
|
||||
detail::ConstantLog2<alignof(T)>::value;
|
||||
};
|
||||
|
||||
template <> struct PointerLikeTypeTraits<void *> {
|
||||
static inline void *getAsVoidPointer(void *P) { return P; }
|
||||
static inline void *getFromVoidPointer(void *P) { return P; }
|
||||
|
||||
/// Note, we assume here that void* is related to raw malloc'ed memory and
|
||||
/// that malloc returns objects at least 4-byte aligned. However, this may be
|
||||
/// wrong, or pointers may be from something other than malloc. In this case,
|
||||
/// you should specify a real typed pointer or avoid this template.
|
||||
///
|
||||
/// All clients should use assertions to do a run-time check to ensure that
|
||||
/// this is actually true.
|
||||
static constexpr int NumLowBitsAvailable = 2;
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const things.
|
||||
template <typename T> struct PointerLikeTypeTraits<const T> {
|
||||
typedef PointerLikeTypeTraits<T> NonConst;
|
||||
|
||||
static inline const void *getAsVoidPointer(const T P) {
|
||||
return NonConst::getAsVoidPointer(P);
|
||||
}
|
||||
static inline const T getFromVoidPointer(const void *P) {
|
||||
return NonConst::getFromVoidPointer(const_cast<void *>(P));
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const pointers.
|
||||
template <typename T> struct PointerLikeTypeTraits<const T *> {
|
||||
typedef PointerLikeTypeTraits<T *> NonConst;
|
||||
|
||||
static inline const void *getAsVoidPointer(const T *P) {
|
||||
return NonConst::getAsVoidPointer(const_cast<T *>(P));
|
||||
}
|
||||
static inline const T *getFromVoidPointer(const void *P) {
|
||||
return NonConst::getFromVoidPointer(const_cast<void *>(P));
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for uintptr_t.
|
||||
template <> struct PointerLikeTypeTraits<uintptr_t> {
|
||||
static inline void *getAsVoidPointer(uintptr_t P) {
|
||||
return reinterpret_cast<void *>(P);
|
||||
}
|
||||
static inline uintptr_t getFromVoidPointer(void *P) {
|
||||
return reinterpret_cast<uintptr_t>(P);
|
||||
}
|
||||
// No bits are available!
|
||||
static constexpr int NumLowBitsAvailable = 0;
|
||||
};
|
||||
|
||||
/// Provide suitable custom traits struct for function pointers.
|
||||
///
|
||||
/// Function pointers can't be directly given these traits as functions can't
|
||||
/// have their alignment computed with `alignof` and we need different casting.
|
||||
///
|
||||
/// To rely on higher alignment for a specialized use, you can provide a
|
||||
/// customized form of this template explicitly with higher alignment, and
|
||||
/// potentially use alignment attributes on functions to satisfy that.
|
||||
template <int Alignment, typename FunctionPointerT>
|
||||
struct FunctionPointerLikeTypeTraits {
|
||||
static constexpr int NumLowBitsAvailable =
|
||||
detail::ConstantLog2<Alignment>::value;
|
||||
static inline void *getAsVoidPointer(FunctionPointerT P) {
|
||||
assert((reinterpret_cast<uintptr_t>(P) &
|
||||
~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&
|
||||
"Alignment not satisfied for an actual function pointer!");
|
||||
return reinterpret_cast<void *>(P);
|
||||
}
|
||||
static inline FunctionPointerT getFromVoidPointer(void *P) {
|
||||
return reinterpret_cast<FunctionPointerT>(P);
|
||||
}
|
||||
};
|
||||
|
||||
/// Provide a default specialization for function pointers that assumes 4-byte
|
||||
/// alignment.
|
||||
///
|
||||
/// We assume here that functions used with this are always at least 4-byte
|
||||
/// aligned. This means that, for example, thumb functions won't work or systems
|
||||
/// with weird unaligned function pointers won't work. But all practical systems
|
||||
/// we support satisfy this requirement.
|
||||
template <typename ReturnT, typename... ParamTs>
|
||||
struct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)>
|
||||
: FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
292
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
vendored
Normal file
292
wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerUnion class, which is a discriminated union of
|
||||
// pointer types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_POINTERUNION_H
|
||||
#define WPIUTIL_WPI_POINTERUNION_H
|
||||
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/PointerIntPair.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T> struct PointerUnionTypeSelectorReturn {
|
||||
using Return = T;
|
||||
};
|
||||
|
||||
/// Get a type based on whether two types are the same or not.
|
||||
///
|
||||
/// For:
|
||||
///
|
||||
/// \code
|
||||
/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
|
||||
/// \endcode
|
||||
///
|
||||
/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
|
||||
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
|
||||
struct PointerUnionTypeSelector {
|
||||
using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
|
||||
};
|
||||
|
||||
template <typename T, typename RET_EQ, typename RET_NE>
|
||||
struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
|
||||
using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
|
||||
};
|
||||
|
||||
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
|
||||
struct PointerUnionTypeSelectorReturn<
|
||||
PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
|
||||
using Return =
|
||||
typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
|
||||
};
|
||||
|
||||
namespace pointer_union_detail {
|
||||
/// Determine the number of bits required to store integers with values < n.
|
||||
/// This is ceil(log2(n)).
|
||||
constexpr int bitsRequired(unsigned n) {
|
||||
return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
|
||||
}
|
||||
|
||||
template <typename... Ts> constexpr int lowBitsAvailable() {
|
||||
return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
|
||||
}
|
||||
|
||||
/// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index
|
||||
/// is the index of T in Us, or sizeof...(Us) if T does not appear in the
|
||||
/// list.
|
||||
template <typename T, typename ...Us> struct TypeIndex;
|
||||
template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> {
|
||||
static constexpr int Index = 0;
|
||||
};
|
||||
template <typename T, typename U, typename... Us>
|
||||
struct TypeIndex<T, U, Us...> {
|
||||
static constexpr int Index = 1 + TypeIndex<T, Us...>::Index;
|
||||
};
|
||||
template <typename T> struct TypeIndex<T> {
|
||||
static constexpr int Index = 0;
|
||||
};
|
||||
|
||||
/// Find the first type in a list of types.
|
||||
template <typename T, typename...> struct GetFirstType {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
|
||||
/// for the template arguments.
|
||||
template <typename ...PTs> class PointerUnionUIntTraits {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(void *P) { return P; }
|
||||
static inline void *getFromVoidPointer(void *P) { return P; }
|
||||
static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
|
||||
};
|
||||
|
||||
template <typename Derived, typename ValTy, int I, typename ...Types>
|
||||
class PointerUnionMembers;
|
||||
|
||||
template <typename Derived, typename ValTy, int I>
|
||||
class PointerUnionMembers<Derived, ValTy, I> {
|
||||
protected:
|
||||
ValTy Val;
|
||||
PointerUnionMembers() = default;
|
||||
PointerUnionMembers(ValTy Val) : Val(Val) {}
|
||||
|
||||
friend struct PointerLikeTypeTraits<Derived>;
|
||||
};
|
||||
|
||||
template <typename Derived, typename ValTy, int I, typename Type,
|
||||
typename ...Types>
|
||||
class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
|
||||
: public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
|
||||
using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
|
||||
public:
|
||||
using Base::Base;
|
||||
PointerUnionMembers() = default;
|
||||
PointerUnionMembers(Type V)
|
||||
: Base(ValTy(const_cast<void *>(
|
||||
PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
|
||||
I)) {}
|
||||
|
||||
using Base::operator=;
|
||||
Derived &operator=(Type V) {
|
||||
this->Val = ValTy(
|
||||
const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
|
||||
I);
|
||||
return static_cast<Derived &>(*this);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// A discriminated union of two or more pointer types, with the discriminator
|
||||
/// in the low bit of the pointer.
|
||||
///
|
||||
/// This implementation is extremely efficient in space due to leveraging the
|
||||
/// low bits of the pointer, while exposing a natural and type-safe API.
|
||||
///
|
||||
/// Common use patterns would be something like this:
|
||||
/// PointerUnion<int*, float*> P;
|
||||
/// P = (int*)0;
|
||||
/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
|
||||
/// X = P.get<int*>(); // ok.
|
||||
/// Y = P.get<float*>(); // runtime assertion failure.
|
||||
/// Z = P.get<double*>(); // compile time failure.
|
||||
/// P = (float*)0;
|
||||
/// Y = P.get<float*>(); // ok.
|
||||
/// X = P.get<int*>(); // runtime assertion failure.
|
||||
template <typename... PTs>
|
||||
class PointerUnion
|
||||
: public pointer_union_detail::PointerUnionMembers<
|
||||
PointerUnion<PTs...>,
|
||||
PointerIntPair<
|
||||
void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
|
||||
pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
|
||||
0, PTs...> {
|
||||
// The first type is special because we want to directly cast a pointer to a
|
||||
// default-initialized union to a pointer to the first type. But we don't
|
||||
// want PointerUnion to be a 'template <typename First, typename ...Rest>'
|
||||
// because it's much more convenient to have a name for the whole pack. So
|
||||
// split off the first type here.
|
||||
using First = typename pointer_union_detail::GetFirstType<PTs...>::type;
|
||||
using Base = typename PointerUnion::PointerUnionMembers;
|
||||
|
||||
public:
|
||||
PointerUnion() = default;
|
||||
|
||||
PointerUnion(std::nullptr_t) : PointerUnion() {}
|
||||
using Base::Base;
|
||||
|
||||
/// Test if the pointer held in the union is null, regardless of
|
||||
/// which type it is.
|
||||
bool isNull() const { return !this->Val.getPointer(); }
|
||||
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
/// Test if the Union currently holds the type matching T.
|
||||
template <typename T> bool is() const {
|
||||
constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index;
|
||||
static_assert(Index < sizeof...(PTs),
|
||||
"PointerUnion::is<T> given type not in the union");
|
||||
return this->Val.getInt() == Index;
|
||||
}
|
||||
|
||||
/// Returns the value of the specified pointer type.
|
||||
///
|
||||
/// If the specified pointer type is incorrect, assert.
|
||||
template <typename T> T get() const {
|
||||
assert(is<T>() && "Invalid accessor called");
|
||||
return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
|
||||
}
|
||||
|
||||
/// Returns the current pointer if it is of the specified pointer type,
|
||||
/// otherwise returns null.
|
||||
template <typename T> T dyn_cast() const {
|
||||
if (is<T>())
|
||||
return get<T>();
|
||||
return T();
|
||||
}
|
||||
|
||||
/// If the union is set to the first pointer type get an address pointing to
|
||||
/// it.
|
||||
First const *getAddrOfPtr1() const {
|
||||
return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
|
||||
}
|
||||
|
||||
/// If the union is set to the first pointer type get an address pointing to
|
||||
/// it.
|
||||
First *getAddrOfPtr1() {
|
||||
assert(is<First>() && "Val is not the first pointer");
|
||||
assert(
|
||||
PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
|
||||
this->Val.getPointer() &&
|
||||
"Can't get the address because PointerLikeTypeTraits changes the ptr");
|
||||
return const_cast<First *>(
|
||||
reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
|
||||
}
|
||||
|
||||
/// Assignment from nullptr which just clears the union.
|
||||
const PointerUnion &operator=(std::nullptr_t) {
|
||||
this->Val.initWithPointer(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assignment from elements of the union.
|
||||
using Base::operator=;
|
||||
|
||||
void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
|
||||
static inline PointerUnion getFromOpaqueValue(void *VP) {
|
||||
PointerUnion V;
|
||||
V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
|
||||
return V;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ...PTs>
|
||||
bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
|
||||
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
template <typename ...PTs>
|
||||
bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
|
||||
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
template <typename ...PTs>
|
||||
bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
|
||||
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
|
||||
// # low bits available = min(PT1bits,PT2bits)-1.
|
||||
template <typename ...PTs>
|
||||
struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
|
||||
static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
|
||||
return P.getOpaqueValue();
|
||||
}
|
||||
|
||||
static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
|
||||
return PointerUnion<PTs...>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
// The number of bits available are the min of the pointer types minus the
|
||||
// bits needed for the discriminator.
|
||||
static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
|
||||
PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
|
||||
};
|
||||
|
||||
// Teach DenseMap how to use PointerUnions as keys.
|
||||
template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
|
||||
using Union = PointerUnion<PTs...>;
|
||||
using FirstInfo =
|
||||
DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
|
||||
|
||||
static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
|
||||
|
||||
static inline Union getTombstoneKey() {
|
||||
return Union(FirstInfo::getTombstoneKey());
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const Union &UnionVal) {
|
||||
intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
|
||||
return DenseMapInfo<intptr_t>::getHashValue(key);
|
||||
}
|
||||
|
||||
static bool isEqual(const Union &LHS, const Union &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_POINTERUNION_H
|
||||
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
vendored
Normal file
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef WPIUTIL_WPI_REVERSEITERATION_H
|
||||
#define WPIUTIL_WPI_REVERSEITERATION_H
|
||||
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template<class T = void *>
|
||||
bool shouldReverseIterate() {
|
||||
#if LLVM_ENABLE_REVERSE_ITERATION
|
||||
return detail::IsPointerLike<T>::value;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
82
wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
vendored
Normal file
82
wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
//===- STLForwardCompat.h - Library features from future STLs ------C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains library features backported from future STL versions.
|
||||
//
|
||||
// These should be replaced with their STL counterparts as the C++ version LLVM
|
||||
// is compiled with is updated.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
#define WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Features from C++17
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
struct negation // NOLINT(readability-identifier-naming)
|
||||
: std::integral_constant<bool, !bool(T::value)> {};
|
||||
|
||||
template <typename...>
|
||||
struct conjunction // NOLINT(readability-identifier-naming)
|
||||
: std::true_type {};
|
||||
template <typename B1> struct conjunction<B1> : B1 {};
|
||||
template <typename B1, typename... Bn>
|
||||
struct conjunction<B1, Bn...>
|
||||
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
|
||||
|
||||
template <typename...>
|
||||
struct disjunction // NOLINT(readability-identifier-naming)
|
||||
: std::false_type {};
|
||||
template <typename B1> struct disjunction<B1> : B1 {};
|
||||
template <typename B1, typename... Bn>
|
||||
struct disjunction<B1, Bn...>
|
||||
: std::conditional<bool(B1::value), B1, disjunction<Bn...>>::type {};
|
||||
|
||||
struct in_place_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_t() = default;
|
||||
};
|
||||
/// \warning This must not be odr-used, as it cannot be made \c inline in C++14.
|
||||
constexpr in_place_t in_place; // NOLINT(readability-identifier-naming)
|
||||
|
||||
template <typename T>
|
||||
struct in_place_type_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_type_t() = default;
|
||||
};
|
||||
|
||||
template <std::size_t I>
|
||||
struct in_place_index_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_index_t() = default;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Features from C++20
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
struct remove_cvref // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
using type = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t // NOLINT(readability-identifier-naming)
|
||||
= typename wpi::remove_cvref<T>::type;
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
517
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
vendored
Normal file
517
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallPtrSet class. See the doxygen comment for
|
||||
// SmallPtrSetImplBase for more details on the algorithm used.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SMALLPTRSET_H
|
||||
#define WPIUTIL_WPI_SMALLPTRSET_H
|
||||
|
||||
#include "wpi/EpochTracker.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/ReverseIteration.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallPtrSetImplBase - This is the common code shared among all the
|
||||
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||
/// for small and one for large sets.
|
||||
///
|
||||
/// Small sets use an array of pointers allocated in the SmallPtrSet object,
|
||||
/// which is treated as a simple array of pointers. When a pointer is added to
|
||||
/// the set, the array is scanned to see if the element already exists, if not
|
||||
/// the element is 'pushed back' onto the array. If we run out of space in the
|
||||
/// array, we grow into the 'large set' case. SmallSet should be used when the
|
||||
/// sets are often small. In this case, no memory allocation is used, and only
|
||||
/// light-weight and cache-efficient scanning is used.
|
||||
///
|
||||
/// Large sets use a classic exponentially-probed hash table. Empty buckets are
|
||||
/// represented with an illegal pointer value (-1) to allow null pointers to be
|
||||
/// inserted. Tombstones are represented with another illegal pointer value
|
||||
/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
|
||||
/// more. When this happens, the table is doubled in size.
|
||||
///
|
||||
class SmallPtrSetImplBase : public DebugEpochBase {
|
||||
friend class SmallPtrSetIteratorImpl;
|
||||
|
||||
protected:
|
||||
/// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
|
||||
const void **SmallArray;
|
||||
/// CurArray - This is the current set of buckets. If equal to SmallArray,
|
||||
/// then the set is in 'small mode'.
|
||||
const void **CurArray;
|
||||
/// CurArraySize - The allocated size of CurArray, always a power of two.
|
||||
unsigned CurArraySize;
|
||||
|
||||
/// Number of elements in CurArray that contain a value or are a tombstone.
|
||||
/// If small, all these elements are at the beginning of CurArray and the rest
|
||||
/// is uninitialized.
|
||||
unsigned NumNonEmpty;
|
||||
/// Number of tombstones in CurArray.
|
||||
unsigned NumTombstones;
|
||||
|
||||
// Helpers to copy and move construct a SmallPtrSet.
|
||||
SmallPtrSetImplBase(const void **SmallStorage,
|
||||
const SmallPtrSetImplBase &that);
|
||||
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that);
|
||||
|
||||
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
|
||||
: SmallArray(SmallStorage), CurArray(SmallStorage),
|
||||
CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
|
||||
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
||||
"Initial size must be a power of two!");
|
||||
}
|
||||
|
||||
~SmallPtrSetImplBase() {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
}
|
||||
|
||||
public:
|
||||
using size_type = unsigned;
|
||||
|
||||
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
|
||||
|
||||
LLVM_NODISCARD bool empty() const { return size() == 0; }
|
||||
size_type size() const { return NumNonEmpty - NumTombstones; }
|
||||
|
||||
void clear() {
|
||||
incrementEpoch();
|
||||
// If the capacity of the array is huge, and the # elements used is small,
|
||||
// shrink the array.
|
||||
if (!isSmall()) {
|
||||
if (size() * 4 < CurArraySize && CurArraySize > 32)
|
||||
return shrink_and_clear();
|
||||
// Fill the array with empty markers.
|
||||
memset(CurArray, -1, CurArraySize * sizeof(void *));
|
||||
}
|
||||
|
||||
NumNonEmpty = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
|
||||
|
||||
static void *getEmptyMarker() {
|
||||
// Note that -1 is chosen to make clear() efficiently implementable with
|
||||
// memset and because it's not a valid pointer value.
|
||||
return reinterpret_cast<void*>(-1);
|
||||
}
|
||||
|
||||
const void **EndPointer() const {
|
||||
return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
|
||||
}
|
||||
|
||||
/// insert_imp - This returns true if the pointer was new to the set, false if
|
||||
/// it was already in the set. This is hidden from the client so that the
|
||||
/// derived class can check that the right type of pointer is passed in.
|
||||
std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
|
||||
if (isSmall()) {
|
||||
// Check to see if it is already in the set.
|
||||
const void **LastTombstone = nullptr;
|
||||
for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
|
||||
APtr != E; ++APtr) {
|
||||
const void *Value = *APtr;
|
||||
if (Value == Ptr)
|
||||
return std::make_pair(APtr, false);
|
||||
if (Value == getTombstoneMarker())
|
||||
LastTombstone = APtr;
|
||||
}
|
||||
|
||||
// Did we find any tombstone marker?
|
||||
if (LastTombstone != nullptr) {
|
||||
*LastTombstone = Ptr;
|
||||
--NumTombstones;
|
||||
incrementEpoch();
|
||||
return std::make_pair(LastTombstone, true);
|
||||
}
|
||||
|
||||
// Nope, there isn't. If we stay small, just 'pushback' now.
|
||||
if (NumNonEmpty < CurArraySize) {
|
||||
SmallArray[NumNonEmpty++] = Ptr;
|
||||
incrementEpoch();
|
||||
return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
|
||||
}
|
||||
// Otherwise, hit the big set case, which will call grow.
|
||||
}
|
||||
return insert_imp_big(Ptr);
|
||||
}
|
||||
|
||||
/// erase_imp - If the set contains the specified pointer, remove it and
|
||||
/// return true, otherwise return false. This is hidden from the client so
|
||||
/// that the derived class can check that the right type of pointer is passed
|
||||
/// in.
|
||||
bool erase_imp(const void * Ptr) {
|
||||
const void *const *P = find_imp(Ptr);
|
||||
if (P == EndPointer())
|
||||
return false;
|
||||
|
||||
const void **Loc = const_cast<const void **>(P);
|
||||
assert(*Loc == Ptr && "broken find!");
|
||||
*Loc = getTombstoneMarker();
|
||||
NumTombstones++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns the raw pointer needed to construct an iterator. If element not
|
||||
/// found, this will be EndPointer. Otherwise, it will be a pointer to the
|
||||
/// slot which stores Ptr;
|
||||
const void *const * find_imp(const void * Ptr) const {
|
||||
if (isSmall()) {
|
||||
// Linear search for the item.
|
||||
for (const void *const *APtr = SmallArray,
|
||||
*const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
|
||||
if (*APtr == Ptr)
|
||||
return APtr;
|
||||
return EndPointer();
|
||||
}
|
||||
|
||||
// Big set case.
|
||||
auto *Bucket = FindBucketFor(Ptr);
|
||||
if (*Bucket == Ptr)
|
||||
return Bucket;
|
||||
return EndPointer();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isSmall() const { return CurArray == SmallArray; }
|
||||
|
||||
std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
|
||||
|
||||
const void * const *FindBucketFor(const void *Ptr) const;
|
||||
void shrink_and_clear();
|
||||
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
void Grow(unsigned NewSize);
|
||||
|
||||
protected:
|
||||
/// swap - Swaps the elements of two sets.
|
||||
/// Note: This method assumes that both sets have the same small size.
|
||||
void swap(SmallPtrSetImplBase &RHS);
|
||||
|
||||
void CopyFrom(const SmallPtrSetImplBase &RHS);
|
||||
void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
|
||||
private:
|
||||
/// Code shared by MoveFrom() and move constructor.
|
||||
void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
/// Code shared by CopyFrom() and copy constructor.
|
||||
void CopyHelper(const SmallPtrSetImplBase &RHS);
|
||||
};
|
||||
|
||||
/// SmallPtrSetIteratorImpl - This is the common base class shared between all
|
||||
/// instances of SmallPtrSetIterator.
|
||||
class SmallPtrSetIteratorImpl {
|
||||
protected:
|
||||
const void *const *Bucket;
|
||||
const void *const *End;
|
||||
|
||||
public:
|
||||
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
|
||||
: Bucket(BP), End(E) {
|
||||
if (shouldReverseIterate()) {
|
||||
RetreatIfNotValid();
|
||||
return;
|
||||
}
|
||||
AdvanceIfNotValid();
|
||||
}
|
||||
|
||||
bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
|
||||
return Bucket == RHS.Bucket;
|
||||
}
|
||||
bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
|
||||
return Bucket != RHS.Bucket;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
|
||||
/// that is. This is guaranteed to stop because the end() bucket is marked
|
||||
/// valid.
|
||||
void AdvanceIfNotValid() {
|
||||
assert(Bucket <= End);
|
||||
while (Bucket != End &&
|
||||
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
|
||||
++Bucket;
|
||||
}
|
||||
void RetreatIfNotValid() {
|
||||
assert(Bucket >= End);
|
||||
while (Bucket != End &&
|
||||
(Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
|
||||
--Bucket;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
|
||||
template <typename PtrTy>
|
||||
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
|
||||
DebugEpochBase::HandleBase {
|
||||
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
|
||||
|
||||
public:
|
||||
using value_type = PtrTy;
|
||||
using reference = PtrTy;
|
||||
using pointer = PtrTy;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E,
|
||||
const DebugEpochBase &Epoch)
|
||||
: SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {}
|
||||
|
||||
// Most methods are provided by the base class.
|
||||
|
||||
const PtrTy operator*() const {
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
if (shouldReverseIterate()) {
|
||||
assert(Bucket > End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
|
||||
}
|
||||
assert(Bucket < End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
|
||||
}
|
||||
|
||||
inline SmallPtrSetIterator& operator++() { // Preincrement
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
if (shouldReverseIterate()) {
|
||||
--Bucket;
|
||||
RetreatIfNotValid();
|
||||
return *this;
|
||||
}
|
||||
++Bucket;
|
||||
AdvanceIfNotValid();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSetIterator operator++(int) { // Postincrement
|
||||
SmallPtrSetIterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next
|
||||
/// power of two (which means N itself if N is already a power of two).
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo;
|
||||
|
||||
/// RoundUpToPowerOfTwoH - If N is not a power of two, increase it. This is a
|
||||
/// helper template used to implement RoundUpToPowerOfTwo.
|
||||
template<unsigned N, bool isPowerTwo>
|
||||
struct RoundUpToPowerOfTwoH {
|
||||
enum { Val = N };
|
||||
};
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwoH<N, false> {
|
||||
enum {
|
||||
// We could just use NextVal = N+1, but this converges faster. N|(N-1) sets
|
||||
// the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
|
||||
Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val
|
||||
};
|
||||
};
|
||||
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo {
|
||||
enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
|
||||
};
|
||||
|
||||
/// A templated base class for \c SmallPtrSet which provides the
|
||||
/// typesafe interface that is common across all small sizes.
|
||||
///
|
||||
/// This is particularly useful for passing around between interface boundaries
|
||||
/// to avoid encoding a particular small size in the interface boundary.
|
||||
template <typename PtrType>
|
||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
|
||||
using PtrTraits = PointerLikeTypeTraits<PtrType>;
|
||||
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
|
||||
|
||||
protected:
|
||||
// Forward constructors to the base.
|
||||
using SmallPtrSetImplBase::SmallPtrSetImplBase;
|
||||
|
||||
public:
|
||||
using iterator = SmallPtrSetIterator<PtrType>;
|
||||
using const_iterator = SmallPtrSetIterator<PtrType>;
|
||||
using key_type = ConstPtrType;
|
||||
using value_type = PtrType;
|
||||
|
||||
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
|
||||
|
||||
/// Inserts Ptr if and only if there is no element in the container equal to
|
||||
/// Ptr. The bool component of the returned pair is true if and only if the
|
||||
/// insertion takes place, and the iterator component of the pair points to
|
||||
/// the element equal to Ptr.
|
||||
std::pair<iterator, bool> insert(PtrType Ptr) {
|
||||
auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
return std::make_pair(makeIterator(p.first), p.second);
|
||||
}
|
||||
|
||||
/// Insert the given pointer with an iterator hint that is ignored. This is
|
||||
/// identical to calling insert(Ptr), but allows SmallPtrSet to be used by
|
||||
/// std::insert_iterator and std::inserter().
|
||||
iterator insert(iterator, PtrType Ptr) {
|
||||
return insert(Ptr).first;
|
||||
}
|
||||
|
||||
/// erase - If the set contains the specified pointer, remove it and return
|
||||
/// true, otherwise return false.
|
||||
bool erase(PtrType Ptr) {
|
||||
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
}
|
||||
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
|
||||
size_type count(ConstPtrType Ptr) const {
|
||||
return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
|
||||
}
|
||||
iterator find(ConstPtrType Ptr) const {
|
||||
return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
|
||||
}
|
||||
bool contains(ConstPtrType Ptr) const {
|
||||
return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
void insert(IterT I, IterT E) {
|
||||
for (; I != E; ++I)
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<PtrType> IL) {
|
||||
insert(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
if (shouldReverseIterate())
|
||||
return makeIterator(EndPointer() - 1);
|
||||
return makeIterator(CurArray);
|
||||
}
|
||||
iterator end() const { return makeIterator(EndPointer()); }
|
||||
|
||||
private:
|
||||
/// Create an iterator that dereferences to same place as the given pointer.
|
||||
iterator makeIterator(const void *const *P) const {
|
||||
if (shouldReverseIterate())
|
||||
return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this);
|
||||
return iterator(P, EndPointer(), *this);
|
||||
}
|
||||
};
|
||||
|
||||
/// Equality comparison for SmallPtrSet.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each value from LHS is also in
|
||||
/// RHS, and that no additional values are in RHS.
|
||||
template <typename PtrType>
|
||||
bool operator==(const SmallPtrSetImpl<PtrType> &LHS,
|
||||
const SmallPtrSetImpl<PtrType> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (const auto *KV : LHS)
|
||||
if (!RHS.count(KV))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Inequality comparison for SmallPtrSet.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS).
|
||||
template <typename PtrType>
|
||||
bool operator!=(const SmallPtrSetImpl<PtrType> &LHS,
|
||||
const SmallPtrSetImpl<PtrType> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
/// SmallPtrSet - This class implements a set which is optimized for holding
|
||||
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
||||
/// power of two if it is not already a power of two. See the comments above
|
||||
/// SmallPtrSetImplBase for details of the algorithm.
|
||||
template<class PtrType, unsigned SmallSize>
|
||||
class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(SmallSize <= 32, "SmallSize should be small");
|
||||
|
||||
using BaseT = SmallPtrSetImpl<PtrType>;
|
||||
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||
/// SmallStorage - Fixed size storage used in 'small mode'.
|
||||
const void *SmallStorage[SmallSizePowTwo];
|
||||
|
||||
public:
|
||||
SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
|
||||
SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
|
||||
SmallPtrSet(SmallPtrSet &&that)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
|
||||
|
||||
template<typename It>
|
||||
SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(I, E);
|
||||
}
|
||||
|
||||
SmallPtrSet(std::initializer_list<PtrType> IL)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
if (&RHS != this)
|
||||
this->CopyFrom(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
|
||||
if (&RHS != this)
|
||||
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(std::initializer_list<PtrType> IL) {
|
||||
this->clear();
|
||||
this->insert(IL.begin(), IL.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap - Swaps the elements of two sets.
|
||||
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
SmallPtrSetImplBase::swap(RHS);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
namespace std {
|
||||
|
||||
/// Implement std::swap in terms of SmallPtrSet swap.
|
||||
template<class T, unsigned N>
|
||||
inline void swap(wpi::SmallPtrSet<T, N> &LHS, wpi::SmallPtrSet<T, N> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
|
||||
} // end namespace std
|
||||
|
||||
#endif // WPIUTIL_WPI_SMALLPTRSET_H
|
||||
285
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
vendored
Normal file
285
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallSet class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SMALLSET_H
|
||||
#define WPIUTIL_WPI_SMALLSET_H
|
||||
|
||||
#include "wpi/SmallPtrSet.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/type_traits.h"
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallSetIterator - This class implements a const_iterator for SmallSet by
|
||||
/// delegating to the underlying SmallVector or Set iterators.
|
||||
template <typename T, unsigned N, typename C>
|
||||
class SmallSetIterator
|
||||
: public iterator_facade_base<SmallSetIterator<T, N, C>,
|
||||
std::forward_iterator_tag, T> {
|
||||
private:
|
||||
using SetIterTy = typename std::set<T, C>::const_iterator;
|
||||
using VecIterTy = typename SmallVector<T, N>::const_iterator;
|
||||
using SelfTy = SmallSetIterator<T, N, C>;
|
||||
|
||||
/// Iterators to the parts of the SmallSet containing the data. They are set
|
||||
/// depending on isSmall.
|
||||
union {
|
||||
SetIterTy SetIter;
|
||||
VecIterTy VecIter;
|
||||
};
|
||||
|
||||
bool isSmall;
|
||||
|
||||
public:
|
||||
SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), isSmall(false) {}
|
||||
|
||||
SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), isSmall(true) {}
|
||||
|
||||
// Spell out destructor, copy/move constructor and assignment operators for
|
||||
// MSVC STL, where set<T>::const_iterator is not trivially copy constructible.
|
||||
~SmallSetIterator() {
|
||||
if (isSmall)
|
||||
VecIter.~VecIterTy();
|
||||
else
|
||||
SetIter.~SetIterTy();
|
||||
}
|
||||
|
||||
SmallSetIterator(const SmallSetIterator &Other) : isSmall(Other.isSmall) {
|
||||
if (isSmall)
|
||||
VecIter = Other.VecIter;
|
||||
else
|
||||
// Use placement new, to make sure SetIter is properly constructed, even
|
||||
// if it is not trivially copy-able (e.g. in MSVC).
|
||||
new (&SetIter) SetIterTy(Other.SetIter);
|
||||
}
|
||||
|
||||
SmallSetIterator(SmallSetIterator &&Other) : isSmall(Other.isSmall) {
|
||||
if (isSmall)
|
||||
VecIter = std::move(Other.VecIter);
|
||||
else
|
||||
// Use placement new, to make sure SetIter is properly constructed, even
|
||||
// if it is not trivially copy-able (e.g. in MSVC).
|
||||
new (&SetIter) SetIterTy(std::move(Other.SetIter));
|
||||
}
|
||||
|
||||
SmallSetIterator& operator=(const SmallSetIterator& Other) {
|
||||
// Call destructor for SetIter, so it gets properly destroyed if it is
|
||||
// not trivially destructible in case we are setting VecIter.
|
||||
if (!isSmall)
|
||||
SetIter.~SetIterTy();
|
||||
|
||||
isSmall = Other.isSmall;
|
||||
if (isSmall)
|
||||
VecIter = Other.VecIter;
|
||||
else
|
||||
new (&SetIter) SetIterTy(Other.SetIter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallSetIterator& operator=(SmallSetIterator&& Other) {
|
||||
// Call destructor for SetIter, so it gets properly destroyed if it is
|
||||
// not trivially destructible in case we are setting VecIter.
|
||||
if (!isSmall)
|
||||
SetIter.~SetIterTy();
|
||||
|
||||
isSmall = Other.isSmall;
|
||||
if (isSmall)
|
||||
VecIter = std::move(Other.VecIter);
|
||||
else
|
||||
new (&SetIter) SetIterTy(std::move(Other.SetIter));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const SmallSetIterator &RHS) const {
|
||||
if (isSmall != RHS.isSmall)
|
||||
return false;
|
||||
if (isSmall)
|
||||
return VecIter == RHS.VecIter;
|
||||
return SetIter == RHS.SetIter;
|
||||
}
|
||||
|
||||
SmallSetIterator &operator++() { // Preincrement
|
||||
if (isSmall)
|
||||
VecIter++;
|
||||
else
|
||||
SetIter++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T &operator*() const { return isSmall ? *VecIter : *SetIter; }
|
||||
};
|
||||
|
||||
/// SmallSet - This maintains a set of unique values, optimizing for the case
|
||||
/// when the set is small (less than N). In this case, the set can be
|
||||
/// maintained with no mallocs. If the set gets large, we expand to using an
|
||||
/// std::set to maintain reasonable lookup times.
|
||||
template <typename T, unsigned N, typename C = std::less<T>>
|
||||
class SmallSet {
|
||||
/// Use a SmallVector to hold the elements here (even though it will never
|
||||
/// reach its 'large' stage) to avoid calling the default ctors of elements
|
||||
/// we will never use.
|
||||
SmallVector<T, N> Vector;
|
||||
std::set<T, C> Set;
|
||||
|
||||
using VIterator = typename SmallVector<T, N>::const_iterator;
|
||||
using mutable_iterator = typename SmallVector<T, N>::iterator;
|
||||
|
||||
// In small mode SmallPtrSet uses linear search for the elements, so it is
|
||||
// not a good idea to choose this value too high. You may consider using a
|
||||
// DenseSet<> instead if you expect many elements in the set.
|
||||
static_assert(N <= 32, "N should be small");
|
||||
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using const_iterator = SmallSetIterator<T, N, C>;
|
||||
|
||||
SmallSet() = default;
|
||||
|
||||
LLVM_NODISCARD bool empty() const {
|
||||
return Vector.empty() && Set.empty();
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return isSmall() ? Vector.size() : Set.size();
|
||||
}
|
||||
|
||||
/// count - Return 1 if the element is in the set, 0 otherwise.
|
||||
size_type count(const T &V) const {
|
||||
if (isSmall()) {
|
||||
// Since the collection is small, just do a linear search.
|
||||
return vfind(V) == Vector.end() ? 0 : 1;
|
||||
} else {
|
||||
return Set.count(V);
|
||||
}
|
||||
}
|
||||
|
||||
/// insert - Insert an element into the set if it isn't already there.
|
||||
/// Returns true if the element is inserted (it was not in the set before).
|
||||
/// The first value of the returned pair is unused and provided for
|
||||
/// partial compatibility with the standard library self-associative container
|
||||
/// concept.
|
||||
// FIXME: Add iterators that abstract over the small and large form, and then
|
||||
// return those here.
|
||||
std::pair<std::nullopt_t, bool> insert(const T &V) {
|
||||
if (!isSmall())
|
||||
return std::make_pair(std::nullopt, Set.insert(V).second);
|
||||
|
||||
VIterator I = vfind(V);
|
||||
if (I != Vector.end()) // Don't reinsert if it already exists.
|
||||
return std::make_pair(std::nullopt, false);
|
||||
if (Vector.size() < N) {
|
||||
Vector.push_back(V);
|
||||
return std::make_pair(std::nullopt, true);
|
||||
}
|
||||
|
||||
// Otherwise, grow from vector to set.
|
||||
while (!Vector.empty()) {
|
||||
Set.insert(Vector.back());
|
||||
Vector.pop_back();
|
||||
}
|
||||
Set.insert(V);
|
||||
return std::make_pair(std::nullopt, true);
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
void insert(IterT I, IterT E) {
|
||||
for (; I != E; ++I)
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
bool erase(const T &V) {
|
||||
if (!isSmall())
|
||||
return Set.erase(V);
|
||||
for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
|
||||
if (*I == V) {
|
||||
Vector.erase(I);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Vector.clear();
|
||||
Set.clear();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (isSmall())
|
||||
return {Vector.begin()};
|
||||
return {Set.begin()};
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
if (isSmall())
|
||||
return {Vector.end()};
|
||||
return {Set.end()};
|
||||
}
|
||||
|
||||
/// Check if the SmallSet contains the given element.
|
||||
bool contains(const T &V) const {
|
||||
if (isSmall())
|
||||
return vfind(V) != Vector.end();
|
||||
return Set.find(V) != Set.end();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isSmall() const { return Set.empty(); }
|
||||
|
||||
VIterator vfind(const T &V) const {
|
||||
for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
|
||||
if (*I == V)
|
||||
return I;
|
||||
return Vector.end();
|
||||
}
|
||||
};
|
||||
|
||||
/// If this set is of pointer values, transparently switch over to using
|
||||
/// SmallPtrSet for performance.
|
||||
template <typename PointeeType, unsigned N>
|
||||
class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
|
||||
|
||||
/// Equality comparison for SmallSet.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each element is also a member
|
||||
/// of RHS, and that RHS contains no additional values.
|
||||
/// Equivalent to N calls to RHS.count.
|
||||
/// For small-set mode amortized complexity is O(N^2)
|
||||
/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
|
||||
/// every hash collides).
|
||||
template <typename T, unsigned LN, unsigned RN, typename C>
|
||||
bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
// All elements in LHS must also be in RHS
|
||||
return std::all_of(LHS.begin(), LHS.end(), [&RHS](const T &E) { return RHS.count(E); });
|
||||
}
|
||||
|
||||
/// Inequality comparison for SmallSet.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
|
||||
template <typename T, unsigned LN, unsigned RN, typename C>
|
||||
bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_SMALLSET_H
|
||||
215
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallString.h
vendored
Normal file
215
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallString.h
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallString class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SMALLSTRING_H
|
||||
#define WPIUTIL_WPI_SMALLSTRING_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallString - A SmallString is just a SmallVector with methods and accessors
|
||||
/// that make it work better as a string (e.g. operator+ etc).
|
||||
template<unsigned InternalLen>
|
||||
class SmallString : public SmallVector<char, InternalLen> {
|
||||
public:
|
||||
/// Default ctor - Initialize to empty.
|
||||
SmallString() = default;
|
||||
|
||||
/// Initialize from a std::string_view.
|
||||
SmallString(std::string_view S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
|
||||
|
||||
/// Initialize by concatenating a list of std::string_views.
|
||||
SmallString(std::initializer_list<std::string_view> Refs)
|
||||
: SmallVector<char, InternalLen>() {
|
||||
this->append(Refs);
|
||||
}
|
||||
|
||||
/// Initialize with a range.
|
||||
template<typename ItTy>
|
||||
SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
|
||||
|
||||
/// @}
|
||||
/// @name String Assignment
|
||||
/// @{
|
||||
|
||||
using SmallVector<char, InternalLen>::assign;
|
||||
|
||||
/// Assign from a std::string_view.
|
||||
void assign(std::string_view RHS) {
|
||||
SmallVectorImpl<char>::assign(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// Assign from a list of std::string_views.
|
||||
void assign(std::initializer_list<std::string_view> Refs) {
|
||||
this->clear();
|
||||
append(Refs);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Concatenation
|
||||
/// @{
|
||||
|
||||
using SmallVector<char, InternalLen>::append;
|
||||
|
||||
/// Append from a std::string_view.
|
||||
void append(std::string_view RHS) {
|
||||
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
|
||||
}
|
||||
|
||||
/// Append from a list of std::string_views.
|
||||
void append(std::initializer_list<std::string_view> Refs) {
|
||||
size_t SizeNeeded = this->size();
|
||||
for (std::string_view Ref : Refs)
|
||||
SizeNeeded += Ref.size();
|
||||
this->reserve(SizeNeeded);
|
||||
auto CurEnd = this->end();
|
||||
for (std::string_view Ref : Refs) {
|
||||
this->uninitialized_copy(Ref.begin(), Ref.end(), CurEnd);
|
||||
CurEnd += Ref.size();
|
||||
}
|
||||
this->set_size(SizeNeeded);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Comparison
|
||||
/// @{
|
||||
|
||||
/// Compare two strings; the result is -1, 0, or 1 if this string is
|
||||
/// lexicographically less than, equal to, or greater than the \p RHS.
|
||||
int compare(std::string_view RHS) const {
|
||||
return str().compare(RHS);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name String Searching
|
||||
/// @{
|
||||
|
||||
/// find - Search for the first character \p C in the string.
|
||||
///
|
||||
/// \return - The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t find(char C, size_t From = 0) const {
|
||||
return str().find(C, From);
|
||||
}
|
||||
|
||||
/// Search for the first string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the first occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t find(std::string_view Str, size_t From = 0) const {
|
||||
return str().find(Str, From);
|
||||
}
|
||||
|
||||
/// Search for the last character \p C in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t rfind(char C, size_t From = std::string_view::npos) const {
|
||||
return str().rfind(C, From);
|
||||
}
|
||||
|
||||
/// Search for the last string \p Str in the string.
|
||||
///
|
||||
/// \returns The index of the last occurrence of \p Str, or npos if not
|
||||
/// found.
|
||||
size_t rfind(std::string_view Str) const {
|
||||
return str().rfind(Str);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is \p C, or npos if not
|
||||
/// found. Same as find.
|
||||
size_t find_first_of(char C, size_t From = 0) const {
|
||||
return str().find_first_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is in \p Chars, or npos if
|
||||
/// not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_of(std::string_view Chars, size_t From = 0) const {
|
||||
return str().find_first_of(Chars, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is not \p C or npos if not
|
||||
/// found.
|
||||
size_t find_first_not_of(char C, size_t From = 0) const {
|
||||
return str().find_first_not_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the first character in the string that is not in the string
|
||||
/// \p Chars, or npos if not found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_first_not_of(std::string_view Chars, size_t From = 0) const {
|
||||
return str().find_first_not_of(Chars, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is \p C, or npos if not
|
||||
/// found.
|
||||
size_t find_last_of(char C, size_t From = std::string_view::npos) const {
|
||||
return str().find_last_of(C, From);
|
||||
}
|
||||
|
||||
/// Find the last character in the string that is in \p C, or npos if not
|
||||
/// found.
|
||||
///
|
||||
/// Complexity: O(size() + Chars.size())
|
||||
size_t find_last_of(
|
||||
std::string_view Chars, size_t From = std::string_view::npos) const {
|
||||
return str().find_last_of(Chars, From);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// Extra methods.
|
||||
|
||||
/// Explicit conversion to std::string_view.
|
||||
std::string_view str() const { return std::string_view(this->begin(), this->size()); }
|
||||
|
||||
// TODO: Make this const, if it's safe...
|
||||
const char* c_str() {
|
||||
this->push_back(0);
|
||||
this->pop_back();
|
||||
return this->data();
|
||||
}
|
||||
|
||||
/// Implicit conversion to std::string_view.
|
||||
operator std::string_view() const { return str(); }
|
||||
|
||||
/// Explicit conversion to std::string.
|
||||
std::string string() const { return {this->begin(), this->size()}; }
|
||||
|
||||
/// Implicit conversion to std::string.
|
||||
operator std::string() const { return string(); }
|
||||
|
||||
// Extra operators.
|
||||
SmallString &operator=(std::string_view RHS) {
|
||||
this->assign(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallString &operator+=(std::string_view RHS) {
|
||||
this->append(RHS.begin(), RHS.end());
|
||||
return *this;
|
||||
}
|
||||
SmallString &operator+=(char C) {
|
||||
this->push_back(C);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_SMALLSTRING_H
|
||||
1276
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
vendored
Normal file
1276
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVectorMemoryBuffer.h
vendored
Normal file
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVectorMemoryBuffer.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
//===- SmallVectorMemoryBuffer.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares a wrapper class to hold the memory into which an
|
||||
// object will be generated.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "wpi/MemoryBuffer.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// SmallVector-backed MemoryBuffer instance.
|
||||
///
|
||||
/// This class enables efficient construction of MemoryBuffers from SmallVector
|
||||
/// instances.
|
||||
class SmallVectorMemoryBuffer : public MemoryBuffer {
|
||||
public:
|
||||
/// Construct an SmallVectorMemoryBuffer from the given SmallVector
|
||||
/// r-value.
|
||||
SmallVectorMemoryBuffer(SmallVectorImpl<uint8_t>&& sv) // NOLINT
|
||||
: m_sv(std::move(sv)), m_bufferName("<in-memory object>") {
|
||||
Init(this->m_sv.begin(), this->m_sv.end());
|
||||
}
|
||||
|
||||
/// Construct a named SmallVectorMemoryBuffer from the given
|
||||
/// SmallVector r-value and StringRef.
|
||||
SmallVectorMemoryBuffer(SmallVectorImpl<uint8_t>&& sv, std::string_view name)
|
||||
: m_sv(std::move(sv)), m_bufferName(name) {
|
||||
Init(this->m_sv.begin(), this->m_sv.end());
|
||||
}
|
||||
|
||||
// Key function.
|
||||
~SmallVectorMemoryBuffer() override;
|
||||
|
||||
std::string_view GetBufferIdentifier() const override { return m_bufferName; }
|
||||
|
||||
BufferKind GetBufferKind() const override { return MemoryBuffer_Malloc; }
|
||||
|
||||
private:
|
||||
SmallVector<uint8_t, 0> m_sv;
|
||||
std::string m_bufferName;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
712
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
vendored
Normal file
712
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
vendored
Normal file
@@ -0,0 +1,712 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
//===- llvm/ADT/StringExtras.h - Useful string functions --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some functions that are useful when dealing with strings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
|
||||
/// hexdigit - Return the hexadecimal character for the
|
||||
/// given number \p X (which should be less than 16).
|
||||
constexpr char hexdigit(unsigned X, bool LowerCase = false) noexcept {
|
||||
const char HexChar = LowerCase ? 'a' : 'A';
|
||||
return X < 10 ? '0' + X : HexChar + X - 10;
|
||||
}
|
||||
|
||||
/// Interpret the given character \p C as a hexadecimal digit and return its
|
||||
/// value.
|
||||
///
|
||||
/// If \p C is not a valid hex digit, -1U is returned.
|
||||
constexpr unsigned hexDigitValue(char C) noexcept {
|
||||
if (C >= '0' && C <= '9') {
|
||||
return C - '0';
|
||||
}
|
||||
if (C >= 'a' && C <= 'f') {
|
||||
return C - 'a' + 10U;
|
||||
}
|
||||
if (C >= 'A' && C <= 'F') {
|
||||
return C - 'A' + 10U;
|
||||
}
|
||||
return (std::numeric_limits<unsigned>::max)();
|
||||
}
|
||||
|
||||
/// Checks if character \p C is one of the 10 decimal digits.
|
||||
constexpr bool isDigit(char C) noexcept {
|
||||
return C >= '0' && C <= '9';
|
||||
}
|
||||
|
||||
/// Checks if character \p C is a hexadecimal numeric character.
|
||||
constexpr bool isHexDigit(char C) noexcept {
|
||||
return hexDigitValue(C) != (std::numeric_limits<unsigned>::max)();
|
||||
}
|
||||
|
||||
/// Checks if character \p C is a valid letter as classified by "C" locale.
|
||||
constexpr bool isAlpha(char C) noexcept {
|
||||
return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z');
|
||||
}
|
||||
|
||||
/// Checks whether character \p C is either a decimal digit or an uppercase or
|
||||
/// lowercase letter as classified by "C" locale.
|
||||
constexpr bool isAlnum(char C) noexcept {
|
||||
return isAlpha(C) || isDigit(C);
|
||||
}
|
||||
|
||||
/// Checks whether character \p C is valid ASCII (high bit is zero).
|
||||
constexpr bool isASCII(char C) noexcept {
|
||||
return static_cast<unsigned char>(C) <= 127;
|
||||
}
|
||||
|
||||
/// Checks whether character \p C is printable.
|
||||
///
|
||||
/// Locale-independent version of the C standard library isprint whose results
|
||||
/// may differ on different platforms.
|
||||
constexpr bool isPrint(char C) noexcept {
|
||||
unsigned char UC = static_cast<unsigned char>(C);
|
||||
return (0x20 <= UC) && (UC <= 0x7E);
|
||||
}
|
||||
|
||||
/// Returns the corresponding lowercase character if \p x is uppercase.
|
||||
constexpr char toLower(char x) noexcept {
|
||||
if (x >= 'A' && x <= 'Z') {
|
||||
return x - 'A' + 'a';
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/// Returns the corresponding uppercase character if \p x is lowercase.
|
||||
constexpr char toUpper(char x) noexcept {
|
||||
if (x >= 'a' && x <= 'z') {
|
||||
return x - 'a' + 'A';
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline std::string utohexstr(unsigned long long val, // NOLINT(runtime/int)
|
||||
bool lowerCase = false) {
|
||||
char buf[17];
|
||||
char* bufptr = std::end(buf);
|
||||
|
||||
if (val == 0) {
|
||||
*--bufptr = '0';
|
||||
}
|
||||
|
||||
while (val) {
|
||||
unsigned char mod = static_cast<unsigned char>(val) & 15;
|
||||
*--bufptr = hexdigit(mod, lowerCase);
|
||||
val >>= 4;
|
||||
}
|
||||
|
||||
return std::string(bufptr, std::end(buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* equals - Check for string equality, this is more efficient than
|
||||
* compare() when the relative ordering of inequal strings isn't needed.
|
||||
*/
|
||||
constexpr bool equals(std::string_view lhs, std::string_view rhs) noexcept {
|
||||
auto length = lhs.size();
|
||||
return length == rhs.size() && std::string_view::traits_type::compare(
|
||||
lhs.data(), rhs.data(), length) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare_lower - Compare two strings, ignoring case.
|
||||
*/
|
||||
int compare_lower(std::string_view lhs, std::string_view rhs) noexcept;
|
||||
|
||||
/**
|
||||
* equals_lower - Check for string equality, ignoring case.
|
||||
*/
|
||||
constexpr bool equals_lower(std::string_view lhs,
|
||||
std::string_view rhs) noexcept {
|
||||
return lhs.size() == rhs.size() && compare_lower(lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first character @p ch in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the first occurrence of @p ch, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type find_lower(
|
||||
std::string_view str, char ch,
|
||||
std::string_view::size_type from = 0) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the first string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the first occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type find_lower(
|
||||
std::string_view str, std::string_view other,
|
||||
std::string_view::size_type from = 0) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the first string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the first occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
inline std::string_view::size_type find_lower(
|
||||
std::string_view str, const char* other,
|
||||
std::string_view::size_type from = 0) noexcept {
|
||||
return find_lower(str, std::string_view{other}, from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the last character @p ch in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the last occurrence of @p ch, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type rfind_lower(
|
||||
std::string_view str, char ch,
|
||||
std::string_view::size_type from = std::string_view::npos) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the last string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the last occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
std::string_view::size_type rfind_lower(std::string_view str,
|
||||
std::string_view other) noexcept;
|
||||
|
||||
/**
|
||||
* Search for the last string @p other in @p str, ignoring case.
|
||||
*
|
||||
* @returns The index of the last occurrence of @p other, or npos if not
|
||||
* found.
|
||||
*/
|
||||
inline std::string_view::size_type rfind_lower(std::string_view str,
|
||||
const char* other) noexcept {
|
||||
return rfind_lower(str, std::string_view{other});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the substring of @p str from [start, start + n).
|
||||
*
|
||||
* @param start The index of the starting character in the substring; if
|
||||
* the index is npos or greater than the length of the string then the
|
||||
* empty substring will be returned.
|
||||
*
|
||||
* @param n The number of characters to included in the substring. If n
|
||||
* exceeds the number of characters remaining in the string, the string
|
||||
* suffix (starting with @p start) will be returned.
|
||||
*/
|
||||
constexpr std::string_view substr(
|
||||
std::string_view str, std::string_view::size_type start,
|
||||
std::string_view::size_type n = std::string_view::npos) noexcept {
|
||||
auto length = str.size();
|
||||
start = (std::min)(start, length);
|
||||
return {str.data() + start, (std::min)(n, length - start)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix.
|
||||
*/
|
||||
constexpr bool starts_with(std::string_view str,
|
||||
std::string_view prefix) noexcept {
|
||||
return substr(str, 0, prefix.size()) == prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix.
|
||||
*/
|
||||
constexpr bool starts_with(std::string_view str, char prefix) noexcept {
|
||||
return !str.empty() && std::string_view::traits_type::eq(str.front(), prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix.
|
||||
*/
|
||||
constexpr bool starts_with(std::string_view str, const char* prefix) noexcept {
|
||||
return starts_with(str, std::string_view(prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix, ignoring case.
|
||||
*/
|
||||
bool starts_with_lower(std::string_view str, std::string_view prefix) noexcept;
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix, ignoring case.
|
||||
*/
|
||||
constexpr bool starts_with_lower(std::string_view str, char prefix) noexcept {
|
||||
return !str.empty() && toLower(str.front()) == toLower(prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str starts with the given @p prefix, ignoring case.
|
||||
*/
|
||||
inline bool starts_with_lower(std::string_view str,
|
||||
const char* prefix) noexcept {
|
||||
return starts_with_lower(str, std::string_view(prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix.
|
||||
*/
|
||||
constexpr bool ends_with(std::string_view str,
|
||||
std::string_view suffix) noexcept {
|
||||
return str.size() >= suffix.size() &&
|
||||
str.compare(str.size() - suffix.size(), std::string_view::npos,
|
||||
suffix) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix.
|
||||
*/
|
||||
constexpr bool ends_with(std::string_view str, char suffix) noexcept {
|
||||
return !str.empty() && std::string_view::traits_type::eq(str.back(), suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix.
|
||||
*/
|
||||
constexpr bool ends_with(std::string_view str, const char* suffix) noexcept {
|
||||
return ends_with(str, std::string_view(suffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix, ignoring case.
|
||||
*/
|
||||
bool ends_with_lower(std::string_view str, std::string_view suffix) noexcept;
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix, ignoring case.
|
||||
*/
|
||||
constexpr bool ends_with_lower(std::string_view str, char suffix) noexcept {
|
||||
return !str.empty() && toLower(str.back()) == toLower(suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str ends with the given @p suffix, ignoring case.
|
||||
*/
|
||||
inline bool ends_with_lower(std::string_view str, const char* suffix) noexcept {
|
||||
return ends_with_lower(str, std::string_view(suffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other.
|
||||
*/
|
||||
constexpr bool contains(std::string_view str, std::string_view other) noexcept {
|
||||
return str.find(other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other.
|
||||
*/
|
||||
constexpr bool contains(std::string_view str, char ch) noexcept {
|
||||
return str.find(ch) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other.
|
||||
*/
|
||||
constexpr bool contains(std::string_view str, const char* other) noexcept {
|
||||
return str.find(other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other, ignoring case.
|
||||
*/
|
||||
inline bool contains_lower(std::string_view str,
|
||||
std::string_view other) noexcept {
|
||||
return find_lower(str, other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other, ignoring case.
|
||||
*/
|
||||
inline bool contains_lower(std::string_view str, char ch) noexcept {
|
||||
return find_lower(str, ch) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if @p str contains the substring @p other, ignoring case.
|
||||
*/
|
||||
inline bool contains_lower(std::string_view str, const char* other) noexcept {
|
||||
return find_lower(str, other) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string_view equal to @p str but with the first @p n elements
|
||||
* dropped.
|
||||
*/
|
||||
constexpr std::string_view drop_front(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
str.remove_prefix(n);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string_view equal to @p str but with the last @p n elements dropped.
|
||||
*/
|
||||
constexpr std::string_view drop_back(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
str.remove_suffix(n);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view equal to @p str but with only the first @p n
|
||||
* elements remaining. If @p n is greater than the length of the
|
||||
* string, the entire string is returned.
|
||||
*/
|
||||
constexpr std::string_view take_front(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
auto length = str.size();
|
||||
if (n >= length) {
|
||||
return str;
|
||||
}
|
||||
return drop_back(str, length - n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view equal to @p str but with only the last @p n
|
||||
* elements remaining. If @p n is greater than the length of the
|
||||
* string, the entire string is returned.
|
||||
*/
|
||||
constexpr std::string_view take_back(
|
||||
std::string_view str, std::string_view::size_type n = 1) noexcept {
|
||||
auto length = str.size();
|
||||
if (n >= length) {
|
||||
return str;
|
||||
}
|
||||
return drop_front(str, length - n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the substring of @p str from [start, end).
|
||||
*
|
||||
* @param start The index of the starting character in the substring; if
|
||||
* the index is npos or greater than the length of the string then the
|
||||
* empty substring will be returned.
|
||||
*
|
||||
* @param end The index following the last character to include in the
|
||||
* substring. If this is npos or exceeds the number of characters
|
||||
* remaining in the string, the string suffix (starting with @p start)
|
||||
* will be returned. If this is less than @p start, an empty string will
|
||||
* be returned.
|
||||
*/
|
||||
constexpr std::string_view slice(std::string_view str,
|
||||
std::string_view::size_type start,
|
||||
std::string_view::size_type end) noexcept {
|
||||
auto length = str.size();
|
||||
start = (std::min)(start, length);
|
||||
end = (std::min)((std::max)(start, end), length);
|
||||
return {str.data() + start, end - start};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the first occurrence of a separator
|
||||
* character.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* maximal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The character to split on.
|
||||
* @returns The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> split(
|
||||
std::string_view str, char separator) noexcept {
|
||||
auto idx = str.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx), slice(str, idx + 1, std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the first occurrence of a separator
|
||||
* string.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* maximal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The string to split on.
|
||||
* @return The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> split(
|
||||
std::string_view str, std::string_view separator) noexcept {
|
||||
auto idx = str.find(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx),
|
||||
slice(str, idx + separator.size(), std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the last occurrence of a separator
|
||||
* character.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* minimal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The string to split on.
|
||||
* @return The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> rsplit(
|
||||
std::string_view str, char separator) noexcept {
|
||||
auto idx = str.rfind(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx), slice(str, idx + 1, std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into two substrings around the last occurrence of a separator
|
||||
* string.
|
||||
*
|
||||
* If @p separator is in the string, then the result is a pair (LHS, RHS)
|
||||
* such that (str == LHS + separator + RHS) is true and RHS is
|
||||
* minimal. If @p separator is not in the string, then the result is a
|
||||
* pair (LHS, RHS) where (str == LHS) and (RHS == "").
|
||||
*
|
||||
* @param separator The string to split on.
|
||||
* @return The split substrings.
|
||||
*/
|
||||
constexpr std::pair<std::string_view, std::string_view> rsplit(
|
||||
std::string_view str, std::string_view separator) noexcept {
|
||||
auto idx = str.rfind(separator);
|
||||
if (idx == std::string_view::npos) {
|
||||
return {str, {}};
|
||||
}
|
||||
return {slice(str, 0, idx),
|
||||
slice(str, idx + separator.size(), std::string_view::npos)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits @p str into substrings around the occurrences of a separator string.
|
||||
*
|
||||
* Each substring is stored in @p arr. If @p maxSplit is >= 0, at most
|
||||
* @p maxSplit splits are done and consequently <= @p maxSplit + 1
|
||||
* elements are added to arr.
|
||||
* If @p keepEmpty is false, empty strings are not added to @p arr. They
|
||||
* still count when considering @p maxSplit
|
||||
* An useful invariant is that
|
||||
* separator.join(arr) == str if maxSplit == -1 and keepEmpty == true
|
||||
*
|
||||
* @param arr Where to put the substrings.
|
||||
* @param separator The string to split on.
|
||||
* @param maxSplit The maximum number of times the string is split.
|
||||
* @param keepEmpty True if empty substring should be added.
|
||||
*/
|
||||
void split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
std::string_view separator, int maxSplit = -1,
|
||||
bool keepEmpty = true) noexcept;
|
||||
|
||||
/**
|
||||
* Splits @p str into substrings around the occurrences of a separator
|
||||
* character.
|
||||
*
|
||||
* Each substring is stored in @p arr. If @p maxSplit is >= 0, at most
|
||||
* @p maxSplit splits are done and consequently <= @p maxSplit + 1
|
||||
* elements are added to arr.
|
||||
* If @p keepEmpty is false, empty strings are not added to @p arr. They
|
||||
* still count when considering @p maxSplit
|
||||
* An useful invariant is that
|
||||
* separator.join(arr) == str if maxSplit == -1 and keepEmpty == true
|
||||
*
|
||||
* @param arr Where to put the substrings.
|
||||
* @param separator The character to split on.
|
||||
* @param maxSplit The maximum number of times the string is split.
|
||||
* @param keepEmpty True if empty substring should be added.
|
||||
*/
|
||||
void split(std::string_view str, SmallVectorImpl<std::string_view>& arr,
|
||||
char separator, int maxSplit = -1, bool keepEmpty = true) noexcept;
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive @p ch characters starting from the
|
||||
* the left removed.
|
||||
*/
|
||||
constexpr std::string_view ltrim(std::string_view str, char ch) noexcept {
|
||||
return drop_front(str, (std::min)(str.size(), str.find_first_not_of(ch)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive characters in @p chars starting from
|
||||
* the left removed.
|
||||
*/
|
||||
constexpr std::string_view ltrim(
|
||||
std::string_view str, std::string_view chars = " \t\n\v\f\r") noexcept {
|
||||
return drop_front(str, (std::min)(str.size(), str.find_first_not_of(chars)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive @p Char characters starting from the
|
||||
* right removed.
|
||||
*/
|
||||
constexpr std::string_view rtrim(std::string_view str, char ch) noexcept {
|
||||
return drop_back(
|
||||
str, str.size() - (std::min)(str.size(), str.find_last_not_of(ch) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive characters in @p chars starting from
|
||||
* the right removed.
|
||||
*/
|
||||
constexpr std::string_view rtrim(
|
||||
std::string_view str, std::string_view chars = " \t\n\v\f\r") noexcept {
|
||||
return drop_back(
|
||||
str,
|
||||
str.size() - (std::min)(str.size(), str.find_last_not_of(chars) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive @p ch characters starting from the
|
||||
* left and right removed.
|
||||
*/
|
||||
constexpr std::string_view trim(std::string_view str, char ch) noexcept {
|
||||
return rtrim(ltrim(str, ch), ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns @p str with consecutive characters in @p chars starting from
|
||||
* the left and right removed.
|
||||
*/
|
||||
constexpr std::string_view trim(
|
||||
std::string_view str, std::string_view chars = " \t\n\v\f\r") noexcept {
|
||||
return rtrim(ltrim(str, chars), chars);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
bool GetAsUnsignedInteger(
|
||||
std::string_view str, unsigned radix,
|
||||
unsigned long long& result) noexcept; // NOLINT(runtime/int)
|
||||
bool GetAsSignedInteger(std::string_view str, unsigned radix,
|
||||
long long& result) noexcept; // NOLINT(runtime/int)
|
||||
|
||||
bool ConsumeUnsignedInteger(
|
||||
std::string_view& str, unsigned radix,
|
||||
unsigned long long& result) noexcept; // NOLINT(runtime/int)
|
||||
bool ConsumeSignedInteger(std::string_view& str, unsigned radix,
|
||||
long long& result) noexcept; // NOLINT(runtime/int)
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Parses the string @p str as an integer of the specified radix. If
|
||||
* @p radix is specified as zero, this does radix autosensing using
|
||||
* extended C rules: 0 is octal, 0x is hex, 0b is binary.
|
||||
*
|
||||
* If the string is invalid or if only a subset of the string is valid,
|
||||
* this returns nullopt to signify the error. The string is considered
|
||||
* erroneous if empty or if it overflows T.
|
||||
*/
|
||||
template <typename T,
|
||||
std::enable_if_t<std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> parse_integer(std::string_view str,
|
||||
unsigned radix) noexcept {
|
||||
long long val; // NOLINT(runtime/int)
|
||||
if (detail::GetAsSignedInteger(str, radix, val) ||
|
||||
static_cast<T>(val) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> parse_integer(std::string_view str,
|
||||
unsigned radix) noexcept {
|
||||
using Int = unsigned long long; // NOLINT(runtime/int)
|
||||
Int val;
|
||||
// The additional cast to unsigned long long is required to avoid the
|
||||
// Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type
|
||||
// 'unsigned __int64' when instantiating getAsInteger with T = bool.
|
||||
if (detail::GetAsUnsignedInteger(str, radix, val) ||
|
||||
static_cast<Int>(static_cast<T>(val)) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string @p str as an integer of the specified radix. If
|
||||
* @p radix is specified as zero, this does radix autosensing using
|
||||
* extended C rules: 0 is octal, 0x is hex, 0b is binary.
|
||||
*
|
||||
* If the string does not begin with a number of the specified radix,
|
||||
* this returns nullopt to signify the error. The string is considered
|
||||
* erroneous if empty or if it overflows T.
|
||||
* The portion of the string representing the discovered numeric value
|
||||
* is removed from the beginning of the string.
|
||||
*/
|
||||
template <typename T,
|
||||
std::enable_if_t<std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> consume_integer(std::string_view* str,
|
||||
unsigned radix) noexcept {
|
||||
using Int = long long; // NOLINT(runtime/int)
|
||||
Int val;
|
||||
if (detail::ConsumeSignedInteger(*str, radix, val) ||
|
||||
static_cast<Int>(static_cast<T>(val)) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::numeric_limits<T>::is_signed, bool> = true>
|
||||
inline std::optional<T> consume_integer(std::string_view* str,
|
||||
unsigned radix) noexcept {
|
||||
using Int = unsigned long long; // NOLINT(runtime/int)
|
||||
Int val;
|
||||
if (detail::ConsumeUnsignedInteger(*str, radix, val) ||
|
||||
static_cast<Int>(static_cast<T>(val)) != val) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string @p str as a floating point value.
|
||||
*
|
||||
* If the string is invalid or if only a subset of the string is valid,
|
||||
* this returns nullopt to signify the error. The string is considered
|
||||
* erroneous if empty or if it overflows T.
|
||||
*/
|
||||
template <typename T>
|
||||
std::optional<T> parse_float(std::string_view str) noexcept;
|
||||
|
||||
template <>
|
||||
std::optional<float> parse_float<float>(std::string_view str) noexcept;
|
||||
template <>
|
||||
std::optional<double> parse_float<double>(std::string_view str) noexcept;
|
||||
template <>
|
||||
std::optional<long double> parse_float<long double>(
|
||||
std::string_view str) noexcept;
|
||||
|
||||
} // namespace wpi
|
||||
584
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
vendored
Normal file
584
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
vendored
Normal file
@@ -0,0 +1,584 @@
|
||||
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the StringMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STRINGMAP_H
|
||||
#define WPIUTIL_WPI_STRINGMAP_H
|
||||
|
||||
#include "wpi/StringMapEntry.h"
|
||||
#include "wpi/AllocatorBase.h"
|
||||
#include "wpi/MemAlloc.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/iterator.h"
|
||||
#include "wpi/iterator_range.h"
|
||||
#include "wpi/PointerLikeTypeTraits.h"
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename ValueTy> class StringMapConstIterator;
|
||||
template <typename ValueTy> class StringMapIterator;
|
||||
template <typename ValueTy> class StringMapKeyIterator;
|
||||
|
||||
/// StringMapImpl - This is the base class of StringMap that is shared among
|
||||
/// all of its instantiations.
|
||||
class StringMapImpl {
|
||||
protected:
|
||||
// Array of NumBuckets pointers to entries, null pointers are holes.
|
||||
// TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
|
||||
// by an array of the actual hash values as unsigned integers.
|
||||
StringMapEntryBase **TheTable = nullptr;
|
||||
unsigned NumBuckets = 0;
|
||||
unsigned NumItems = 0;
|
||||
unsigned NumTombstones = 0;
|
||||
unsigned ItemSize;
|
||||
|
||||
protected:
|
||||
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
|
||||
StringMapImpl(StringMapImpl &&RHS) noexcept
|
||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||
ItemSize(RHS.ItemSize) {
|
||||
RHS.TheTable = nullptr;
|
||||
RHS.NumBuckets = 0;
|
||||
RHS.NumItems = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
StringMapImpl(unsigned InitSize, unsigned ItemSize);
|
||||
unsigned RehashTable(unsigned BucketNo = 0);
|
||||
|
||||
/// 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
|
||||
/// case, the FullHashValue field of the bucket will be set to the hash value
|
||||
/// of the string.
|
||||
unsigned LookupBucketFor(std::string_view Key);
|
||||
|
||||
/// FindKey - Look up the bucket that contains the specified key. If it exists
|
||||
/// in the map, return the bucket number of the key. Otherwise return -1.
|
||||
/// This does not modify the map.
|
||||
int FindKey(std::string_view Key) const;
|
||||
|
||||
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
|
||||
/// delete it. This aborts if the value isn't in the table.
|
||||
void RemoveKey(StringMapEntryBase *V);
|
||||
|
||||
/// RemoveKey - Remove the StringMapEntry for the specified key from the
|
||||
/// table, returning it. If the key is not in the table, this returns null.
|
||||
StringMapEntryBase *RemoveKey(std::string_view Key);
|
||||
|
||||
/// Allocate the table with the specified number of buckets and otherwise
|
||||
/// setup the map as empty.
|
||||
void init(unsigned Size);
|
||||
|
||||
public:
|
||||
static constexpr uintptr_t TombstoneIntVal =
|
||||
static_cast<uintptr_t>(-1)
|
||||
<< PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
|
||||
|
||||
static StringMapEntryBase *getTombstoneVal() {
|
||||
return reinterpret_cast<StringMapEntryBase *>(TombstoneIntVal);
|
||||
}
|
||||
|
||||
unsigned getNumBuckets() const { return NumBuckets; }
|
||||
unsigned getNumItems() const { return NumItems; }
|
||||
|
||||
bool empty() const { return NumItems == 0; }
|
||||
unsigned size() const { return NumItems; }
|
||||
|
||||
void swap(StringMapImpl &Other) {
|
||||
std::swap(TheTable, Other.TheTable);
|
||||
std::swap(NumBuckets, Other.NumBuckets);
|
||||
std::swap(NumItems, Other.NumItems);
|
||||
std::swap(NumTombstones, Other.NumTombstones);
|
||||
}
|
||||
};
|
||||
|
||||
/// StringMap - This is an unconventional map that is specialized for handling
|
||||
/// keys that are "strings", which are basically ranges of bytes. This does some
|
||||
/// funky memory allocation and hashing things to make it extremely efficient,
|
||||
/// storing the string data *after* the value in the map.
|
||||
template <typename ValueTy, typename AllocatorTy = MallocAllocator>
|
||||
class StringMap : public StringMapImpl {
|
||||
AllocatorTy Allocator;
|
||||
|
||||
public:
|
||||
using MapEntryTy = StringMapEntry<ValueTy>;
|
||||
|
||||
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(unsigned InitialSize)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||
|
||||
explicit StringMap(AllocatorTy A)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {
|
||||
}
|
||||
|
||||
StringMap(unsigned InitialSize, AllocatorTy A)
|
||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(A) {}
|
||||
|
||||
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
|
||||
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
|
||||
for (const auto &P : List) {
|
||||
insert(P);
|
||||
}
|
||||
}
|
||||
|
||||
StringMap(StringMap &&RHS)
|
||||
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
|
||||
|
||||
StringMap(const StringMap &RHS)
|
||||
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||
Allocator(RHS.Allocator) {
|
||||
if (RHS.empty())
|
||||
return;
|
||||
|
||||
// Allocate TheTable of the same size as RHS's TheTable, and set the
|
||||
// sentinel appropriately (and NumBuckets).
|
||||
init(RHS.NumBuckets);
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1),
|
||||
*RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1);
|
||||
|
||||
NumItems = RHS.NumItems;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = RHS.TheTable[I];
|
||||
if (!Bucket || Bucket == getTombstoneVal()) {
|
||||
TheTable[I] = Bucket;
|
||||
continue;
|
||||
}
|
||||
|
||||
TheTable[I] = MapEntryTy::Create(
|
||||
static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
|
||||
static_cast<MapEntryTy *>(Bucket)->getValue());
|
||||
HashTable[I] = RHSHashTable[I];
|
||||
}
|
||||
|
||||
// Note that here we've copied everything from the RHS into this object,
|
||||
// tombstones included. We could, instead, have re-probed for each key to
|
||||
// instantiate this new object without any tombstone buckets. The
|
||||
// assumption here is that items are rarely deleted from most StringMaps,
|
||||
// and so tombstones are rare, so the cost of re-probing for all inputs is
|
||||
// not worthwhile.
|
||||
}
|
||||
|
||||
StringMap &operator=(StringMap RHS) {
|
||||
StringMapImpl::swap(RHS);
|
||||
std::swap(Allocator, RHS.Allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~StringMap() {
|
||||
// Delete all the elements in the map, but don't reset the elements
|
||||
// to default values. This is a copy of clear(), but avoids unnecessary
|
||||
// work not required in the destructor.
|
||||
if (!empty()) {
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(TheTable);
|
||||
}
|
||||
|
||||
AllocatorTy &getAllocator() { return Allocator; }
|
||||
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||
|
||||
using key_type = const char *;
|
||||
using mapped_type = ValueTy;
|
||||
using value_type = StringMapEntry<ValueTy>;
|
||||
using size_type = size_t;
|
||||
|
||||
using const_iterator = StringMapConstIterator<ValueTy>;
|
||||
using iterator = StringMapIterator<ValueTy>;
|
||||
|
||||
iterator begin() { return iterator(TheTable, NumBuckets == 0); }
|
||||
iterator end() { return iterator(TheTable + NumBuckets, true); }
|
||||
const_iterator begin() const {
|
||||
return const_iterator(TheTable, NumBuckets == 0);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return const_iterator(TheTable + NumBuckets, true);
|
||||
}
|
||||
|
||||
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
|
||||
return make_range(StringMapKeyIterator<ValueTy>(begin()),
|
||||
StringMapKeyIterator<ValueTy>(end()));
|
||||
}
|
||||
|
||||
iterator find(std::string_view Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
return iterator(TheTable + Bucket, true);
|
||||
}
|
||||
|
||||
const_iterator find(std::string_view Key) const {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1)
|
||||
return end();
|
||||
return const_iterator(TheTable + Bucket, true);
|
||||
}
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
ValueTy lookup(std::string_view Key) const {
|
||||
const_iterator it = find(Key);
|
||||
if (it != end())
|
||||
return it->second;
|
||||
return ValueTy();
|
||||
}
|
||||
|
||||
/// Lookup the ValueTy for the \p Key, or create a default constructed value
|
||||
/// if the key is not in the map.
|
||||
ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
|
||||
|
||||
/// count - Return 1 if the element is in the map, 0 otherwise.
|
||||
size_type count(std::string_view Key) const { return find(Key) == end() ? 0 : 1; }
|
||||
|
||||
template <typename InputTy>
|
||||
size_type count(const StringMapEntry<InputTy> &MapEntry) const {
|
||||
return count(MapEntry.getKey());
|
||||
}
|
||||
|
||||
/// equal - check whether both of the containers are equal.
|
||||
bool operator==(const StringMap &RHS) const {
|
||||
if (size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (const auto &KeyValue : *this) {
|
||||
auto FindInRHS = RHS.find(KeyValue.getKey());
|
||||
|
||||
if (FindInRHS == RHS.end())
|
||||
return false;
|
||||
|
||||
if (!(KeyValue.getValue() == FindInRHS->getValue()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const StringMap &RHS) const { return !(*this == RHS); }
|
||||
|
||||
/// insert - Insert the specified key/value pair into the map. If the key
|
||||
/// already exists in the map, return false and ignore the request, otherwise
|
||||
/// insert it and return true.
|
||||
bool insert(MapEntryTy *KeyValue) {
|
||||
unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return false; // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = KeyValue;
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
RehashTable();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// insert - Inserts the specified key/value pair into the map if the key
|
||||
/// isn't already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
std::pair<iterator, bool> insert(std::pair<std::string_view, ValueTy> KV) {
|
||||
return try_emplace(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
/// Inserts an element or assigns to the current element if the key already
|
||||
/// exists. The return type is the same as try_emplace.
|
||||
template <typename V>
|
||||
std::pair<iterator, bool> insert_or_assign(std::string_view Key, V &&Val) {
|
||||
auto Ret = try_emplace(Key, std::forward<V>(Val));
|
||||
if (!Ret.second)
|
||||
Ret.first->second = std::forward<V>(Val);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/// Emplace a new element for the specified key into the map if the key isn't
|
||||
/// already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
/// the pair points to the element with key equivalent to the key of the pair.
|
||||
template <typename... ArgsTy>
|
||||
std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&... Args) {
|
||||
unsigned BucketNo = LookupBucketFor(Key);
|
||||
StringMapEntryBase *&Bucket = TheTable[BucketNo];
|
||||
if (Bucket && Bucket != getTombstoneVal())
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false),
|
||||
false); // Already exists in map.
|
||||
|
||||
if (Bucket == getTombstoneVal())
|
||||
--NumTombstones;
|
||||
Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
|
||||
++NumItems;
|
||||
assert(NumItems + NumTombstones <= NumBuckets);
|
||||
|
||||
BucketNo = RehashTable(BucketNo);
|
||||
return std::make_pair(iterator(TheTable + BucketNo, false), true);
|
||||
}
|
||||
|
||||
// clear - Empties out the StringMap
|
||||
void clear() {
|
||||
if (empty())
|
||||
return;
|
||||
|
||||
// Zap all values, resetting the keys back to non-present (not tombstone),
|
||||
// which is safe because we're removing all elements.
|
||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||
StringMapEntryBase *&Bucket = TheTable[I];
|
||||
if (Bucket && Bucket != getTombstoneVal()) {
|
||||
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
|
||||
}
|
||||
Bucket = nullptr;
|
||||
}
|
||||
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
/// remove - Remove the specified key/value pair from the map, but do not
|
||||
/// erase it. This aborts if the key is not in the map.
|
||||
void remove(MapEntryTy *KeyValue) { RemoveKey(KeyValue); }
|
||||
|
||||
void erase(iterator I) {
|
||||
MapEntryTy &V = *I;
|
||||
remove(&V);
|
||||
V.Destroy(Allocator);
|
||||
}
|
||||
|
||||
bool erase(std::string_view Key) {
|
||||
iterator I = find(Key);
|
||||
if (I == end())
|
||||
return false;
|
||||
erase(I);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DerivedTy, typename ValueTy>
|
||||
class StringMapIterBase
|
||||
: public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
|
||||
ValueTy> {
|
||||
protected:
|
||||
StringMapEntryBase **Ptr = nullptr;
|
||||
|
||||
public:
|
||||
StringMapIterBase() = default;
|
||||
|
||||
explicit StringMapIterBase(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: Ptr(Bucket) {
|
||||
if (!NoAdvance)
|
||||
AdvancePastEmptyBuckets();
|
||||
}
|
||||
|
||||
DerivedTy &operator=(const DerivedTy &Other) {
|
||||
Ptr = Other.Ptr;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
|
||||
return LHS.Ptr == RHS.Ptr;
|
||||
}
|
||||
|
||||
DerivedTy &operator++() { // Preincrement
|
||||
++Ptr;
|
||||
AdvancePastEmptyBuckets();
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
DerivedTy operator++(int) { // Post-increment
|
||||
DerivedTy Tmp(Ptr);
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
DerivedTy &operator--() { // Predecrement
|
||||
--Ptr;
|
||||
ReversePastEmptyBuckets();
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
DerivedTy operator--(int) { // Post-decrement
|
||||
DerivedTy Tmp(Ptr);
|
||||
--*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
void AdvancePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
++Ptr;
|
||||
}
|
||||
void ReversePastEmptyBuckets() {
|
||||
while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
|
||||
--Ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapConstIterator
|
||||
: public StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>> {
|
||||
using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapConstIterator() = default;
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
const StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
|
||||
StringMapEntry<ValueTy>> {
|
||||
using base =
|
||||
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapIterator() = default;
|
||||
explicit StringMapIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
|
||||
operator StringMapConstIterator<ValueTy>() const {
|
||||
return StringMapConstIterator<ValueTy>(this->Ptr, true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapKeyIterator
|
||||
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, std::string_view> {
|
||||
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
|
||||
StringMapConstIterator<ValueTy>,
|
||||
std::forward_iterator_tag, std::string_view>;
|
||||
|
||||
public:
|
||||
StringMapKeyIterator() = default;
|
||||
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
||||
: base(std::move(Iter)) {}
|
||||
|
||||
std::string_view &operator*() {
|
||||
Key = this->wrapped()->getKey();
|
||||
return Key;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view Key;
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
bool operator==(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
// same instance?
|
||||
if (&lhs == &rhs) return true;
|
||||
|
||||
// first check that sizes are identical
|
||||
if (lhs.size() != rhs.size()) return false;
|
||||
|
||||
// copy into vectors and sort by key
|
||||
SmallVector<StringMapConstIterator<ValueTy>, 16> lhs_items;
|
||||
lhs_items.reserve(lhs.size());
|
||||
for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
lhs_items.push_back(i);
|
||||
std::sort(lhs_items.begin(), lhs_items.end(),
|
||||
[](const StringMapConstIterator<ValueTy>& a,
|
||||
const StringMapConstIterator<ValueTy>& b) {
|
||||
return a->getKey() < b->getKey();
|
||||
});
|
||||
|
||||
SmallVector<StringMapConstIterator<ValueTy>, 16> rhs_items;
|
||||
rhs_items.reserve(rhs.size());
|
||||
for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
rhs_items.push_back(i);
|
||||
std::sort(rhs_items.begin(), rhs_items.end(),
|
||||
[](const StringMapConstIterator<ValueTy>& a,
|
||||
const StringMapConstIterator<ValueTy>& b) {
|
||||
return a->getKey() < b->getKey();
|
||||
});
|
||||
|
||||
// compare vector keys and values
|
||||
for (auto a = lhs_items.begin(), b = rhs_items.begin(),
|
||||
aend = lhs_items.end(), bend = rhs_items.end();
|
||||
a != aend && b != bend; ++a, ++b) {
|
||||
if ((*a)->first() != (*b)->first() || (*a)->second != (*b)->second)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator!=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
bool operator<(const StringMap<ValueTy>& lhs, const StringMap<ValueTy>& rhs) {
|
||||
// same instance?
|
||||
if (&lhs == &rhs) return false;
|
||||
|
||||
// copy into vectors and sort by key
|
||||
SmallVector<std::string_view, 16> lhs_keys;
|
||||
lhs_keys.reserve(lhs.size());
|
||||
for (auto i = lhs.begin(), end = lhs.end(); i != end; ++i)
|
||||
lhs_keys.push_back(i->getKey());
|
||||
std::sort(lhs_keys.begin(), lhs_keys.end());
|
||||
|
||||
SmallVector<std::string_view, 16> rhs_keys;
|
||||
rhs_keys.reserve(rhs.size());
|
||||
for (auto i = rhs.begin(), end = rhs.end(); i != end; ++i)
|
||||
rhs_keys.push_back(i->getKey());
|
||||
std::sort(rhs_keys.begin(), rhs_keys.end());
|
||||
|
||||
// use std::vector comparison
|
||||
return lhs_keys < rhs_keys;
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator<=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator>(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
inline bool operator>=(const StringMap<ValueTy>& lhs,
|
||||
const StringMap<ValueTy>& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STRINGMAP_H
|
||||
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
vendored
Normal file
152
wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
//===- StringMapEntry.h - String Hash table map interface -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the StringMapEntry class - it is intended to be a low
|
||||
// dependency implementation detail of StringMap that is more suitable for
|
||||
// inclusion in public headers than StringMap.h itself is.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
#define WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||
class StringMapEntryBase {
|
||||
size_t keyLength;
|
||||
|
||||
public:
|
||||
explicit StringMapEntryBase(size_t keyLength) : keyLength(keyLength) {}
|
||||
|
||||
size_t getKeyLength() const { return keyLength; }
|
||||
|
||||
protected:
|
||||
/// Helper to tail-allocate \p Key. It'd be nice to generalize this so it
|
||||
/// could be reused elsewhere, maybe even taking an wpi::function_ref to
|
||||
/// type-erase the allocator and put it in a source file.
|
||||
template <typename AllocatorTy>
|
||||
static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
std::string_view Key, AllocatorTy &Allocator);
|
||||
};
|
||||
|
||||
// Define out-of-line to dissuade inlining.
|
||||
template <typename AllocatorTy>
|
||||
void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign,
|
||||
std::string_view Key,
|
||||
AllocatorTy &Allocator) {
|
||||
size_t KeyLength = Key.size();
|
||||
|
||||
// Allocate a new item with space for the string at the end and a null
|
||||
// terminator.
|
||||
size_t AllocSize = EntrySize + KeyLength + 1;
|
||||
void *Allocation = Allocator.Allocate(AllocSize, EntryAlign);
|
||||
assert(Allocation && "Unhandled out-of-memory");
|
||||
|
||||
// Copy the string information.
|
||||
char *Buffer = reinterpret_cast<char *>(Allocation) + EntrySize;
|
||||
if (KeyLength > 0)
|
||||
::memcpy(Buffer, Key.data(), KeyLength);
|
||||
Buffer[KeyLength] = 0; // Null terminate for convenience of clients.
|
||||
return Allocation;
|
||||
}
|
||||
|
||||
/// StringMapEntryStorage - Holds the value in a StringMapEntry.
|
||||
///
|
||||
/// Factored out into a separate base class to make it easier to specialize.
|
||||
/// This is primarily intended to support StringSet, which doesn't need a value
|
||||
/// stored at all.
|
||||
template <typename ValueTy>
|
||||
class StringMapEntryStorage : public StringMapEntryBase {
|
||||
public:
|
||||
ValueTy second;
|
||||
|
||||
explicit StringMapEntryStorage(size_t keyLength)
|
||||
: StringMapEntryBase(keyLength), second() {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntryStorage(size_t keyLength, InitTy &&... initVals)
|
||||
: StringMapEntryBase(keyLength),
|
||||
second(std::forward<InitTy>(initVals)...) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &e) = delete;
|
||||
|
||||
const ValueTy &getValue() const { return second; }
|
||||
ValueTy &getValue() { return second; }
|
||||
|
||||
void setValue(const ValueTy &V) { second = V; }
|
||||
};
|
||||
|
||||
template <> class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
|
||||
public:
|
||||
explicit StringMapEntryStorage(size_t keyLength, std::nullopt_t = std::nullopt)
|
||||
: StringMapEntryBase(keyLength) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &entry) = delete;
|
||||
|
||||
std::nullopt_t getValue() const { return std::nullopt; }
|
||||
};
|
||||
|
||||
/// StringMapEntry - This is used to represent one value that is inserted into
|
||||
/// a StringMap. It contains the Value itself and the key: the string length
|
||||
/// and data.
|
||||
template <typename ValueTy>
|
||||
class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
|
||||
public:
|
||||
using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
|
||||
|
||||
std::string_view getKey() const {
|
||||
return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// getKeyData - Return the start of the string data that is the key for this
|
||||
/// value. The string data is always stored immediately after the
|
||||
/// StringMapEntry object.
|
||||
const char *getKeyData() const {
|
||||
return reinterpret_cast<const char *>(this + 1);
|
||||
}
|
||||
|
||||
std::string_view first() const {
|
||||
return std::string_view(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
template <typename AllocatorTy, typename... InitTy>
|
||||
static StringMapEntry *Create(std::string_view key, AllocatorTy &allocator,
|
||||
InitTy &&... initVals) {
|
||||
return new (StringMapEntryBase::allocateWithKey(
|
||||
sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
|
||||
StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
|
||||
}
|
||||
|
||||
/// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
|
||||
/// into a StringMapEntry, return the StringMapEntry itself.
|
||||
static StringMapEntry &GetStringMapEntryFromKeyData(const char *keyData) {
|
||||
char *ptr = const_cast<char *>(keyData) - sizeof(StringMapEntry<ValueTy>);
|
||||
return *reinterpret_cast<StringMapEntry *>(ptr);
|
||||
}
|
||||
|
||||
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
|
||||
/// specified allocator.
|
||||
template <typename AllocatorTy> void Destroy(AllocatorTy &allocator) {
|
||||
// Free memory referenced by the item.
|
||||
size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1;
|
||||
this->~StringMapEntry();
|
||||
allocator.Deallocate(static_cast<void *>(this), AllocSize,
|
||||
alignof(StringMapEntry));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STRINGMAPENTRY_H
|
||||
165
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
vendored
Normal file
165
wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares generic and optimized functions to swap the byte order of
|
||||
// an integral type.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
|
||||
#define WPIUTIL_WPI_SWAPBYTEORDER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#if defined(_MSC_VER) && !defined(_DEBUG)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
|
||||
defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
|
||||
#include <endian.h>
|
||||
#elif defined(_AIX)
|
||||
#include <sys/machine.h>
|
||||
#elif defined(__sun)
|
||||
/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
|
||||
#include <sys/types.h>
|
||||
#define BIG_ENDIAN 4321
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#if defined(_BIG_ENDIAN)
|
||||
#define BYTE_ORDER BIG_ENDIAN
|
||||
#else
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
#elif defined(__MVS__)
|
||||
#define BIG_ENDIAN 4321
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#define BYTE_ORDER BIG_ENDIAN
|
||||
#else
|
||||
#if !defined(BYTE_ORDER) && !defined(_WIN32)
|
||||
#include <machine/endian.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// ByteSwap_16 - This function returns a byte-swapped representation of
|
||||
/// the 16-bit argument.
|
||||
inline uint16_t ByteSwap_16(uint16_t value) {
|
||||
#if defined(_MSC_VER) && !defined(_DEBUG)
|
||||
// The DLL version of the runtime lacks these functions (bug!?), but in a
|
||||
// release build they're replaced with BSWAP instructions anyway.
|
||||
return _byteswap_ushort(value);
|
||||
#else
|
||||
uint16_t Hi = value << 8;
|
||||
uint16_t Lo = value >> 8;
|
||||
return Hi | Lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// This function returns a byte-swapped representation of the 32-bit argument.
|
||||
inline uint32_t ByteSwap_32(uint32_t value) {
|
||||
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
|
||||
return __builtin_bswap32(value);
|
||||
#elif defined(_MSC_VER) && !defined(_DEBUG)
|
||||
return _byteswap_ulong(value);
|
||||
#else
|
||||
uint32_t Byte0 = value & 0x000000FF;
|
||||
uint32_t Byte1 = value & 0x0000FF00;
|
||||
uint32_t Byte2 = value & 0x00FF0000;
|
||||
uint32_t Byte3 = value & 0xFF000000;
|
||||
return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// This function returns a byte-swapped representation of the 64-bit argument.
|
||||
inline uint64_t ByteSwap_64(uint64_t value) {
|
||||
#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
|
||||
return __builtin_bswap64(value);
|
||||
#elif defined(_MSC_VER) && !defined(_DEBUG)
|
||||
return _byteswap_uint64(value);
|
||||
#else
|
||||
uint64_t Hi = ByteSwap_32(uint32_t(value));
|
||||
uint32_t Lo = ByteSwap_32(uint32_t(value >> 32));
|
||||
return (Hi << 32) | Lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace sys {
|
||||
|
||||
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
|
||||
constexpr bool IsBigEndianHost = true;
|
||||
#else
|
||||
constexpr bool IsBigEndianHost = false;
|
||||
#endif
|
||||
|
||||
static const bool IsLittleEndianHost = !IsBigEndianHost;
|
||||
|
||||
inline unsigned char getSwappedBytes(unsigned char C) { return C; }
|
||||
inline signed char getSwappedBytes(signed char C) { return C; }
|
||||
inline char getSwappedBytes(char C) { return C; }
|
||||
|
||||
inline unsigned short getSwappedBytes(unsigned short C) { return ByteSwap_16(C); }
|
||||
inline signed short getSwappedBytes( signed short C) { return ByteSwap_16(C); }
|
||||
|
||||
inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); }
|
||||
inline signed int getSwappedBytes( signed int C) { return ByteSwap_32(C); }
|
||||
|
||||
inline unsigned long getSwappedBytes(unsigned long C) {
|
||||
// Handle LLP64 and LP64 platforms.
|
||||
return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
|
||||
: ByteSwap_64((uint64_t)C);
|
||||
}
|
||||
inline signed long getSwappedBytes(signed long C) {
|
||||
// Handle LLP64 and LP64 platforms.
|
||||
return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
|
||||
: ByteSwap_64((uint64_t)C);
|
||||
}
|
||||
|
||||
inline unsigned long long getSwappedBytes(unsigned long long C) {
|
||||
return ByteSwap_64(C);
|
||||
}
|
||||
inline signed long long getSwappedBytes(signed long long C) {
|
||||
return ByteSwap_64(C);
|
||||
}
|
||||
|
||||
inline float getSwappedBytes(float C) {
|
||||
union {
|
||||
uint32_t i;
|
||||
float f;
|
||||
} in, out;
|
||||
in.f = C;
|
||||
out.i = ByteSwap_32(in.i);
|
||||
return out.f;
|
||||
}
|
||||
|
||||
inline double getSwappedBytes(double C) {
|
||||
union {
|
||||
uint64_t i;
|
||||
double d;
|
||||
} in, out;
|
||||
in.d = C;
|
||||
out.i = ByteSwap_64(in.i);
|
||||
return out.d;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
|
||||
return static_cast<T>(
|
||||
getSwappedBytes(static_cast<std::underlying_type_t<T>>(C)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void swapByteOrder(T &Value) {
|
||||
Value = getSwappedBytes(Value);
|
||||
}
|
||||
|
||||
} // end namespace sys
|
||||
} // end namespace wpi
|
||||
|
||||
#endif
|
||||
164
wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
vendored
Normal file
164
wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Defines the llvm::VersionTuple class, which represents a version in
|
||||
/// the form major[.minor[.subminor]].
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
#define WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace wpi {
|
||||
class raw_ostream;
|
||||
|
||||
/// Represents a version number in the form major[.minor[.subminor[.build]]].
|
||||
class VersionTuple {
|
||||
unsigned Major : 32;
|
||||
|
||||
unsigned Minor : 31;
|
||||
unsigned HasMinor : 1;
|
||||
|
||||
unsigned Subminor : 31;
|
||||
unsigned HasSubminor : 1;
|
||||
|
||||
unsigned Build : 31;
|
||||
unsigned HasBuild : 1;
|
||||
|
||||
public:
|
||||
VersionTuple()
|
||||
: Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
|
||||
Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major)
|
||||
: Major(Major), Minor(0), HasMinor(false), Subminor(0),
|
||||
HasSubminor(false), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
|
||||
HasSubminor(false), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
|
||||
HasSubminor(true), Build(0), HasBuild(false) {}
|
||||
|
||||
explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
|
||||
unsigned Build)
|
||||
: Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
|
||||
HasSubminor(true), Build(Build), HasBuild(true) {}
|
||||
|
||||
/// Determine whether this version information is empty
|
||||
/// (e.g., all version components are zero).
|
||||
bool empty() const {
|
||||
return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
|
||||
}
|
||||
|
||||
/// Retrieve the major version number.
|
||||
unsigned getMajor() const { return Major; }
|
||||
|
||||
/// Retrieve the minor version number, if provided.
|
||||
std::optional<unsigned> getMinor() const {
|
||||
if (!HasMinor)
|
||||
return std::nullopt;
|
||||
return Minor;
|
||||
}
|
||||
|
||||
/// Retrieve the subminor version number, if provided.
|
||||
std::optional<unsigned> getSubminor() const {
|
||||
if (!HasSubminor)
|
||||
return std::nullopt;
|
||||
return Subminor;
|
||||
}
|
||||
|
||||
/// Retrieve the build version number, if provided.
|
||||
std::optional<unsigned> getBuild() const {
|
||||
if (!HasBuild)
|
||||
return std::nullopt;
|
||||
return Build;
|
||||
}
|
||||
|
||||
/// Return a version tuple that contains only the first 3 version components.
|
||||
VersionTuple withoutBuild() const {
|
||||
if (HasBuild)
|
||||
return VersionTuple(Major, Minor, Subminor);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return a version tuple that contains only components that are non-zero.
|
||||
VersionTuple normalize() const {
|
||||
VersionTuple Result = *this;
|
||||
if (Result.Build == 0) {
|
||||
Result.HasBuild = false;
|
||||
if (Result.Subminor == 0) {
|
||||
Result.HasSubminor = false;
|
||||
if (Result.Minor == 0)
|
||||
Result.HasMinor = false;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Determine if two version numbers are equivalent. If not
|
||||
/// provided, minor and subminor version numbers are considered to be zero.
|
||||
friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return X.Major == Y.Major && X.Minor == Y.Minor &&
|
||||
X.Subminor == Y.Subminor && X.Build == Y.Build;
|
||||
}
|
||||
|
||||
/// Determine if two version numbers are not equivalent.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
|
||||
/// Determine whether one version number precedes another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return std::tie(X.Major, X.Minor, X.Subminor, X.Build) <
|
||||
std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build);
|
||||
}
|
||||
|
||||
/// Determine whether one version number follows another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator>(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return Y < X;
|
||||
}
|
||||
|
||||
/// Determine whether one version number precedes or is
|
||||
/// equivalent to another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return !(Y < X);
|
||||
}
|
||||
|
||||
/// Determine whether one version number follows or is
|
||||
/// equivalent to another.
|
||||
///
|
||||
/// If not provided, minor and subminor version numbers are considered to be
|
||||
/// zero.
|
||||
friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
|
||||
return !(X < Y);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
#endif // WPIUTIL_WPI_VERSIONTUPLE_H
|
||||
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/WindowsError.h
vendored
Normal file
18
wpiutil/src/main/native/thirdparty/llvm/include/wpi/WindowsError.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_WINDOWSERROR_H
|
||||
#define WPIUTIL_WPI_WINDOWSERROR_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace wpi {
|
||||
std::error_code mapWindowsError(unsigned EV);
|
||||
}
|
||||
|
||||
#endif
|
||||
66
wpiutil/src/main/native/thirdparty/llvm/include/wpi/function_ref.h
vendored
Normal file
66
wpiutil/src/main/native/thirdparty/llvm/include/wpi/function_ref.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_FUNCTION_REF_H_
|
||||
#define WPIUTIL_WPI_FUNCTION_REF_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// An efficient, type-erasing, non-owning reference to a callable. This is
|
||||
/// intended for use as the type of a function parameter that is not used
|
||||
/// after the function in question returns.
|
||||
///
|
||||
/// This class does not own the callable, so it is not in general safe to store
|
||||
/// a function_ref.
|
||||
template <typename Fn>
|
||||
class function_ref;
|
||||
|
||||
template <typename Ret, typename... Params>
|
||||
class function_ref<Ret(Params...)> {
|
||||
Ret (*callback)(intptr_t callable, Params... params) = nullptr;
|
||||
intptr_t callable;
|
||||
|
||||
template <typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Params... params) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(std::forward<Params>(
|
||||
params)...);
|
||||
}
|
||||
|
||||
public:
|
||||
function_ref() = default;
|
||||
/*implicit*/ function_ref(std::nullptr_t) {} // NOLINT
|
||||
|
||||
template <typename Callable>
|
||||
/*implicit*/ function_ref( // NOLINT
|
||||
Callable&& callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_reference<Callable>::type,
|
||||
function_ref>::value>::type* = nullptr)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
|
||||
Ret operator()(Params... params) const {
|
||||
return callback(callable, std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
explicit operator bool() const { return callback; }
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_FUNCTION_REF_H_
|
||||
355
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator.h
vendored
Normal file
355
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator.h
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ITERATOR_H
|
||||
#define WPIUTIL_WPI_ITERATOR_H
|
||||
|
||||
#include "wpi/iterator_range.h"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// CRTP base class which implements the entire standard iterator facade
|
||||
/// in terms of a minimal subset of the interface.
|
||||
///
|
||||
/// Use this when it is reasonable to implement most of the iterator
|
||||
/// functionality in terms of a core subset. If you need special behavior or
|
||||
/// there are performance implications for this, you may want to override the
|
||||
/// relevant members instead.
|
||||
///
|
||||
/// Note, one abstraction that this does *not* provide is implementing
|
||||
/// subtraction in terms of addition by negating the difference. Negation isn't
|
||||
/// always information preserving, and I can see very reasonable iterator
|
||||
/// designs where this doesn't work well. It doesn't really force much added
|
||||
/// boilerplate anyways.
|
||||
///
|
||||
/// Another abstraction that this doesn't provide is implementing increment in
|
||||
/// terms of addition of one. These aren't equivalent for all iterator
|
||||
/// categories, and respecting that adds a lot of complexity for little gain.
|
||||
///
|
||||
/// Classes wishing to use `iterator_facade_base` should implement the following
|
||||
/// methods:
|
||||
///
|
||||
/// Forward Iterators:
|
||||
/// (All of the following methods)
|
||||
/// - DerivedT &operator=(const DerivedT &R);
|
||||
/// - bool operator==(const DerivedT &R) const;
|
||||
/// - const T &operator*() const;
|
||||
/// - T &operator*();
|
||||
/// - DerivedT &operator++();
|
||||
///
|
||||
/// Bidirectional Iterators:
|
||||
/// (All methods of forward iterators, plus the following)
|
||||
/// - DerivedT &operator--();
|
||||
///
|
||||
/// Random-access Iterators:
|
||||
/// (All methods of bidirectional iterators excluding the following)
|
||||
/// - DerivedT &operator++();
|
||||
/// - DerivedT &operator--();
|
||||
/// (and plus the following)
|
||||
/// - bool operator<(const DerivedT &RHS) const;
|
||||
/// - DifferenceTypeT operator-(const DerivedT &R) const;
|
||||
/// - DerivedT &operator+=(DifferenceTypeT N);
|
||||
/// - DerivedT &operator-=(DifferenceTypeT N);
|
||||
///
|
||||
template <typename DerivedT, typename IteratorCategoryT, typename T,
|
||||
typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
|
||||
typename ReferenceT = T &>
|
||||
class iterator_facade_base {
|
||||
public:
|
||||
using iterator_category = IteratorCategoryT;
|
||||
using value_type = T;
|
||||
using difference_type = DifferenceTypeT;
|
||||
using pointer = PointerT;
|
||||
using reference = ReferenceT;
|
||||
|
||||
protected:
|
||||
enum {
|
||||
IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
|
||||
IteratorCategoryT>::value,
|
||||
IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag,
|
||||
IteratorCategoryT>::value,
|
||||
};
|
||||
|
||||
/// A proxy object for computing a reference via indirecting a copy of an
|
||||
/// iterator. This is used in APIs which need to produce a reference via
|
||||
/// indirection but for which the iterator object might be a temporary. The
|
||||
/// proxy preserves the iterator internally and exposes the indirected
|
||||
/// reference via a conversion operator.
|
||||
class ReferenceProxy {
|
||||
friend iterator_facade_base;
|
||||
|
||||
DerivedT I;
|
||||
|
||||
ReferenceProxy(DerivedT I) : I(std::move(I)) {}
|
||||
|
||||
public:
|
||||
operator ReferenceT() const { return *I; }
|
||||
};
|
||||
|
||||
public:
|
||||
DerivedT operator+(DifferenceTypeT n) const {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp += n;
|
||||
return tmp;
|
||||
}
|
||||
friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
return i + n;
|
||||
}
|
||||
DerivedT operator-(DifferenceTypeT n) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
DerivedT tmp = *static_cast<const DerivedT *>(this);
|
||||
tmp -= n;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
DerivedT &operator++() {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
return static_cast<DerivedT *>(this)->operator+=(1);
|
||||
}
|
||||
DerivedT operator++(int) {
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
++*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
return static_cast<DerivedT *>(this)->operator-=(1);
|
||||
}
|
||||
DerivedT operator--(int) {
|
||||
static_assert(
|
||||
IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
DerivedT tmp = *static_cast<DerivedT *>(this);
|
||||
--*static_cast<DerivedT *>(this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#ifndef __cpp_impl_three_way_comparison
|
||||
bool operator!=(const DerivedT &RHS) const {
|
||||
return !(static_cast<const DerivedT &>(*this) == RHS);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator>(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !(static_cast<const DerivedT &>(*this) < RHS) &&
|
||||
!(static_cast<const DerivedT &>(*this) == RHS);
|
||||
}
|
||||
bool operator<=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !(static_cast<const DerivedT &>(*this) > RHS);
|
||||
}
|
||||
bool operator>=(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return !(static_cast<const DerivedT &>(*this) < RHS);
|
||||
}
|
||||
|
||||
PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
|
||||
PointerT operator->() const {
|
||||
return &static_cast<const DerivedT *>(this)->operator*();
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) const {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
};
|
||||
|
||||
/// CRTP base class for adapting an iterator to a different type.
|
||||
///
|
||||
/// This class can be used through CRTP to adapt one iterator into another.
|
||||
/// Typically this is done through providing in the derived class a custom \c
|
||||
/// operator* implementation. Other methods can be overridden as well.
|
||||
template <
|
||||
typename DerivedT, typename WrappedIteratorT,
|
||||
typename IteratorCategoryT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
|
||||
typename DifferenceTypeT =
|
||||
typename std::iterator_traits<WrappedIteratorT>::difference_type,
|
||||
typename PointerT = std::conditional_t<
|
||||
std::is_same<T, typename std::iterator_traits<
|
||||
WrappedIteratorT>::value_type>::value,
|
||||
typename std::iterator_traits<WrappedIteratorT>::pointer, T *>,
|
||||
typename ReferenceT = std::conditional_t<
|
||||
std::is_same<T, typename std::iterator_traits<
|
||||
WrappedIteratorT>::value_type>::value,
|
||||
typename std::iterator_traits<WrappedIteratorT>::reference, T &>>
|
||||
class iterator_adaptor_base
|
||||
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
|
||||
DifferenceTypeT, PointerT, ReferenceT> {
|
||||
using BaseT = typename iterator_adaptor_base::iterator_facade_base;
|
||||
|
||||
protected:
|
||||
WrappedIteratorT I;
|
||||
|
||||
iterator_adaptor_base() = default;
|
||||
|
||||
explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {
|
||||
static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
}
|
||||
|
||||
const WrappedIteratorT &wrapped() const { return I; }
|
||||
|
||||
public:
|
||||
using difference_type = DifferenceTypeT;
|
||||
|
||||
DerivedT &operator+=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '+=' operator is only defined for random access iterators.");
|
||||
I += n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
DerivedT &operator-=(difference_type n) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-=' operator is only defined for random access iterators.");
|
||||
I -= n;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator-;
|
||||
difference_type operator-(const DerivedT &RHS) const {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"The '-' operator is only defined for random access iterators.");
|
||||
return I - RHS.I;
|
||||
}
|
||||
|
||||
// We have to explicitly provide ++ and -- rather than letting the facade
|
||||
// forward to += because WrappedIteratorT might not support +=.
|
||||
using BaseT::operator++;
|
||||
DerivedT &operator++() {
|
||||
++I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
using BaseT::operator--;
|
||||
DerivedT &operator--() {
|
||||
static_assert(
|
||||
BaseT::IsBidirectional,
|
||||
"The decrement operator is only defined for bidirectional iterators.");
|
||||
--I;
|
||||
return *static_cast<DerivedT *>(this);
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator_adaptor_base &LHS,
|
||||
const iterator_adaptor_base &RHS) {
|
||||
return LHS.I == RHS.I;
|
||||
}
|
||||
friend bool operator<(const iterator_adaptor_base &LHS,
|
||||
const iterator_adaptor_base &RHS) {
|
||||
static_assert(
|
||||
BaseT::IsRandomAccess,
|
||||
"Relational operators are only defined for random access iterators.");
|
||||
return LHS.I < RHS.I;
|
||||
}
|
||||
|
||||
ReferenceT operator*() const { return *I; }
|
||||
};
|
||||
|
||||
/// An iterator type that allows iterating over the pointees via some
|
||||
/// other iterator.
|
||||
///
|
||||
/// The typical usage of this is to expose a type that iterates over Ts, but
|
||||
/// which is implemented with some iterator over T*s:
|
||||
///
|
||||
/// \code
|
||||
/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
|
||||
/// \endcode
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = std::remove_reference_t<decltype(
|
||||
**std::declval<WrappedIteratorT>())>>
|
||||
struct pointee_iterator
|
||||
: iterator_adaptor_base<
|
||||
pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
pointee_iterator() = default;
|
||||
template <typename U>
|
||||
pointee_iterator(U &&u)
|
||||
: pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
|
||||
|
||||
T &operator*() const { return **this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointee_iterator<WrappedIteratorT>>
|
||||
make_pointee_range(RangeT &&Range) {
|
||||
using PointeeIteratorT = pointee_iterator<WrappedIteratorT>;
|
||||
return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointeeIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = decltype(&*std::declval<WrappedIteratorT>())>
|
||||
class pointer_iterator
|
||||
: public iterator_adaptor_base<
|
||||
pointer_iterator<WrappedIteratorT, T>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
mutable T Ptr;
|
||||
|
||||
public:
|
||||
pointer_iterator() = default;
|
||||
|
||||
explicit pointer_iterator(WrappedIteratorT u)
|
||||
: pointer_iterator::iterator_adaptor_base(std::move(u)) {}
|
||||
|
||||
T &operator*() { return Ptr = &*this->I; }
|
||||
const T &operator*() const { return Ptr = &*this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointer_iterator<WrappedIteratorT>>
|
||||
make_pointer_range(RangeT &&Range) {
|
||||
using PointerIteratorT = pointer_iterator<WrappedIteratorT>;
|
||||
return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
template <typename WrappedIteratorT,
|
||||
typename T1 = std::remove_reference_t<decltype(
|
||||
**std::declval<WrappedIteratorT>())>,
|
||||
typename T2 = std::add_pointer_t<T1>>
|
||||
using raw_pointer_iterator =
|
||||
pointer_iterator<pointee_iterator<WrappedIteratorT, T1>, T2>;
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_ITERATOR_H
|
||||
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
vendored
Normal file
63
wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This provides a very simple, boring adaptor for a begin and end iterator
|
||||
/// into a range type. This should be used to build range views that work well
|
||||
/// with range based for loops and range based constructors.
|
||||
///
|
||||
/// Note that code here follows more standards-based coding conventions as it
|
||||
/// is mirroring proposed interfaces for standardization.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
|
||||
#define WPIUTIL_WPI_ITERATOR_RANGE_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// A range adaptor for a pair of iterators.
|
||||
///
|
||||
/// This just wraps two iterators into a range-compatible interface. Nothing
|
||||
/// fancy at all.
|
||||
template <typename IteratorT>
|
||||
class iterator_range {
|
||||
IteratorT begin_iterator, end_iterator;
|
||||
|
||||
public:
|
||||
//TODO: Add SFINAE to test that the Container's iterators match the range's
|
||||
// iterators.
|
||||
template <typename Container>
|
||||
iterator_range(Container &&c)
|
||||
//TODO: Consider ADL/non-member begin/end calls.
|
||||
: begin_iterator(c.begin()), end_iterator(c.end()) {}
|
||||
iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
|
||||
: begin_iterator(std::move(begin_iterator)),
|
||||
end_iterator(std::move(end_iterator)) {}
|
||||
|
||||
IteratorT begin() const { return begin_iterator; }
|
||||
IteratorT end() const { return end_iterator; }
|
||||
bool empty() const { return begin_iterator == end_iterator; }
|
||||
};
|
||||
|
||||
/// Convenience function for iterating over sub-ranges.
|
||||
///
|
||||
/// This provides a bit of syntactic sugar to make using sub-ranges
|
||||
/// in for loops a bit easier. Analogous to std::make_pair().
|
||||
template <class T> iterator_range<T> make_range(T x, T y) {
|
||||
return iterator_range<T>(std::move(x), std::move(y));
|
||||
}
|
||||
|
||||
template <typename T> iterator_range<T> make_range(std::pair<T, T> p) {
|
||||
return iterator_range<T>(std::move(p.first), std::move(p.second));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
41
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_os_ostream.h
vendored
Normal file
41
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_os_ostream.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
//===- raw_os_ostream.h - std::ostream adaptor for raw_ostream --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the raw_os_ostream class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_RAW_OS_OSTREAM_H
|
||||
#define WPIUTIL_WPI_RAW_OS_OSTREAM_H
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// raw_os_ostream - A raw_ostream that writes to an std::ostream. This is a
|
||||
/// simple adaptor class. It does not check for output errors; clients should
|
||||
/// use the underlying stream to detect errors.
|
||||
class raw_os_ostream : public raw_ostream {
|
||||
std::ostream &OS;
|
||||
|
||||
/// write_impl - See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
/// current_pos - Return the current position within the stream, not
|
||||
/// counting the bytes currently in the buffer.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
raw_os_ostream(std::ostream &O) : OS(O) {}
|
||||
~raw_os_ostream() override;
|
||||
};
|
||||
|
||||
} // end wpi namespace
|
||||
|
||||
#endif
|
||||
754
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
vendored
Normal file
754
wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
vendored
Normal file
@@ -0,0 +1,754 @@
|
||||
//===--- raw_ostream.h - Raw output stream ----------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the raw_ostream class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
#define WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/span.h"
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#if __cplusplus > 201402L
|
||||
#include <string_view>
|
||||
#endif
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace fs {
|
||||
enum FileAccess : unsigned;
|
||||
enum OpenFlags : unsigned;
|
||||
enum CreationDisposition : unsigned;
|
||||
class FileLocker;
|
||||
} // end namespace fs
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/// This class implements an extremely fast bulk output stream that can *only*
|
||||
/// output to a stream. It does not support seeking, reopening, rewinding, line
|
||||
/// buffered disciplines etc. It is a simple buffer that outputs
|
||||
/// a chunk at a time.
|
||||
class raw_ostream {
|
||||
public:
|
||||
// Class kinds to support LLVM-style RTTI.
|
||||
enum class OStreamKind {
|
||||
OK_OStream,
|
||||
OK_FDStream,
|
||||
};
|
||||
|
||||
private:
|
||||
OStreamKind Kind;
|
||||
|
||||
/// The buffer is handled in such a way that the buffer is
|
||||
/// uninitialized, unbuffered, or out of space when OutBufCur >=
|
||||
/// OutBufEnd. Thus a single comparison suffices to determine if we
|
||||
/// need to take the slow path to write a single character.
|
||||
///
|
||||
/// The buffer is in one of three states:
|
||||
/// 1. Unbuffered (BufferMode == Unbuffered)
|
||||
/// 1. Uninitialized (BufferMode != Unbuffered && OutBufStart == 0).
|
||||
/// 2. Buffered (BufferMode != Unbuffered && OutBufStart != 0 &&
|
||||
/// OutBufEnd - OutBufStart >= 1).
|
||||
///
|
||||
/// If buffered, then the raw_ostream owns the buffer if (BufferMode ==
|
||||
/// InternalBuffer); otherwise the buffer has been set via SetBuffer and is
|
||||
/// managed by the subclass.
|
||||
///
|
||||
/// If a subclass installs an external buffer using SetBuffer then it can wait
|
||||
/// for a \see write_impl() call to handle the data which has been put into
|
||||
/// this buffer.
|
||||
char *OutBufStart, *OutBufEnd, *OutBufCur;
|
||||
|
||||
/// Optional stream this stream is tied to. If this stream is written to, the
|
||||
/// tied-to stream will be flushed first.
|
||||
raw_ostream *TiedStream = nullptr;
|
||||
|
||||
enum class BufferKind {
|
||||
Unbuffered = 0,
|
||||
InternalBuffer,
|
||||
ExternalBuffer
|
||||
} BufferMode;
|
||||
|
||||
public:
|
||||
// color order matches ANSI escape sequence, don't change
|
||||
enum class Colors {
|
||||
BLACK = 0,
|
||||
RED,
|
||||
GREEN,
|
||||
YELLOW,
|
||||
BLUE,
|
||||
MAGENTA,
|
||||
CYAN,
|
||||
WHITE,
|
||||
SAVEDCOLOR,
|
||||
RESET,
|
||||
};
|
||||
|
||||
static constexpr Colors BLACK = Colors::BLACK;
|
||||
static constexpr Colors RED = Colors::RED;
|
||||
static constexpr Colors GREEN = Colors::GREEN;
|
||||
static constexpr Colors YELLOW = Colors::YELLOW;
|
||||
static constexpr Colors BLUE = Colors::BLUE;
|
||||
static constexpr Colors MAGENTA = Colors::MAGENTA;
|
||||
static constexpr Colors CYAN = Colors::CYAN;
|
||||
static constexpr Colors WHITE = Colors::WHITE;
|
||||
static constexpr Colors SAVEDCOLOR = Colors::SAVEDCOLOR;
|
||||
static constexpr Colors RESET = Colors::RESET;
|
||||
|
||||
explicit raw_ostream(bool unbuffered = false,
|
||||
OStreamKind K = OStreamKind::OK_OStream)
|
||||
: Kind(K), BufferMode(unbuffered ? BufferKind::Unbuffered
|
||||
: BufferKind::InternalBuffer) {
|
||||
// Start out ready to flush.
|
||||
OutBufStart = OutBufEnd = OutBufCur = nullptr;
|
||||
}
|
||||
|
||||
raw_ostream(const raw_ostream &) = delete;
|
||||
void operator=(const raw_ostream &) = delete;
|
||||
|
||||
virtual ~raw_ostream();
|
||||
|
||||
/// tell - Return the current offset with the file.
|
||||
uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); }
|
||||
|
||||
OStreamKind get_kind() const { return Kind; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Configuration Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// If possible, pre-allocate \p ExtraSize bytes for stream data.
|
||||
/// i.e. it extends internal buffers to keep additional ExtraSize bytes.
|
||||
/// So that the stream could keep at least tell() + ExtraSize bytes
|
||||
/// without re-allocations. reserveExtraSpace() does not change
|
||||
/// the size/data of the stream.
|
||||
virtual void reserveExtraSpace(uint64_t ExtraSize) {}
|
||||
|
||||
/// Set the stream to be buffered, with an automatically determined buffer
|
||||
/// size.
|
||||
void SetBuffered();
|
||||
|
||||
/// Set the stream to be buffered, using the specified buffer size.
|
||||
void SetBufferSize(size_t Size) {
|
||||
flush();
|
||||
SetBufferAndMode(new char[Size], Size, BufferKind::InternalBuffer);
|
||||
}
|
||||
|
||||
size_t GetBufferSize() const {
|
||||
// If we're supposed to be buffered but haven't actually gotten around
|
||||
// to allocating the buffer yet, return the value that would be used.
|
||||
if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr)
|
||||
return preferred_buffer_size();
|
||||
|
||||
// Otherwise just return the size of the allocated buffer.
|
||||
return OutBufEnd - OutBufStart;
|
||||
}
|
||||
|
||||
/// Set the stream to be unbuffered. When unbuffered, the stream will flush
|
||||
/// after every write. This routine will also flush the buffer immediately
|
||||
/// when the stream is being set to unbuffered.
|
||||
void SetUnbuffered() {
|
||||
flush();
|
||||
SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered);
|
||||
}
|
||||
|
||||
size_t GetNumBytesInBuffer() const {
|
||||
return OutBufCur - OutBufStart;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Data Output Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void flush() {
|
||||
if (OutBufCur != OutBufStart)
|
||||
flush_nonempty();
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(unsigned char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(signed char C) {
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
return write(C);
|
||||
*OutBufCur++ = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(span<const uint8_t> Arr) {
|
||||
// Inline fast path, particularly for arrays with a known length.
|
||||
size_t Size = Arr.size();
|
||||
|
||||
// Make sure we can use the fast path.
|
||||
if (Size > (size_t)(OutBufEnd - OutBufCur))
|
||||
return write(Arr.data(), Size);
|
||||
|
||||
if (Size) {
|
||||
memcpy(OutBufCur, Arr.data(), Size);
|
||||
OutBufCur += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(std::string_view Str) {
|
||||
// Inline fast path, particularly for strings with a known length.
|
||||
size_t Size = Str.size();
|
||||
|
||||
// Make sure we can use the fast path.
|
||||
if (Size > (size_t)(OutBufEnd - OutBufCur))
|
||||
return write(Str.data(), Size);
|
||||
|
||||
if (Size) {
|
||||
memcpy(OutBufCur, Str.data(), Size);
|
||||
OutBufCur += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const char *Str) {
|
||||
// Inline fast path, particularly for constant strings where a sufficiently
|
||||
// smart compiler will simplify strlen.
|
||||
|
||||
return this->operator<<(std::string_view(Str));
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const std::string &Str) {
|
||||
// Avoid the fast path, it would only increase code size for a marginal win.
|
||||
return write(Str.data(), Str.length());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const SmallVectorImpl<char> &Str) {
|
||||
return write(Str.data(), Str.size());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const std::vector<uint8_t> &Arr) {
|
||||
// Avoid the fast path, it would only increase code size for a marginal win.
|
||||
return write(Arr.data(), Arr.size());
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(const SmallVectorImpl<uint8_t> &Arr) {
|
||||
return write(Arr.data(), Arr.size());
|
||||
}
|
||||
|
||||
/// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
|
||||
/// satisfy wpi::isPrint into an escape sequence.
|
||||
raw_ostream &write_escaped(std::string_view Str, bool UseHexEscapes = false);
|
||||
|
||||
raw_ostream &write(unsigned char C);
|
||||
raw_ostream &write(const char *Ptr, size_t Size);
|
||||
raw_ostream &write(const uint8_t *Ptr, size_t Size) {
|
||||
return write(reinterpret_cast<const char *>(Ptr), Size);
|
||||
}
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &indent(unsigned NumSpaces);
|
||||
|
||||
/// write_zeros - Insert 'NumZeros' nulls.
|
||||
raw_ostream &write_zeros(unsigned NumZeros);
|
||||
|
||||
/// Changes the foreground color of text that will be output from this point
|
||||
/// forward.
|
||||
/// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
|
||||
/// change only the bold attribute, and keep colors untouched
|
||||
/// @param Bold bold/brighter text, default false
|
||||
/// @param BG if true change the background, default: change foreground
|
||||
/// @returns itself so it can be used within << invocations
|
||||
virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false,
|
||||
bool BG = false) {
|
||||
(void)Color;
|
||||
(void)Bold;
|
||||
(void)BG;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Resets the colors to terminal defaults. Call this when you are done
|
||||
/// outputting colored text, or before program exit.
|
||||
virtual raw_ostream &resetColor() { return *this; }
|
||||
|
||||
/// Reverses the foreground and background colors.
|
||||
virtual raw_ostream &reverseColor() { return *this; }
|
||||
|
||||
/// This function determines if this stream is connected to a "tty" or
|
||||
/// "console" window. That is, the output would be displayed to the user
|
||||
/// rather than being put on a pipe or stored in a file.
|
||||
virtual bool is_displayed() const { return false; }
|
||||
|
||||
/// This function determines if this stream is displayed and supports colors.
|
||||
/// The result is unaffected by calls to enable_color().
|
||||
virtual bool has_colors() const { return is_displayed(); }
|
||||
|
||||
// Enable or disable colors. Once enable_colors(false) is called,
|
||||
// changeColor() has no effect until enable_colors(true) is called.
|
||||
virtual void enable_colors(bool /*enable*/) {}
|
||||
|
||||
/// Tie this stream to the specified stream. Replaces any existing tied-to
|
||||
/// stream. Specifying a nullptr unties the stream.
|
||||
void tie(raw_ostream *TieTo) { TiedStream = TieTo; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Subclass Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
private:
|
||||
/// The is the piece of the class that is implemented by subclasses. This
|
||||
/// writes the \p Size bytes starting at
|
||||
/// \p Ptr to the underlying stream.
|
||||
///
|
||||
/// This function is guaranteed to only be called at a point at which it is
|
||||
/// safe for the subclass to install a new buffer via SetBuffer.
|
||||
///
|
||||
/// \param Ptr The start of the data to be written. For buffered streams this
|
||||
/// is guaranteed to be the start of the buffer.
|
||||
///
|
||||
/// \param Size The number of bytes to be written.
|
||||
///
|
||||
/// \invariant { Size > 0 }
|
||||
virtual void write_impl(const char *Ptr, size_t Size) = 0;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
virtual uint64_t current_pos() const = 0;
|
||||
|
||||
protected:
|
||||
/// Use the provided buffer as the raw_ostream buffer. This is intended for
|
||||
/// use only by subclasses which can arrange for the output to go directly
|
||||
/// into the desired output buffer, instead of being copied on each flush.
|
||||
void SetBuffer(char *BufferStart, size_t Size) {
|
||||
SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
|
||||
}
|
||||
|
||||
/// Return an efficient buffer size for the underlying output mechanism.
|
||||
virtual size_t preferred_buffer_size() const;
|
||||
|
||||
/// Return the beginning of the current stream buffer, or 0 if the stream is
|
||||
/// unbuffered.
|
||||
const char *getBufferStart() const { return OutBufStart; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Private Interface
|
||||
//===--------------------------------------------------------------------===//
|
||||
private:
|
||||
/// Install the given buffer and mode.
|
||||
void SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode);
|
||||
|
||||
/// Flush the current buffer, which is known to be non-empty. This outputs the
|
||||
/// currently buffered data and resets the buffer to empty.
|
||||
void flush_nonempty();
|
||||
|
||||
/// Copy data into the buffer. Size must not be greater than the number of
|
||||
/// unused bytes in the buffer.
|
||||
void copy_to_buffer(const char *Ptr, size_t Size);
|
||||
|
||||
/// Flush the tied-to stream (if present) and then write the required data.
|
||||
void flush_tied_then_write(const char *Ptr, size_t Size);
|
||||
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// Call the appropriate insertion operator, given an rvalue reference to a
|
||||
/// raw_ostream object and return a stream of the same type as the argument.
|
||||
template <typename OStream, typename T>
|
||||
std::enable_if_t<!std::is_reference<OStream>::value &&
|
||||
std::is_base_of<raw_ostream, OStream>::value,
|
||||
OStream &&>
|
||||
operator<<(OStream &&OS, const T &Value) {
|
||||
OS << Value;
|
||||
return std::move(OS);
|
||||
}
|
||||
|
||||
/// An abstract base class for streams implementations that also support a
|
||||
/// pwrite operation. This is useful for code that can mostly stream out data,
|
||||
/// but needs to patch in a header that needs to know the output size.
|
||||
class raw_pwrite_stream : public raw_ostream {
|
||||
virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0;
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
explicit raw_pwrite_stream(bool Unbuffered = false,
|
||||
OStreamKind K = OStreamKind::OK_OStream)
|
||||
: raw_ostream(Unbuffered, K) {}
|
||||
void pwrite(const char *Ptr, size_t Size, uint64_t Offset) {
|
||||
#ifndef NDEBUG
|
||||
uint64_t Pos = tell();
|
||||
// /dev/null always reports a pos of 0, so we cannot perform this check
|
||||
// in that case.
|
||||
if (Pos)
|
||||
assert(Size + Offset <= Pos && "We don't support extending the stream");
|
||||
#endif
|
||||
pwrite_impl(Ptr, Size, Offset);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Output Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream that writes to a file descriptor.
|
||||
///
|
||||
class raw_fd_ostream : public raw_pwrite_stream {
|
||||
int FD;
|
||||
bool ShouldClose;
|
||||
bool SupportsSeeking = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
/// True if this fd refers to a Windows console device. Mintty and other
|
||||
/// terminal emulators are TTYs, but they are not consoles.
|
||||
bool IsWindowsConsole = false;
|
||||
#endif
|
||||
|
||||
std::error_code EC;
|
||||
|
||||
uint64_t pos = 0;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override { return pos; }
|
||||
|
||||
/// Determine an efficient buffer size.
|
||||
size_t preferred_buffer_size() const override;
|
||||
|
||||
void anchor() override;
|
||||
|
||||
protected:
|
||||
/// Set the flag indicating that an output error has been encountered.
|
||||
void error_detected(std::error_code EC) { this->EC = EC; }
|
||||
|
||||
/// Return the file descriptor.
|
||||
int get_fd() const { return FD; }
|
||||
|
||||
// Update the file position by increasing \p Delta.
|
||||
void inc_pos(uint64_t Delta) { pos += Delta; }
|
||||
|
||||
public:
|
||||
/// Open the specified file for writing. If an error occurs, information
|
||||
/// about the error is put into EC, and the stream should be immediately
|
||||
/// destroyed;
|
||||
/// \p Flags allows optional flags to control how the file will be opened.
|
||||
///
|
||||
/// As a special case, if Filename is "-", then the stream will use
|
||||
/// STDOUT_FILENO instead of opening a file. This will not close the stdout
|
||||
/// descriptor.
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::FileAccess Access);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::OpenFlags Flags);
|
||||
raw_fd_ostream(std::string_view Filename, std::error_code &EC,
|
||||
fs::CreationDisposition Disp, fs::FileAccess Access,
|
||||
fs::OpenFlags Flags);
|
||||
|
||||
/// FD is the file descriptor that this writes to. If ShouldClose is true,
|
||||
/// this closes the file when the stream is destroyed. If FD is for stdout or
|
||||
/// stderr, it will not be closed.
|
||||
raw_fd_ostream(int fd, bool shouldClose, bool unbuffered = false,
|
||||
OStreamKind K = OStreamKind::OK_OStream);
|
||||
|
||||
~raw_fd_ostream() override;
|
||||
|
||||
/// Manually flush the stream and close the file. Note that this does not call
|
||||
/// fsync.
|
||||
void close();
|
||||
|
||||
bool supportsSeeking() const { return SupportsSeeking; }
|
||||
|
||||
/// Flushes the stream and repositions the underlying file descriptor position
|
||||
/// to the offset specified from the beginning of the file.
|
||||
uint64_t seek(uint64_t off);
|
||||
|
||||
std::error_code error() const { return EC; }
|
||||
|
||||
/// Return the value of the flag in this raw_fd_ostream indicating whether an
|
||||
/// output error has been encountered.
|
||||
/// This doesn't implicitly flush any pending output. Also, it doesn't
|
||||
/// guarantee to detect all errors unless the stream has been closed.
|
||||
bool has_error() const { return bool(EC); }
|
||||
|
||||
/// Set the flag read by has_error() to false. If the error flag is set at the
|
||||
/// time when this raw_ostream's destructor is called, report_fatal_error is
|
||||
/// called to report the error. Use clear_error() after handling the error to
|
||||
/// avoid this behavior.
|
||||
///
|
||||
/// "Errors should never pass silently.
|
||||
/// Unless explicitly silenced."
|
||||
/// - from The Zen of Python, by Tim Peters
|
||||
///
|
||||
void clear_error() { EC = std::error_code(); }
|
||||
};
|
||||
|
||||
/// This returns a reference to a raw_fd_ostream for standard output. Use it
|
||||
/// like: outs() << "foo" << "bar";
|
||||
raw_fd_ostream &outs();
|
||||
|
||||
/// This returns a reference to a raw_ostream for standard error.
|
||||
/// Use it like: errs() << "foo" << "bar";
|
||||
/// By default, the stream is tied to stdout to ensure stdout is flushed before
|
||||
/// stderr is written, to ensure the error messages are written in their
|
||||
/// expected place.
|
||||
raw_fd_ostream &errs();
|
||||
|
||||
/// This returns a reference to a raw_ostream which simply discards output.
|
||||
raw_ostream &nulls();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// File Streams
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream of a file for reading/writing/seeking.
|
||||
///
|
||||
class raw_fd_stream : public raw_fd_ostream {
|
||||
public:
|
||||
/// Open the specified file for reading/writing/seeking. If an error occurs,
|
||||
/// information about the error is put into EC, and the stream should be
|
||||
/// immediately destroyed.
|
||||
raw_fd_stream(std::string_view Filename, std::error_code &EC);
|
||||
|
||||
/// Check if \p OS is a pointer of type raw_fd_stream*.
|
||||
static bool classof(const raw_ostream *OS);
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Output Stream Adaptors
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A raw_ostream that writes to an std::string. This is a simple adaptor
|
||||
/// class. This class does not encounter output errors.
|
||||
class raw_string_ostream : public raw_ostream {
|
||||
std::string &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override { return OS.size(); }
|
||||
|
||||
public:
|
||||
explicit raw_string_ostream(std::string &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
~raw_string_ostream() override;
|
||||
|
||||
/// Flushes the stream contents to the target string and returns the string's
|
||||
/// reference.
|
||||
std::string& str() {
|
||||
flush();
|
||||
return OS;
|
||||
}
|
||||
|
||||
void reserveExtraSpace(uint64_t ExtraSize) override {
|
||||
OS.reserve(tell() + ExtraSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to an SmallVector or SmallString. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_svector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the SmallString. Thus the SmallString is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_svector_ostream : public raw_pwrite_stream {
|
||||
SmallVectorImpl<char> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_svector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a std::string_view for the vector contents.
|
||||
std::string_view str() const { return std::string_view(OS.data(), OS.size()); }
|
||||
|
||||
void reserveExtraSpace(uint64_t ExtraSize) override {
|
||||
OS.reserve(tell() + ExtraSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to a vector. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_vector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the vector. Thus the vector is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_vector_ostream : public raw_pwrite_stream {
|
||||
std::vector<char> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_vector_ostream(std::vector<char> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_vector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a std::string_view for the vector contents.
|
||||
std::string_view str() { return std::string_view(OS.data(), OS.size()); }
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to an SmallVector or SmallString. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_svector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the SmallString. Thus the SmallString is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_usvector_ostream : public raw_pwrite_stream {
|
||||
SmallVectorImpl<uint8_t> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_usvector_ostream(SmallVectorImpl<uint8_t> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_usvector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return an span for the vector contents.
|
||||
span<uint8_t> array() { return {OS.data(), OS.size()}; }
|
||||
span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
|
||||
};
|
||||
|
||||
/// A raw_ostream that writes to a vector. This is a
|
||||
/// simple adaptor class. This class does not encounter output errors.
|
||||
/// raw_vector_ostream operates without a buffer, delegating all memory
|
||||
/// management to the vector. Thus the vector is always up-to-date,
|
||||
/// may be used directly and there is no need to call flush().
|
||||
class raw_uvector_ostream : public raw_pwrite_stream {
|
||||
std::vector<uint8_t> &OS;
|
||||
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t Size) override;
|
||||
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
/// Construct a new raw_svector_ostream.
|
||||
///
|
||||
/// \param O The vector to write to; this should generally have at least 128
|
||||
/// bytes free to avoid any extraneous memory overhead.
|
||||
explicit raw_uvector_ostream(std::vector<uint8_t> &O) : OS(O) {
|
||||
SetUnbuffered();
|
||||
}
|
||||
|
||||
~raw_uvector_ostream() override = default;
|
||||
|
||||
void flush() = delete;
|
||||
|
||||
/// Return a span for the vector contents.
|
||||
span<uint8_t> array() { return {OS.data(), OS.size()}; }
|
||||
span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
|
||||
};
|
||||
|
||||
|
||||
/// A raw_ostream that discards all output.
|
||||
class raw_null_ostream : public raw_pwrite_stream {
|
||||
/// See raw_ostream::write_impl.
|
||||
void write_impl(const char *Ptr, size_t size) override;
|
||||
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
|
||||
|
||||
/// Return the current position within the stream, not counting the bytes
|
||||
/// currently in the buffer.
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
public:
|
||||
explicit raw_null_ostream() = default;
|
||||
~raw_null_ostream() override;
|
||||
};
|
||||
|
||||
class buffer_ostream : public raw_svector_ostream {
|
||||
raw_ostream &OS;
|
||||
SmallVector<char, 0> Buffer;
|
||||
|
||||
virtual void anchor() override;
|
||||
|
||||
public:
|
||||
buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
|
||||
~buffer_ostream() override { OS << str(); }
|
||||
};
|
||||
|
||||
class buffer_unique_ostream : public raw_svector_ostream {
|
||||
std::unique_ptr<raw_ostream> OS;
|
||||
SmallVector<char, 0> Buffer;
|
||||
|
||||
virtual void anchor() override;
|
||||
|
||||
public:
|
||||
buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
|
||||
: raw_svector_ostream(Buffer), OS(std::move(OS)) {}
|
||||
~buffer_unique_ostream() override { *OS << str(); }
|
||||
};
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_RAW_OSTREAM_H
|
||||
104
wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
vendored
Normal file
104
wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides useful additions to the standard type_traits library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
#define WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
|
||||
#include "wpi/Compiler.h"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
|
||||
/// Metafunction that determines whether the given type is either an
|
||||
/// integral type or an enumeration type, including enum classes.
|
||||
///
|
||||
/// Note that this accepts potentially more integral types than is_integral
|
||||
/// because it is based on being implicitly convertible to an integral type.
|
||||
/// Also note that enum classes aren't implicitly convertible to integral types,
|
||||
/// the value may therefore need to be explicitly converted before being used.
|
||||
template <typename T> class is_integral_or_enum {
|
||||
using UnderlyingT = std::remove_reference_t<T>;
|
||||
|
||||
public:
|
||||
static const bool value =
|
||||
!std::is_class<UnderlyingT>::value && // Filter conversion operators.
|
||||
!std::is_pointer<UnderlyingT>::value &&
|
||||
!std::is_floating_point<UnderlyingT>::value &&
|
||||
(std::is_enum<UnderlyingT>::value ||
|
||||
std::is_convertible<UnderlyingT, unsigned long long>::value);
|
||||
};
|
||||
|
||||
/// If T is a pointer, just return it. If it is not, return T&.
|
||||
template<typename T, typename Enable = void>
|
||||
struct add_lvalue_reference_if_not_pointer { using type = T &; };
|
||||
|
||||
template <typename T>
|
||||
struct add_lvalue_reference_if_not_pointer<
|
||||
T, std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
/// If T is a pointer to X, return a pointer to const X. If it is not,
|
||||
/// return const T.
|
||||
template<typename T, typename Enable = void>
|
||||
struct add_const_past_pointer { using type = const T; };
|
||||
|
||||
template <typename T>
|
||||
struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
using type = const std::remove_pointer_t<T> *;
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct const_pointer_or_const_ref {
|
||||
using type = const T &;
|
||||
};
|
||||
template <typename T>
|
||||
struct const_pointer_or_const_ref<T,
|
||||
std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
using type = typename add_const_past_pointer<T>::type;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/// Internal utility to detect trivial copy construction.
|
||||
template<typename T> union copy_construction_triviality_helper {
|
||||
T t;
|
||||
copy_construction_triviality_helper() = default;
|
||||
copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
|
||||
~copy_construction_triviality_helper() = default;
|
||||
};
|
||||
/// Internal utility to detect trivial move construction.
|
||||
template<typename T> union move_construction_triviality_helper {
|
||||
T t;
|
||||
move_construction_triviality_helper() = default;
|
||||
move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
|
||||
~move_construction_triviality_helper() = default;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
union trivial_helper {
|
||||
T t;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template <typename T>
|
||||
using is_trivially_move_constructible = std::is_trivially_move_constructible<T>;
|
||||
|
||||
template <typename T>
|
||||
using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
|
||||
|
||||
|
||||
} // end namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_TYPE_TRAITS_H
|
||||
Reference in New Issue
Block a user