[wpiutil] Vendor llvm and update to 13.0.0 (#4224)

This commit is contained in:
PJ Reiniger
2022-05-20 18:59:53 -04:00
committed by GitHub
parent 5aa67f56e6
commit c3b223ce60
106 changed files with 16897 additions and 1895 deletions

View File

@@ -88,12 +88,247 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==============================================================================
LLVM Release License
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.
==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign.
Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:

View File

@@ -0,0 +1,39 @@
From 4f34f83152a851ce675c876f3bd0e53322110d04 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 20:50:26 -0400
Subject: [PATCH 01/31] Fix spelling / language errors
---
llvm/include/llvm/Support/Chrono.h | 2 +-
llvm/include/llvm/Support/ErrorHandling.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Support/Chrono.h b/llvm/include/llvm/Support/Chrono.h
index f478549a7e4e..004519a883fd 100644
--- a/llvm/include/llvm/Support/Chrono.h
+++ b/llvm/include/llvm/Support/Chrono.h
@@ -22,7 +22,7 @@ class raw_ostream;
namespace sys {
/// A time point on the system clock. This is provided for two reasons:
-/// - to insulate us agains subtle differences in behavoir to differences in
+/// - 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
diff --git a/llvm/include/llvm/Support/ErrorHandling.h b/llvm/include/llvm/Support/ErrorHandling.h
index 0ec0242d569d..dd85a5892e01 100644
--- a/llvm/include/llvm/Support/ErrorHandling.h
+++ b/llvm/include/llvm/Support/ErrorHandling.h
@@ -45,7 +45,7 @@ class StringRef;
void install_fatal_error_handler(fatal_error_handler_t handler,
void *user_data = nullptr);
- /// Restores default error handling behaviour.
+ /// Restores default error handling behavior.
void remove_fatal_error_handler();
/// ScopedFatalErrorHandler - This is a simple helper class which just
--
2.20.1.windows.1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
From 81df3d81b0bffd848890d7c01d946e65744fb649 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 22:12:41 -0400
Subject: [PATCH 03/31] Wrap std::min/max calls in parens, for windows warnings
---
llvm/include/llvm/ADT/DenseMap.h | 4 ++--
llvm/include/llvm/ADT/DenseMapInfo.h | 2 +-
llvm/include/llvm/ADT/SmallVector.h | 12 ++++++------
llvm/include/llvm/Support/ConvertUTF.h | 2 +-
llvm/include/llvm/Support/MathExtras.h | 22 +++++++++++-----------
llvm/lib/Support/SmallVector.cpp | 2 +-
6 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index 595eabd0ffb4..588c39faea2f 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -389,7 +389,7 @@ protected:
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);
+ return static_cast<unsigned>(NextPowerOf2(NumEntries * 4 / 3 + 1));
}
void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
@@ -825,7 +825,7 @@ public:
// Reduce the number of buckets.
unsigned NewNumBuckets = 0;
if (OldNumEntries)
- NewNumBuckets = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1));
+ NewNumBuckets = (std::max)(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1));
if (NewNumBuckets == NumBuckets) {
this->BaseT::initEmpty();
return;
diff --git a/llvm/include/llvm/ADT/DenseMapInfo.h b/llvm/include/llvm/ADT/DenseMapInfo.h
index d276acbfa6a6..0040ac36217e 100644
--- a/llvm/include/llvm/ADT/DenseMapInfo.h
+++ b/llvm/include/llvm/ADT/DenseMapInfo.h
@@ -285,7 +285,7 @@ template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
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 val; }
+ static unsigned getHashValue(hash_code val) { return static_cast<unsigned>(val); }
static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; }
};
diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h
index b8a11030fc33..602fcc5b7a98 100644
--- a/llvm/include/llvm/ADT/SmallVector.h
+++ b/llvm/include/llvm/ADT/SmallVector.h
@@ -49,12 +49,12 @@ protected:
/// The maximum value of the Size_T used.
static constexpr size_t SizeTypeMax() {
- return std::numeric_limits<Size_T>::max();
+ return (std::numeric_limits<Size_T>::max)();
}
SmallVectorBase() = delete;
SmallVectorBase(void *FirstEl, size_t TotalCapacity)
- : BeginX(FirstEl), Capacity(TotalCapacity) {}
+ : BeginX(FirstEl), Capacity(static_cast<unsigned>(TotalCapacity)) {}
/// This is a helper for \a grow() that's out of line to reduce code
/// duplication. This function will report a fatal error if it can't grow at
@@ -83,7 +83,7 @@ public:
/// which will only be overwritten.
void set_size(size_t N) {
assert(N <= capacity());
- Size = N;
+ Size = static_cast<unsigned>(N);
}
};
@@ -263,7 +263,7 @@ public:
size_type size_in_bytes() const { return size() * sizeof(T); }
size_type max_size() const {
- return std::min(this->SizeTypeMax(), size_type(-1) / sizeof(T));
+ return (std::min)(this->SizeTypeMax(), size_type(-1) / sizeof(T));
}
size_t capacity_in_bytes() const { return capacity() * sizeof(T); }
@@ -448,7 +448,7 @@ void SmallVectorTemplateBase<T, TriviallyCopyable>::takeAllocationForGrow(
free(this->begin());
this->BeginX = NewElts;
- this->Capacity = NewCapacity;
+ this->Capacity = static_cast<unsigned>(NewCapacity);
}
/// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put
@@ -674,7 +674,7 @@ public:
}
// Assign over existing elements.
- std::fill_n(this->begin(), std::min(NumElts, this->size()), Elt);
+ std::fill_n(this->begin(), (std::min)(NumElts, this->size()), Elt);
if (NumElts > this->size())
std::uninitialized_fill_n(this->end(), NumElts - this->size(), Elt);
else if (NumElts < this->size())
diff --git a/llvm/include/llvm/Support/ConvertUTF.h b/llvm/include/llvm/Support/ConvertUTF.h
index 7f1527f51cdf..b085c8a179e8 100644
--- a/llvm/include/llvm/Support/ConvertUTF.h
+++ b/llvm/include/llvm/Support/ConvertUTF.h
@@ -112,7 +112,7 @@ namespace llvm {
typedef unsigned int UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
-typedef unsigned char Boolean; /* 0 or 1 */
+typedef bool Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index 753b1998c40c..db9fbc148ae3 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -97,7 +97,7 @@ template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
// Bisection method.
unsigned ZeroBits = 0;
T Shift = std::numeric_limits<T>::digits >> 1;
- T Mask = std::numeric_limits<T>::max() >> Shift;
+ T Mask = (std::numeric_limits<T>::max)() >> Shift;
while (Shift) {
if ((Val & Mask) == 0) {
Val >>= Shift;
@@ -238,7 +238,7 @@ unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
/// 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 (std::numeric_limits<T>::max)();
return countTrailingZeros(Val, ZB_Undefined);
}
@@ -279,7 +279,7 @@ template <typename T> T maskLeadingZeros(unsigned N) {
/// 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();
+ 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.
@@ -594,26 +594,26 @@ inline double Log2(double Value) {
/// (32 bit edition.)
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
inline unsigned Log2_32(uint32_t Value) {
- return 31 - countLeadingZeros(Value);
+ 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 63 - countLeadingZeros(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 32 - countLeadingZeros(Value - 1);
+ 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 64 - countLeadingZeros(Value - 1);
+ return static_cast<unsigned>(64 - countLeadingZeros(Value - 1));
}
/// Return the greatest common divisor of the values using Euclid's algorithm.
@@ -807,7 +807,7 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
T Z = X + Y;
Overflowed = (Z < X || Z < Y);
if (Overflowed)
- return std::numeric_limits<T>::max();
+ return (std::numeric_limits<T>::max)();
else
return Z;
}
@@ -832,7 +832,7 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
// 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();
+ const T Max = (std::numeric_limits<T>::max)();
int Log2Max = Log2_64(Max);
if (Log2Z < Log2Max) {
return X * Y;
@@ -952,9 +952,9 @@ std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) {
// 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;
+ 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;
+ return UX > (static_cast<U>((std::numeric_limits<T>::max)())) / UY;
}
} // End llvm namespace
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp
index 0005f7840912..26901fe97d20 100644
--- a/llvm/lib/Support/SmallVector.cpp
+++ b/llvm/lib/Support/SmallVector.cpp
@@ -95,7 +95,7 @@ static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
// 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);
+ return (std::min)((std::max)(NewCapacity, MinSize), MaxSize);
}
// Note: Moving this function into the header may cause performance regression.
--
2.20.1.windows.1

View File

@@ -0,0 +1,34 @@
From 086a4a7ee635c68d81b85044c9f8f4317b2b164c Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 22:13:55 -0400
Subject: [PATCH 04/31] Change uniqe_function storage size
---
llvm/include/llvm/ADT/FunctionExtras.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/ADT/FunctionExtras.h b/llvm/include/llvm/ADT/FunctionExtras.h
index e67ef7377c88..1a26cb702cae 100644
--- a/llvm/include/llvm/ADT/FunctionExtras.h
+++ b/llvm/include/llvm/ADT/FunctionExtras.h
@@ -72,7 +72,7 @@ using EnableIfCallable =
template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
protected:
- static constexpr size_t InlineStorageSize = sizeof(void *) * 3;
+ static constexpr size_t InlineStorageSize = sizeof(void *) * 4;
template <typename T, class = void>
struct IsSizeLessThanThresholdT : std::false_type {};
@@ -151,7 +151,7 @@ protected:
"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 three pointers worth of storage here.
+ // 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
--
2.20.1.windows.1

View File

@@ -0,0 +1,188 @@
From a53483a33c8d5778e5594a49376b5bafe742d126 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 22:17:19 -0400
Subject: [PATCH 05/31] Threading updates
- Remove guards for threads and exception
- Prefer scope gaurd over lock gaurd
---
llvm/include/llvm/Support/Compiler.h | 6 -----
llvm/lib/Support/ErrorHandling.cpp | 38 +++++-----------------------
llvm/lib/Support/ManagedStatic.cpp | 10 ++++----
3 files changed, 11 insertions(+), 43 deletions(-)
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index f4d6612fe074..989d25bb03b9 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -525,7 +525,6 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
/// 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 LLVM_ENABLE_THREADS
#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
#define LLVM_THREAD_LOCAL thread_local
#else
@@ -533,11 +532,6 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
// we only need the restricted functionality that provides.
#define LLVM_THREAD_LOCAL __thread
#endif
-#else // !LLVM_ENABLE_THREADS
-// If threading is disabled entirely, this compiles to nothing and you get
-// a normal global variable.
-#define LLVM_THREAD_LOCAL
-#endif
/// \macro LLVM_ENABLE_EXCEPTIONS
/// Whether LLVM is built with exception support.
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index 19d1fd77af12..2403db9c80f1 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -44,7 +44,6 @@ static void *ErrorHandlerUserData = nullptr;
static fatal_error_handler_t BadAllocErrorHandler = nullptr;
static void *BadAllocErrorHandlerUserData = nullptr;
-#if LLVM_ENABLE_THREADS == 1
// 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.
@@ -58,22 +57,17 @@ static void *BadAllocErrorHandlerUserData = nullptr;
// builds. We can remove these ifdefs if that script goes away.
static std::mutex ErrorHandlerMutex;
static std::mutex BadAllocErrorHandlerMutex;
-#endif
void llvm::install_fatal_error_handler(fatal_error_handler_t handler,
void *user_data) {
-#if LLVM_ENABLE_THREADS == 1
- std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
-#endif
+ std::scoped_lock Lock(ErrorHandlerMutex);
assert(!ErrorHandler && "Error handler already registered!\n");
ErrorHandler = handler;
ErrorHandlerUserData = user_data;
}
void llvm::remove_fatal_error_handler() {
-#if LLVM_ENABLE_THREADS == 1
- std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
-#endif
+ std::scoped_lock Lock(ErrorHandlerMutex);
ErrorHandler = nullptr;
ErrorHandlerUserData = nullptr;
}
@@ -92,9 +86,7 @@ void llvm::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
{
// Only acquire the mutex while reading the handler, so as not to invoke a
// user-supplied callback under a lock.
-#if LLVM_ENABLE_THREADS == 1
- std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
-#endif
+ std::scoped_lock Lock(ErrorHandlerMutex);
handler = ErrorHandler;
handlerData = ErrorHandlerUserData;
}
@@ -123,18 +115,14 @@ void llvm::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
void *user_data) {
-#if LLVM_ENABLE_THREADS == 1
- std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
-#endif
+ std::scoped_lock Lock(BadAllocErrorHandlerMutex);
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
BadAllocErrorHandler = handler;
BadAllocErrorHandlerUserData = user_data;
}
void llvm::remove_bad_alloc_error_handler() {
-#if LLVM_ENABLE_THREADS == 1
- std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
-#endif
+ std::scoped_lock Lock(BadAllocErrorHandlerMutex);
BadAllocErrorHandler = nullptr;
BadAllocErrorHandlerUserData = nullptr;
}
@@ -145,9 +133,7 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
{
// Only acquire the mutex while reading the handler, so as not to invoke a
// user-supplied callback under a lock.
-#if LLVM_ENABLE_THREADS == 1
- std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
-#endif
+ std::scoped_lock Lock(BadAllocErrorHandlerMutex);
Handler = BadAllocErrorHandler;
HandlerData = BadAllocErrorHandlerUserData;
}
@@ -157,10 +143,6 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
llvm_unreachable("bad alloc handler should not return");
}
-#ifdef LLVM_ENABLE_EXCEPTIONS
- // If exceptions are enabled, make OOM in malloc look like OOM in new.
- throw std::bad_alloc();
-#else
// 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";
@@ -169,15 +151,8 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
(void)!::write(2, Reason, strlen(Reason));
(void)!::write(2, Newline, strlen(Newline));
abort();
-#endif
}
-#ifdef LLVM_ENABLE_EXCEPTIONS
-// Do not set custom new handler if exceptions are enabled. In this case OOM
-// errors are handled by throwing 'std::bad_alloc'.
-void llvm::install_out_of_memory_new_handler() {
-}
-#else
// 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() {
@@ -192,7 +167,6 @@ void llvm::install_out_of_memory_new_handler() {
assert((old == nullptr || old == out_of_memory_new_handler) &&
"new-handler already installed");
}
-#endif
void llvm::llvm_unreachable_internal(const char *msg, const char *file,
unsigned line) {
diff --git a/llvm/lib/Support/ManagedStatic.cpp b/llvm/lib/Support/ManagedStatic.cpp
index a6ae67066ea0..fc798b7ec1b7 100644
--- a/llvm/lib/Support/ManagedStatic.cpp
+++ b/llvm/lib/Support/ManagedStatic.cpp
@@ -12,23 +12,23 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Config/config.h"
-#include "llvm/Support/Threading.h"
+#include "llvm/Support/mutex.h"
#include <cassert>
#include <mutex>
using namespace llvm;
static const ManagedStaticBase *StaticList = nullptr;
-static std::recursive_mutex *getManagedStaticMutex() {
- static std::recursive_mutex m;
+static llvm::mutex *getManagedStaticMutex() {
+ static llvm::mutex m;
return &m;
}
void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
void (*Deleter)(void*)) const {
assert(Creator);
- if (llvm_is_multithreaded()) {
- std::lock_guard<std::recursive_mutex> Lock(*getManagedStaticMutex());
+ if (1) {
+ std::scoped_lock Lock(*getManagedStaticMutex());
if (!Ptr.load(std::memory_order_relaxed)) {
void *Tmp = Creator();
--
2.20.1.windows.1

View File

@@ -0,0 +1,62 @@
From 04f1186ea8f0160da1a1863a344ff9a9f55b6733 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 22:24:34 -0400
Subject: [PATCH 06/31] Remove DJB hash dependency
---
llvm/lib/Support/StringMap.cpp | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Support/StringMap.cpp b/llvm/lib/Support/StringMap.cpp
index d9eeba619428..f0d5ae6de646 100644
--- a/llvm/lib/Support/StringMap.cpp
+++ b/llvm/lib/Support/StringMap.cpp
@@ -12,11 +12,26 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/DJB.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/MathExtras.h"
using namespace llvm;
+/// HashString - Hash function for strings.
+///
+/// This is the Bernstein hash function.
+//
+// FIXME: Investigate whether a modified bernstein hash function performs
+// better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
+// X*33+c -> X*33^c
+static inline unsigned HashString(std::string_view str,
+ unsigned result = 0) noexcept {
+ for (std::string_view::size_type i = 0, e = str.size(); i != e; ++i) {
+ result = result * 33 + static_cast<unsigned char>(str[i]);
+ }
+ return result;
+}
+
/// 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) {
@@ -77,7 +92,7 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
init(16);
HTSize = NumBuckets;
}
- unsigned FullHashValue = djbHash(Name, 0);
+ unsigned FullHashValue = HashString(Name);
unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
@@ -133,7 +148,7 @@ 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 FullHashValue = HashString(Key);
unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
--
2.20.1.windows.1

View File

@@ -0,0 +1,354 @@
From d16ac9833a8469fe49b564ad21e2331875b450b8 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 22:28:13 -0400
Subject: [PATCH 07/31] #ifdef guard safety
Prevents redefinition if someone is pulling in real LLVM, since the macros are in global namespace
---
llvm/include/llvm/Support/Compiler.h | 54 ++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index 989d25bb03b9..14f95ae8cc52 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -80,6 +80,7 @@
/// * 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))
@@ -91,28 +92,33 @@
#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
@@ -132,21 +138,26 @@
#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)
@@ -160,6 +171,7 @@
#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
@@ -182,11 +194,13 @@
// 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)) && \
@@ -196,6 +210,7 @@
#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__)
@@ -204,14 +219,18 @@
#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)
@@ -219,9 +238,11 @@
#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)
@@ -229,11 +250,13 @@
#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)
@@ -241,7 +264,9 @@
#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)
@@ -249,7 +274,9 @@
#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)
@@ -257,9 +284,11 @@
#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)
@@ -267,8 +296,10 @@
#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)
@@ -280,6 +311,7 @@
#else
#define LLVM_FALLTHROUGH
#endif
+#endif
/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
/// they are constant initialized.
@@ -308,28 +340,35 @@
/// 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)
@@ -341,10 +380,12 @@
#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)
@@ -358,9 +399,11 @@
// 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)
@@ -369,6 +412,7 @@
#else
# define LLVM_ASSUME_ALIGNED(p, a) (p)
#endif
+#endif
/// \macro LLVM_PACKED
/// Used to specify a packed structure.
@@ -388,6 +432,7 @@
/// 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))
@@ -397,11 +442,13 @@
# 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)
@@ -413,6 +460,7 @@
#else
# define LLVM_PTR_SIZE sizeof(void *)
#endif
+#endif
/// \macro LLVM_MEMORY_SANITIZER_BUILD
/// Whether LLVM itself is built with MemorySanitizer instrumentation.
@@ -483,11 +531,13 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
/// \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.
@@ -495,17 +545,20 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
/// `#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__)
@@ -513,6 +566,7 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#else
#define LLVM_PRETTY_FUNCTION __func__
#endif
+#endif
/// \macro LLVM_THREAD_LOCAL
/// A thread-local storage specifier which can be used with globals,
--
2.20.1.windows.1

View File

@@ -0,0 +1,81 @@
From 945a1d5a54ad830f857625417da414d05d367a37 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 22:37:34 -0400
Subject: [PATCH 08/31] Explicitly use std::
---
llvm/include/llvm/ADT/SmallSet.h | 2 +-
llvm/include/llvm/Support/MathExtras.h | 2 +-
llvm/lib/Support/ErrorHandling.cpp | 2 +-
llvm/unittests/ADT/SmallPtrSetTest.cpp | 2 +-
llvm/unittests/ADT/StringMapTest.cpp | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/ADT/SmallSet.h b/llvm/include/llvm/ADT/SmallSet.h
index e4c209c5f2a9..f2b402ccf9a0 100644
--- a/llvm/include/llvm/ADT/SmallSet.h
+++ b/llvm/include/llvm/ADT/SmallSet.h
@@ -269,7 +269,7 @@ bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
return false;
// All elements in LHS must also be in RHS
- return all_of(LHS, [&RHS](const T &E) { return RHS.count(E); });
+ return std::all_of(LHS.begin(), LHS.end(), [&RHS](const T &E) { return RHS.count(E); });
}
/// Inequality comparison for SmallSet.
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index db9fbc148ae3..da843ef79ff9 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -586,7 +586,7 @@ inline double Log2(double Value) {
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
return __builtin_log(Value) / __builtin_log(2.0);
#else
- return log2(Value);
+ return std::log2(Value);
#endif
}
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index 2403db9c80f1..9c0c6fb868f2 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -210,7 +210,7 @@ void LLVMResetFatalErrorHandler() {
// I'd rather not double the line count of the following.
#define MAP_ERR_TO_COND(x, y) \
case x: \
- return make_error_code(errc::y)
+ return std::make_error_code(std::errc::y)
std::error_code llvm::mapWindowsError(unsigned EV) {
switch (EV) {
diff --git a/llvm/unittests/ADT/SmallPtrSetTest.cpp b/llvm/unittests/ADT/SmallPtrSetTest.cpp
index 6f3c94eed273..531f81ab5b3f 100644
--- a/llvm/unittests/ADT/SmallPtrSetTest.cpp
+++ b/llvm/unittests/ADT/SmallPtrSetTest.cpp
@@ -298,7 +298,7 @@ TEST(SmallPtrSetTest, dereferenceAndIterate) {
// Sort. We should hit the first element just once and the final element N
// times.
- llvm::sort(std::begin(Found), std::end(Found));
+ std::sort(std::begin(Found), std::end(Found));
for (auto F = std::begin(Found), E = std::end(Found); F != E; ++F)
EXPECT_EQ(F - Found + 1, *F);
}
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
index 4c4aec2184b7..5211f01bbd73 100644
--- a/llvm/unittests/ADT/StringMapTest.cpp
+++ b/llvm/unittests/ADT/StringMapTest.cpp
@@ -308,7 +308,7 @@ TEST_F(StringMapTest, IterMapKeys) {
Map["D"] = 3;
auto Keys = to_vector<4>(Map.keys());
- llvm::sort(Keys);
+ std::sort(Keys.begin(), Keys.end());
SmallVector<std::string_view, 4> Expected = {"A", "B", "C", "D"};
EXPECT_EQ(Expected, Keys);
--
2.20.1.windows.1

View File

@@ -0,0 +1,234 @@
From 1f42fe3358dc55b9686d9c2dd0725dd7e4a14efa Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 22:53:50 -0400
Subject: [PATCH 09/31] Remove format_provider
---
llvm/include/llvm/Support/Chrono.h | 109 ------------------------
llvm/include/llvm/Support/raw_ostream.h | 5 --
llvm/unittests/Support/Chrono.cpp | 61 -------------
3 files changed, 175 deletions(-)
diff --git a/llvm/include/llvm/Support/Chrono.h b/llvm/include/llvm/Support/Chrono.h
index 2c2869de49b6..06829d1fbe14 100644
--- a/llvm/include/llvm/Support/Chrono.h
+++ b/llvm/include/llvm/Support/Chrono.h
@@ -10,7 +10,6 @@
#define LLVM_SUPPORT_CHRONO_H
#include "llvm/Support/Compiler.h"
-#include "llvm/Support/FormatProviders.h"
#include <chrono>
#include <ctime>
@@ -58,114 +57,6 @@ toTimePoint(std::time_t T, uint32_t nsec) {
raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
-/// Format provider for TimePoint<>
-///
-/// The options string is a strftime format string, with extensions:
-/// - %L is millis: 000-999
-/// - %f is micros: 000000-999999
-/// - %N is nanos: 000000000 - 999999999
-///
-/// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N".
-template <>
-struct format_provider<sys::TimePoint<>> {
- static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS,
- std::string_view Style);
-};
-
-namespace detail {
-template <typename Period> struct unit { static const char value[]; };
-template <typename Period> const char unit<Period>::value[] = "";
-
-template <> struct unit<std::ratio<3600>> { static const char value[]; };
-template <> struct unit<std::ratio<60>> { static const char value[]; };
-template <> struct unit<std::ratio<1>> { static const char value[]; };
-template <> struct unit<std::milli> { static const char value[]; };
-template <> struct unit<std::micro> { static const char value[]; };
-template <> struct unit<std::nano> { static const char value[]; };
-} // namespace detail
-
-/// Implementation of format_provider<T> for duration types.
-///
-/// The options string of a duration type has the grammar:
-///
-/// duration_options ::= [unit][show_unit [number_options]]
-/// unit ::= `h`|`m`|`s`|`ms|`us`|`ns`
-/// show_unit ::= `+` | `-`
-/// number_options ::= options string for a integral or floating point type
-///
-/// Examples
-/// =================================
-/// | options | Input | Output |
-/// =================================
-/// | "" | 1s | 1 s |
-/// | "ms" | 1s | 1000 ms |
-/// | "ms-" | 1s | 1000 |
-/// | "ms-n" | 1s | 1,000 |
-/// | "" | 1.0s | 1.00 s |
-/// =================================
-///
-/// If the unit of the duration type is not one of the units specified above,
-/// it is still possible to format it, provided you explicitly request a
-/// display unit or you request that the unit is not displayed.
-
-template <typename Rep, typename Period>
-struct format_provider<std::chrono::duration<Rep, Period>> {
-private:
- typedef std::chrono::duration<Rep, Period> Dur;
- typedef std::conditional_t<std::chrono::treat_as_floating_point<Rep>::value,
- double, intmax_t>
- InternalRep;
-
- template <typename AsPeriod> static InternalRep getAs(const Dur &D) {
- using namespace std::chrono;
- return duration_cast<duration<InternalRep, AsPeriod>>(D).count();
- }
-
- static std::pair<InternalRep, std::string_view> consumeUnit(std::string_view &Style,
- const Dur &D) {
- using namespace std::chrono;
- if (Style.consume_front("ns"))
- return {getAs<std::nano>(D), "ns"};
- if (Style.consume_front("us"))
- return {getAs<std::micro>(D), "us"};
- if (Style.consume_front("ms"))
- return {getAs<std::milli>(D), "ms"};
- if (Style.consume_front("s"))
- return {getAs<std::ratio<1>>(D), "s"};
- if (Style.consume_front("m"))
- return {getAs<std::ratio<60>>(D), "m"};
- if (Style.consume_front("h"))
- return {getAs<std::ratio<3600>>(D), "h"};
- return {D.count(), detail::unit<Period>::value};
- }
-
- static bool consumeShowUnit(std::string_view &Style) {
- if (Style.empty())
- return true;
- if (Style.consume_front("-"))
- return false;
- if (Style.consume_front("+"))
- return true;
- assert(0 && "Unrecognised duration format");
- return true;
- }
-
-public:
- static void format(const Dur &D, llvm::raw_ostream &Stream, std::string_view Style) {
- InternalRep count;
- std::string_view unit;
- std::tie(count, unit) = consumeUnit(Style, D);
- bool show_unit = consumeShowUnit(Style);
-
- format_provider<InternalRep>::format(count, Stream, Style);
-
- if (show_unit) {
- assert(!unit.empty());
- Stream << " " << unit;
- }
- }
-};
-
} // namespace llvm
#endif // LLVM_SUPPORT_CHRONO_H
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index 4f6ea873304f..94d0ed66eced 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -29,11 +29,6 @@
namespace llvm {
-class formatv_object_base;
-class format_object_base;
-class FormattedString;
-class FormattedNumber;
-class FormattedBytes;
template <class T> class LLVM_NODISCARD Expected;
namespace sys {
diff --git a/llvm/unittests/Support/Chrono.cpp b/llvm/unittests/Support/Chrono.cpp
index 9a08a5c1bfdf..3c049de18c0a 100644
--- a/llvm/unittests/Support/Chrono.cpp
+++ b/llvm/unittests/Support/Chrono.cpp
@@ -30,37 +30,6 @@ TEST(Chrono, TimeTConversion) {
EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
}
-TEST(Chrono, TimePointFormat) {
- using namespace std::chrono;
- struct tm TM {};
- TM.tm_year = 106;
- TM.tm_mon = 0;
- TM.tm_mday = 2;
- TM.tm_hour = 15;
- TM.tm_min = 4;
- TM.tm_sec = 5;
- TM.tm_isdst = -1;
- TimePoint<> T =
- system_clock::from_time_t(mktime(&TM)) + nanoseconds(123456789);
-
- // operator<< uses the format YYYY-MM-DD HH:MM:SS.NNNNNNNNN
- std::string S;
- raw_string_ostream OS(S);
- OS << T;
- EXPECT_EQ("2006-01-02 15:04:05.123456789", OS.str());
-
- // formatv default style matches operator<<.
- EXPECT_EQ("2006-01-02 15:04:05.123456789", formatv("{0}", T).str());
- // formatv supports strftime-style format strings.
- EXPECT_EQ("15:04:05", formatv("{0:%H:%M:%S}", T).str());
- // formatv supports our strftime extensions for sub-second precision.
- EXPECT_EQ("123", formatv("{0:%L}", T).str());
- EXPECT_EQ("123456", formatv("{0:%f}", T).str());
- EXPECT_EQ("123456789", formatv("{0:%N}", T).str());
- // our extensions don't interfere with %% escaping.
- EXPECT_EQ("%foo", formatv("{0:%%foo}", T).str());
-}
-
// Test that toTimePoint and toTimeT can be called with a arguments with varying
// precisions.
TEST(Chrono, ImplicitConversions) {
@@ -78,34 +47,4 @@ TEST(Chrono, ImplicitConversions) {
EXPECT_EQ(TimeT, toTimeT(Nano));
}
-TEST(Chrono, DurationFormat) {
- EXPECT_EQ("1 h", formatv("{0}", hours(1)).str());
- EXPECT_EQ("1 m", formatv("{0}", minutes(1)).str());
- EXPECT_EQ("1 s", formatv("{0}", seconds(1)).str());
- EXPECT_EQ("1 ms", formatv("{0}", milliseconds(1)).str());
- EXPECT_EQ("1 us", formatv("{0}", microseconds(1)).str());
- EXPECT_EQ("1 ns", formatv("{0}", nanoseconds(1)).str());
-
- EXPECT_EQ("1 s", formatv("{0:+}", seconds(1)).str());
- EXPECT_EQ("1", formatv("{0:-}", seconds(1)).str());
-
- EXPECT_EQ("1000 ms", formatv("{0:ms}", seconds(1)).str());
- EXPECT_EQ("1000000 us", formatv("{0:us}", seconds(1)).str());
- EXPECT_EQ("1000", formatv("{0:ms-}", seconds(1)).str());
-
- EXPECT_EQ("1,000 ms", formatv("{0:+n}", milliseconds(1000)).str());
- EXPECT_EQ("0x3e8", formatv("{0:-x}", milliseconds(1000)).str());
- EXPECT_EQ("010", formatv("{0:-3}", milliseconds(10)).str());
- EXPECT_EQ("10,000", formatv("{0:ms-n}", seconds(10)).str());
-
- EXPECT_EQ("1.00 s", formatv("{0}", duration<float>(1)).str());
- EXPECT_EQ("0.123 s", formatv("{0:+3}", duration<float>(0.123f)).str());
- EXPECT_EQ("1.230e-01 s", formatv("{0:+e3}", duration<float>(0.123f)).str());
-
- typedef duration<float, std::ratio<60 * 60 * 24 * 14, 1000000>>
- microfortnights;
- EXPECT_EQ("1.00", formatv("{0:-}", microfortnights(1)).str());
- EXPECT_EQ("1209.60 ms", formatv("{0:ms}", microfortnights(1)).str());
-}
-
} // anonymous namespace
--
2.20.1.windows.1

View File

@@ -0,0 +1,266 @@
From 29e7b322eab2284b434cc270bb36ade7c8a62755 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 23:02:07 -0400
Subject: [PATCH 10/31] Remove reverse iterator
---
llvm/include/llvm/ADT/DenseMap.h | 74 ++++-------------------------
llvm/include/llvm/ADT/SmallPtrSet.h | 21 +-------
2 files changed, 11 insertions(+), 84 deletions(-)
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index 588c39faea2f..5e5c020adf0b 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -76,8 +76,6 @@ public:
// empty buckets.
if (empty())
return end();
- if (shouldReverseIterate<KeyT>())
- return makeIterator(getBucketsEnd() - 1, getBuckets(), *this);
return makeIterator(getBuckets(), getBucketsEnd(), *this);
}
inline iterator end() {
@@ -86,8 +84,6 @@ public:
inline const_iterator begin() const {
if (empty())
return end();
- if (shouldReverseIterate<KeyT>())
- return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this);
return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
}
inline const_iterator end() const {
@@ -150,18 +146,14 @@ public:
iterator find(const_arg_type_t<KeyT> Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeIterator(TheBucket,
- shouldReverseIterate<KeyT>() ? getBuckets()
- : getBucketsEnd(),
+ return makeIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
const_iterator find(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeConstIterator(TheBucket,
- shouldReverseIterate<KeyT>() ? getBuckets()
- : getBucketsEnd(),
+ return makeConstIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
@@ -175,9 +167,7 @@ public:
iterator find_as(const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeIterator(TheBucket,
- shouldReverseIterate<KeyT>() ? getBuckets()
- : getBucketsEnd(),
+ return makeIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
@@ -185,9 +175,7 @@ public:
const_iterator find_as(const LookupKeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeConstIterator(TheBucket,
- shouldReverseIterate<KeyT>() ? getBuckets()
- : getBucketsEnd(),
+ return makeConstIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
@@ -222,20 +210,14 @@ public:
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
- return std::make_pair(makeIterator(TheBucket,
- shouldReverseIterate<KeyT>()
- ? getBuckets()
- : getBucketsEnd(),
+ return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket =
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
- return std::make_pair(makeIterator(TheBucket,
- shouldReverseIterate<KeyT>()
- ? getBuckets()
- : getBucketsEnd(),
+ return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
@@ -247,19 +229,13 @@ public:
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
- return std::make_pair(makeIterator(TheBucket,
- shouldReverseIterate<KeyT>()
- ? getBuckets()
- : getBucketsEnd(),
+ return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
- return std::make_pair(makeIterator(TheBucket,
- shouldReverseIterate<KeyT>()
- ? getBuckets()
- : getBucketsEnd(),
+ return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
@@ -274,20 +250,14 @@ public:
const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return std::make_pair(makeIterator(TheBucket,
- shouldReverseIterate<KeyT>()
- ? getBuckets()
- : getBucketsEnd(),
+ return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
- return std::make_pair(makeIterator(TheBucket,
- shouldReverseIterate<KeyT>()
- ? getBuckets()
- : getBucketsEnd(),
+ return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
@@ -464,20 +434,12 @@ private:
iterator makeIterator(BucketT *P, BucketT *E,
DebugEpochBase &Epoch,
bool NoAdvance=false) {
- if (shouldReverseIterate<KeyT>()) {
- BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
- return iterator(B, E, Epoch, NoAdvance);
- }
return iterator(P, E, Epoch, NoAdvance);
}
const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
const DebugEpochBase &Epoch,
const bool NoAdvance=false) const {
- if (shouldReverseIterate<KeyT>()) {
- const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
- return const_iterator(B, E, Epoch, NoAdvance);
- }
return const_iterator(P, E, Epoch, NoAdvance);
}
@@ -1214,10 +1176,6 @@ public:
assert(isHandleInSync() && "invalid construction!");
if (NoAdvance) return;
- if (shouldReverseIterate<KeyT>()) {
- RetreatPastEmptyBuckets();
- return;
- }
AdvancePastEmptyBuckets();
}
@@ -1232,16 +1190,10 @@ public:
reference operator*() const {
assert(isHandleInSync() && "invalid iterator access!");
- assert(Ptr != End && "dereferencing end() iterator");
- if (shouldReverseIterate<KeyT>())
- return Ptr[-1];
return *Ptr;
}
pointer operator->() const {
assert(isHandleInSync() && "invalid iterator access!");
- assert(Ptr != End && "dereferencing end() iterator");
- if (shouldReverseIterate<KeyT>())
- return &(Ptr[-1]);
return Ptr;
}
@@ -1261,12 +1213,6 @@ public:
inline DenseMapIterator& operator++() { // Preincrement
assert(isHandleInSync() && "invalid iterator access!");
- assert(Ptr != End && "incrementing end() iterator");
- if (shouldReverseIterate<KeyT>()) {
- --Ptr;
- RetreatPastEmptyBuckets();
- return *this;
- }
++Ptr;
AdvancePastEmptyBuckets();
return *this;
diff --git a/llvm/include/llvm/ADT/SmallPtrSet.h b/llvm/include/llvm/ADT/SmallPtrSet.h
index 981b741669b0..e46a5171e301 100644
--- a/llvm/include/llvm/ADT/SmallPtrSet.h
+++ b/llvm/include/llvm/ADT/SmallPtrSet.h
@@ -226,10 +226,6 @@ protected:
public:
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
: Bucket(BP), End(E) {
- if (shouldReverseIterate()) {
- RetreatIfNotValid();
- return;
- }
AdvanceIfNotValid();
}
@@ -281,22 +277,11 @@ public:
// 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;
@@ -400,8 +385,6 @@ public:
}
iterator begin() const {
- if (shouldReverseIterate())
- return makeIterator(EndPointer() - 1);
return makeIterator(CurArray);
}
iterator end() const { return makeIterator(EndPointer()); }
@@ -409,9 +392,7 @@ public:
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);
+ return iterator(P, EndPointer());
}
};
--
2.20.1.windows.1

View File

@@ -0,0 +1,237 @@
From be653ec8d4b0a5944fcf084a911389cb0c5cc205 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 23:07:38 -0400
Subject: [PATCH 11/31] Remove allocator from collections
---
llvm/include/llvm/ADT/StringMap.h | 33 +++++++-------------------
llvm/include/llvm/ADT/StringMapEntry.h | 25 +++++++------------
llvm/unittests/ADT/StringMapTest.cpp | 14 +++++------
3 files changed, 23 insertions(+), 49 deletions(-)
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
index 5f463cfef943..3b40bba37f58 100644
--- a/llvm/include/llvm/ADT/StringMap.h
+++ b/llvm/include/llvm/ADT/StringMap.h
@@ -104,10 +104,8 @@ public:
/// 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>
+template<typename ValueTy>
class StringMap : public StringMapImpl {
- AllocatorTy Allocator;
-
public:
using MapEntryTy = StringMapEntry<ValueTy>;
@@ -116,14 +114,6 @@ public:
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) {
@@ -132,11 +122,10 @@ public:
}
StringMap(StringMap &&RHS)
- : StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
+ : StringMapImpl(std::move(RHS)) {}
- StringMap(const StringMap &RHS)
- : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
- Allocator(RHS.Allocator) {
+ StringMap(const StringMap &RHS) :
+ StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
if (RHS.empty())
return;
@@ -156,7 +145,7 @@ public:
}
TheTable[I] = MapEntryTy::Create(
- static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
+ static_cast<MapEntryTy *>(Bucket)->getKey(),
static_cast<MapEntryTy *>(Bucket)->getValue());
HashTable[I] = RHSHashTable[I];
}
@@ -171,7 +160,6 @@ public:
StringMap &operator=(StringMap RHS) {
StringMapImpl::swap(RHS);
- std::swap(Allocator, RHS.Allocator);
return *this;
}
@@ -183,16 +171,13 @@ public:
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
- static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
+ static_cast<MapEntryTy *>(Bucket)->Destroy();
}
}
}
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>;
@@ -321,7 +306,7 @@ public:
if (Bucket == getTombstoneVal())
--NumTombstones;
- Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
+ Bucket = MapEntryTy::Create(Key, std::forward<ArgsTy>(Args)...);
++NumItems;
assert(NumItems + NumTombstones <= NumBuckets);
@@ -339,7 +324,7 @@ public:
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *&Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
- static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
+ static_cast<MapEntryTy *>(Bucket)->Destroy();
}
Bucket = nullptr;
}
@@ -355,7 +340,7 @@ public:
void erase(iterator I) {
MapEntryTy &V = *I;
remove(&V);
- V.Destroy(Allocator);
+ V.Destroy();
}
bool erase(std::string_view Key) {
diff --git a/llvm/include/llvm/ADT/StringMapEntry.h b/llvm/include/llvm/ADT/StringMapEntry.h
index 93e13b5bb16c..66a30698d787 100644
--- a/llvm/include/llvm/ADT/StringMapEntry.h
+++ b/llvm/include/llvm/ADT/StringMapEntry.h
@@ -33,22 +33,14 @@ protected:
/// Helper to tail-allocate \p Key. It'd be nice to generalize this so it
/// could be reused elsewhere, maybe even taking an llvm::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) {
+ std::string_view Key) {
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);
+ void *Allocation = safe_malloc(AllocSize);
assert(Allocation && "Unhandled out-of-memory");
// Copy the string information.
@@ -58,6 +50,7 @@ void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign,
Buffer[KeyLength] = 0; // Null terminate for convenience of clients.
return Allocation;
}
+};
/// StringMapEntryStorage - Holds the value in a StringMapEntry.
///
@@ -117,11 +110,11 @@ public:
/// 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,
+ template <typename... InitTy>
+ static StringMapEntry *Create(std::string_view key,
InitTy &&... initVals) {
return new (StringMapEntryBase::allocateWithKey(
- sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
+ sizeof(StringMapEntry), alignof(StringMapEntry), key))
StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
}
@@ -134,12 +127,10 @@ public:
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
/// specified allocator.
- template <typename AllocatorTy> void Destroy(AllocatorTy &allocator) {
+ void Destroy() {
// 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));
+ std::free(static_cast<void *>(this));
}
};
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
index 5211f01bbd73..28d710fe69e9 100644
--- a/llvm/unittests/ADT/StringMapTest.cpp
+++ b/llvm/unittests/ADT/StringMapTest.cpp
@@ -223,13 +223,12 @@ TEST_F(StringMapTest, IterationTest) {
// Test StringMapEntry::Create() method.
TEST_F(StringMapTest, StringMapEntryTest) {
- MallocAllocator Allocator;
StringMap<uint32_t>::value_type *entry =
StringMap<uint32_t>::value_type::Create(
std::string_view(testKeyFirst, testKeyLength), 1u);
EXPECT_STREQ(testKey, entry->first().data());
EXPECT_EQ(1u, entry->second);
- entry->Destroy(Allocator);
+ entry->Destroy();
}
// Test insert() method.
@@ -238,7 +237,7 @@ TEST_F(StringMapTest, InsertTest) {
testMap.insert(
StringMap<uint32_t>::value_type::Create(
std::string_view(testKeyFirst, testKeyLength),
- testMap.getAllocator(), 1u));
+ 1u));
assertSingleItemMap();
}
@@ -353,15 +352,14 @@ TEST_F(StringMapTest, MoveOnly) {
StringMap<MoveOnly> t;
t.insert(std::make_pair("Test", MoveOnly(42)));
std::string_view Key = "Test";
- StringMapEntry<MoveOnly>::Create(Key, t.getAllocator(), MoveOnly(42))
- ->Destroy(t.getAllocator());
+ StringMapEntry<MoveOnly>::Create(Key, MoveOnly(42))
+ ->Destroy();
}
TEST_F(StringMapTest, CtorArg) {
std::string_view Key = "Test";
- MallocAllocator Allocator;
- StringMapEntry<MoveOnly>::Create(Key, Allocator, Immovable())
- ->Destroy(Allocator);
+ StringMapEntry<MoveOnly>::Create(Key, Immovable())
+ ->Destroy();
}
TEST_F(StringMapTest, MoveConstruct) {
--
2.20.1.windows.1

View File

@@ -0,0 +1,91 @@
From ba61e94bf9e2273b6a2e5d3d4b2bb74f76536b19 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sat, 7 May 2022 23:08:15 -0400
Subject: [PATCH 12/31] Remove EpochTracker
---
llvm/include/llvm/ADT/SmallPtrSet.h | 14 ++++----------
llvm/lib/Support/SmallPtrSet.cpp | 1 -
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/ADT/SmallPtrSet.h b/llvm/include/llvm/ADT/SmallPtrSet.h
index e46a5171e301..2edc1f5e2066 100644
--- a/llvm/include/llvm/ADT/SmallPtrSet.h
+++ b/llvm/include/llvm/ADT/SmallPtrSet.h
@@ -14,7 +14,6 @@
#ifndef LLVM_ADT_SMALLPTRSET_H
#define LLVM_ADT_SMALLPTRSET_H
-#include "llvm/ADT/EpochTracker.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ReverseIteration.h"
#include "llvm/Support/type_traits.h"
@@ -46,7 +45,7 @@ namespace llvm {
/// (-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 {
+class SmallPtrSetImplBase {
friend class SmallPtrSetIteratorImpl;
protected:
@@ -92,7 +91,6 @@ public:
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()) {
@@ -139,14 +137,12 @@ protected:
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.
@@ -259,8 +255,7 @@ protected:
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
template <typename PtrTy>
-class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
- DebugEpochBase::HandleBase {
+class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
public:
@@ -270,9 +265,8 @@ public:
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) {}
+ explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
+ : SmallPtrSetIteratorImpl(BP, E) {}
// Most methods are provided by the base class.
diff --git a/llvm/lib/Support/SmallPtrSet.cpp b/llvm/lib/Support/SmallPtrSet.cpp
index f6e2dfb8a6c9..4549db08e3ee 100644
--- a/llvm/lib/Support/SmallPtrSet.cpp
+++ b/llvm/lib/Support/SmallPtrSet.cpp
@@ -59,7 +59,6 @@ SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
else
++NumNonEmpty; // Track density.
*Bucket = Ptr;
- incrementEpoch();
return std::make_pair(Bucket, true);
}
--
2.20.1.windows.1

View File

@@ -0,0 +1,230 @@
From 2e9ec7d3e5c58424fde4312784e2a9faab58fe2c Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 13:34:07 -0400
Subject: [PATCH 13/31] Add compiler warning pragrams
---
llvm/include/llvm/ADT/FunctionExtras.h | 10 ++++++++++
llvm/include/llvm/ADT/Hashing.h | 9 +++++++++
llvm/include/llvm/ADT/SmallVector.h | 8 ++++++++
llvm/include/llvm/Support/MathExtras.h | 9 +++++++++
llvm/include/llvm/Support/MemAlloc.h | 13 +++++++++++++
llvm/lib/Support/raw_ostream.cpp | 4 ++++
llvm/unittests/ADT/DenseMapTest.cpp | 4 ++++
llvm/unittests/ADT/MapVectorTest.cpp | 7 +++++++
llvm/unittests/ADT/SmallVectorTest.cpp | 4 ++++
llvm/unittests/Support/AlignOfTest.cpp | 7 +++----
10 files changed, 71 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/ADT/FunctionExtras.h b/llvm/include/llvm/ADT/FunctionExtras.h
index 1a26cb702cae..3b834236b8fa 100644
--- a/llvm/include/llvm/ADT/FunctionExtras.h
+++ b/llvm/include/llvm/ADT/FunctionExtras.h
@@ -54,6 +54,12 @@ namespace llvm {
/// 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>
@@ -405,6 +411,10 @@ public:
}
};
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
} // end namespace llvm
#endif // LLVM_ADT_FUNCTIONEXTRAS_H
diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h
index e296c1c53ebd..8f90b4214b92 100644
--- a/llvm/include/llvm/ADT/Hashing.h
+++ b/llvm/include/llvm/ADT/Hashing.h
@@ -55,6 +55,11 @@
#include <tuple>
#include <utility>
+#ifdef _WIN32
+#pragma warning(push)
+#pragma warning(disable : 26495)
+#endif
+
namespace llvm {
/// An opaque object representing a hash code.
@@ -679,4 +684,8 @@ hash_code hash_value(const std::basic_string<T> &arg) {
} // namespace llvm
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
+
#endif
diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h
index 602fcc5b7a98..690d512a43c8 100644
--- a/llvm/include/llvm/ADT/SmallVector.h
+++ b/llvm/include/llvm/ADT/SmallVector.h
@@ -13,6 +13,14 @@
#ifndef LLVM_ADT_SMALLVECTOR_H
#define LLVM_ADT_SMALLVECTOR_H
+// This file uses std::memcpy() to copy std::pair<unsigned int, unsigned int>.
+// That type is POD, but the standard doesn't guarantee that. GCC doesn't treat
+// the type as POD so it throws a warning. We want to consider this a warning
+// instead of an error.
+#if __GNUC__ >= 8
+#pragma GCC diagnostic warning "-Wclass-memaccess"
+#endif
+
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index da843ef79ff9..fac12dd0e4c6 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -435,6 +435,11 @@ inline uint64_t maxUIntN(uint64_t N) {
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");
@@ -442,6 +447,10 @@ inline int64_t minIntN(int64_t N) {
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");
diff --git a/llvm/include/llvm/Support/MemAlloc.h b/llvm/include/llvm/Support/MemAlloc.h
index d6012bd5a698..01007deb89bb 100644
--- a/llvm/include/llvm/Support/MemAlloc.h
+++ b/llvm/include/llvm/Support/MemAlloc.h
@@ -22,6 +22,14 @@
namespace llvm {
+#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) {
@@ -84,4 +92,9 @@ allocate_buffer(size_t Size, size_t Alignment);
void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment);
} // namespace llvm
+
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
+
#endif
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 306cc981ed8f..bff7b6c9a77b 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -10,6 +10,10 @@
//
//===----------------------------------------------------------------------===//
+#ifdef _WIN32
+#define _CRT_NONSTDC_NO_WARNINGS
+#endif
+
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index a122f1fe3bdf..123012a3118d 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -6,6 +6,10 @@
//
//===----------------------------------------------------------------------===//
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
#include "llvm/ADT/DenseMap.h"
#include "gtest/gtest.h"
#include <map>
diff --git a/llvm/unittests/ADT/MapVectorTest.cpp b/llvm/unittests/ADT/MapVectorTest.cpp
index 552f9956bdc2..20ebcd753bcc 100644
--- a/llvm/unittests/ADT/MapVectorTest.cpp
+++ b/llvm/unittests/ADT/MapVectorTest.cpp
@@ -6,6 +6,13 @@
//
//===----------------------------------------------------------------------===//
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wpedantic"
+#if !defined(__clang__)
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+#endif
+
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/iterator_range.h"
#include "gtest/gtest.h"
diff --git a/llvm/unittests/ADT/SmallVectorTest.cpp b/llvm/unittests/ADT/SmallVectorTest.cpp
index 1914f38fac6c..387229c32d5a 100644
--- a/llvm/unittests/ADT/SmallVectorTest.cpp
+++ b/llvm/unittests/ADT/SmallVectorTest.cpp
@@ -17,6 +17,10 @@
#include <list>
#include <stdarg.h>
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+
using namespace llvm;
namespace {
diff --git a/llvm/unittests/Support/AlignOfTest.cpp b/llvm/unittests/Support/AlignOfTest.cpp
index f84895c18602..6a50205b143b 100644
--- a/llvm/unittests/Support/AlignOfTest.cpp
+++ b/llvm/unittests/Support/AlignOfTest.cpp
@@ -31,10 +31,9 @@ namespace {
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Winaccessible-base"
#elif ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
-// Pragma based warning suppression was introduced in GGC 4.2. Additionally
-// this warning is "enabled by default". The warning still appears if -Wall is
-// suppressed. Apparently GCC suppresses it when -w is specifed, which is odd.
-#pragma GCC diagnostic warning "-w"
+#pragma GCC diagnostic warning "-Wunknown-pragmas"
+#pragma GCC diagnostic warning "-Winaccessible-base"
+#pragma GCC diagnostic warning "-Wunused-function"
#endif
// Define some fixed alignment types to use in these tests.
--
2.20.1.windows.1

View File

@@ -0,0 +1,743 @@
From e8352137c16b81ab7af248e608eca3a1d8221e37 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 13:43:50 -0400
Subject: [PATCH 14/31] Remove unused functions
---
llvm/include/llvm/ADT/SmallString.h | 80 ------
llvm/include/llvm/Support/Errno.h | 9 -
llvm/include/llvm/Support/VersionTuple.h | 33 ---
llvm/include/llvm/Support/raw_ostream.h | 115 +-------
llvm/lib/Support/raw_ostream.cpp | 327 -----------------------
5 files changed, 8 insertions(+), 556 deletions(-)
diff --git a/llvm/include/llvm/ADT/SmallString.h b/llvm/include/llvm/ADT/SmallString.h
index 8112741dd01d..85987811f3c4 100644
--- a/llvm/include/llvm/ADT/SmallString.h
+++ b/llvm/include/llvm/ADT/SmallString.h
@@ -86,48 +86,12 @@ public:
/// @name String Comparison
/// @{
- /// Check for string equality. This is more efficient than compare() when
- /// the relative ordering of inequal strings isn't needed.
- bool equals(std::string_view RHS) const {
- return str().equals(RHS);
- }
-
- /// Check for string equality, ignoring case.
- bool equals_insensitive(std::string_view RHS) const {
- return str().equals_insensitive(RHS);
- }
-
/// 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);
}
- /// compare_insensitive - Compare two strings, ignoring case.
- int compare_insensitive(std::string_view RHS) const {
- return str().compare_insensitive(RHS);
- }
-
- /// compare_numeric - Compare two strings, treating sequences of digits as
- /// numbers.
- int compare_numeric(std::string_view RHS) const {
- return str().compare_numeric(RHS);
- }
-
- /// @}
- /// @name String Predicates
- /// @{
-
- /// startswith - Check if this string starts with the given \p Prefix.
- bool startswith(std::string_view Prefix) const {
- return str().startswith(Prefix);
- }
-
- /// endswith - Check if this string ends with the given \p Suffix.
- bool endswith(std::string_view Suffix) const {
- return str().endswith(Suffix);
- }
-
/// @}
/// @name String Searching
/// @{
@@ -208,50 +172,6 @@ public:
}
/// @}
- /// @name Helpful Algorithms
- /// @{
-
- /// Return the number of occurrences of \p C in the string.
- size_t count(char C) const {
- return str().count(C);
- }
-
- /// Return the number of non-overlapped occurrences of \p Str in the
- /// string.
- size_t count(std::string_view Str) const {
- return str().count(Str);
- }
-
- /// @}
- /// @name Substring Operations
- /// @{
-
- /// Return a reference to the substring 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 \p N
- /// exceeds the number of characters remaining in the string, the string
- /// suffix (starting with \p Start) will be returned.
- std::string_view substr(size_t Start, size_t N = std::string_view::npos) const {
- return str().substr(Start, N);
- }
-
- /// Return a reference to the substring 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 less than \p Start, or exceeds the
- /// number of characters remaining in the string, the string suffix
- /// (starting with \p Start) will be returned.
- std::string_view slice(size_t Start, size_t End) const {
- return str().slice(Start, End);
- }
// Extra methods.
diff --git a/llvm/include/llvm/Support/Errno.h b/llvm/include/llvm/Support/Errno.h
index 07df6765d9db..d9bf68bb369e 100644
--- a/llvm/include/llvm/Support/Errno.h
+++ b/llvm/include/llvm/Support/Errno.h
@@ -20,15 +20,6 @@
namespace llvm {
namespace sys {
-/// Returns a string representation of the errno value, using whatever
-/// thread-safe variant of strerror() is available. Be sure to call this
-/// immediately after the function that set errno, or errno may have been
-/// overwritten by an intervening call.
-std::string StrError();
-
-/// Like the no-argument version above, but uses \p errnum instead of errno.
-std::string StrError(int errnum);
-
template <typename FailT, typename Fun, typename... Args>
inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F,
const Args &... As) {
diff --git a/llvm/include/llvm/Support/VersionTuple.h b/llvm/include/llvm/Support/VersionTuple.h
index 85f4f1a707c7..a28e12adcc25 100644
--- a/llvm/include/llvm/Support/VersionTuple.h
+++ b/llvm/include/llvm/Support/VersionTuple.h
@@ -158,39 +158,6 @@ public:
friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
return !(X < Y);
}
-
- friend llvm::hash_code hash_value(const VersionTuple &VT) {
- return llvm::hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build);
- }
-
- /// Retrieve a string representation of the version number.
- std::string getAsString() const;
-};
-
-/// Print a version number.
-raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V);
-
-// Provide DenseMapInfo for version tuples.
-template <> struct DenseMapInfo<VersionTuple> {
- static inline VersionTuple getEmptyKey() { return VersionTuple(0x7FFFFFFF); }
- static inline VersionTuple getTombstoneKey() {
- return VersionTuple(0x7FFFFFFE);
- }
- static unsigned getHashValue(const VersionTuple &Value) {
- unsigned Result = Value.getMajor();
- if (auto Minor = Value.getMinor())
- Result = detail::combineHashValue(Result, *Minor);
- if (auto Subminor = Value.getSubminor())
- Result = detail::combineHashValue(Result, *Subminor);
- if (auto Build = Value.getBuild())
- Result = detail::combineHashValue(Result, *Build);
-
- return Result;
- }
-
- static bool isEqual(const VersionTuple &LHS, const VersionTuple &RHS) {
- return LHS == RHS;
- }
};
} // end namespace llvm
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index 94d0ed66eced..50443e018aaf 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -249,32 +249,6 @@ public:
return write(Str.data(), Str.size());
}
- raw_ostream &operator<<(unsigned long N);
- raw_ostream &operator<<(long N);
- raw_ostream &operator<<(unsigned long long N);
- raw_ostream &operator<<(long long N);
- raw_ostream &operator<<(const void *P);
-
- raw_ostream &operator<<(unsigned int N) {
- return this->operator<<(static_cast<unsigned long>(N));
- }
-
- raw_ostream &operator<<(int N) {
- return this->operator<<(static_cast<long>(N));
- }
-
- raw_ostream &operator<<(double N);
-
- /// Output \p N in hexadecimal, without any prefix or padding.
- raw_ostream &write_hex(unsigned long long N);
-
- // Change the foreground color of text.
- raw_ostream &operator<<(Colors C);
-
- /// Output a formatted UUID with dash separators.
- using uuid_t = uint8_t[16];
- raw_ostream &write_uuid(const uuid_t UUID);
-
/// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
/// satisfy llvm::isPrint into an escape sequence.
raw_ostream &write_escaped(std::string_view Str, bool UseHexEscapes = false);
@@ -282,21 +256,6 @@ public:
raw_ostream &write(unsigned char C);
raw_ostream &write(const char *Ptr, size_t Size);
- // Formatted output, see the format() function in Support/Format.h.
- raw_ostream &operator<<(const format_object_base &Fmt);
-
- // Formatted output, see the leftJustify() function in Support/Format.h.
- raw_ostream &operator<<(const FormattedString &);
-
- // Formatted output, see the formatHex() function in Support/Format.h.
- raw_ostream &operator<<(const FormattedNumber &);
-
- // Formatted output, see the formatv() function in Support/FormatVariadic.h.
- raw_ostream &operator<<(const formatv_object_base &);
-
- // Formatted output, see the format_bytes() function in Support/Format.h.
- raw_ostream &operator<<(const FormattedBytes &);
-
/// indent - Insert 'NumSpaces' spaces.
raw_ostream &indent(unsigned NumSpaces);
@@ -311,14 +270,19 @@ public:
/// @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);
+ 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();
+ virtual raw_ostream &resetColor() { return *this; }
/// Reverses the foreground and background colors.
- virtual raw_ostream &reverseColor();
+ 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
@@ -391,10 +355,6 @@ private:
/// unused bytes in the buffer.
void copy_to_buffer(const char *Ptr, size_t Size);
- /// Compute whether colors should be used and do the necessary work such as
- /// flushing. The result is affected by calls to enable_color().
- bool prepare_colors();
-
/// Flush the tied-to stream (if present) and then write the required data.
void flush_tied_then_write(const char *Ptr, size_t Size);
@@ -445,7 +405,6 @@ class raw_fd_ostream : public raw_pwrite_stream {
int FD;
bool ShouldClose;
bool SupportsSeeking = false;
- mutable Optional<bool> HasColors;
#ifdef _WIN32
/// True if this fd refers to a Windows console device. Mintty and other
@@ -519,10 +478,6 @@ public:
/// to the offset specified from the beginning of the file.
uint64_t seek(uint64_t off);
- bool is_displayed() const override;
-
- bool has_colors() const override;
-
std::error_code error() const { return EC; }
/// Return the value of the flag in this raw_fd_ostream indicating whether an
@@ -541,38 +496,6 @@ public:
/// - from The Zen of Python, by Tim Peters
///
void clear_error() { EC = std::error_code(); }
-
- /// Locks the underlying file.
- ///
- /// @returns RAII object that releases the lock upon leaving the scope, if the
- /// locking was successful. Otherwise returns corresponding
- /// error code.
- ///
- /// The function blocks the current thread until the lock become available or
- /// error occurs.
- ///
- /// Possible use of this function may be as follows:
- ///
- /// @code{.cpp}
- /// if (auto L = stream.lock()) {
- /// // ... do action that require file to be locked.
- /// } else {
- /// handleAllErrors(std::move(L.takeError()), [&](ErrorInfoBase &EIB) {
- /// // ... handle lock error.
- /// });
- /// }
- /// @endcode
- LLVM_NODISCARD Expected<sys::fs::FileLocker> lock();
-
- /// Tries to lock the underlying file within the specified period.
- ///
- /// @returns RAII object that releases the lock upon leaving the scope, if the
- /// locking was successful. Otherwise returns corresponding
- /// error code.
- ///
- /// It is used as @ref lock.
- LLVM_NODISCARD
- Expected<sys::fs::FileLocker> tryLockFor(std::chrono::milliseconds Timeout);
};
/// This returns a reference to a raw_fd_ostream for standard output. Use it
@@ -602,17 +525,6 @@ public:
/// immediately destroyed.
raw_fd_stream(std::string_view Filename, std::error_code &EC);
- /// This reads the \p Size bytes into a buffer pointed by \p Ptr.
- ///
- /// \param Ptr The start of the buffer to hold data to be read.
- ///
- /// \param Size The number of bytes to be read.
- ///
- /// On success, the number of bytes read is returned, and the file position is
- /// advanced by this number. On error, -1 is returned, use error() to get the
- /// error code.
- ssize_t read(char *Ptr, size_t Size);
-
/// Check if \p OS is a pointer of type raw_fd_stream*.
static bool classof(const raw_ostream *OS);
};
@@ -726,17 +638,6 @@ public:
~buffer_unique_ostream() override { *OS << str(); }
};
-class Error;
-
-/// This helper creates an output stream and then passes it to \p Write.
-/// The stream created is based on the specified \p OutputFileName:
-/// llvm::outs for "-", raw_null_ostream for "/dev/null", and raw_fd_ostream
-/// for other names. For raw_fd_ostream instances, the stream writes to
-/// a temporary file. The final output file is atomically replaced with the
-/// temporary file after the \p Write function is finished.
-Error writeToOutput(std::string_view OutputFileName,
- std::function<Error(raw_ostream &)> Write);
-
} // end namespace llvm
#endif // LLVM_SUPPORT_RAW_OSTREAM_H
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index bff7b6c9a77b..611043dc5925 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -121,49 +121,6 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
assert(OutBufStart <= OutBufEnd && "Invalid size!");
}
-raw_ostream &raw_ostream::operator<<(unsigned long N) {
- write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(long N) {
- write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(unsigned long long N) {
- write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(long long N) {
- write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
- return *this;
-}
-
-raw_ostream &raw_ostream::write_hex(unsigned long long N) {
- llvm::write_hex(*this, N, HexPrintStyle::Lower);
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(Colors C) {
- if (C == Colors::RESET)
- resetColor();
- else
- changeColor(C);
- return *this;
-}
-
-raw_ostream &raw_ostream::write_uuid(const uuid_t UUID) {
- for (int Idx = 0; Idx < 16; ++Idx) {
- *this << format("%02" PRIX32, UUID[Idx]);
- if (Idx == 3 || Idx == 5 || Idx == 7 || Idx == 9)
- *this << "-";
- }
- return *this;
-}
-
-
raw_ostream &raw_ostream::write_escaped(std::string_view Str,
bool UseHexEscapes) {
for (unsigned char c : Str) {
@@ -309,172 +266,6 @@ void raw_ostream::flush_tied_then_write(const char *Ptr, size_t Size) {
write_impl(Ptr, Size);
}
-// Formatted output.
-raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
- // If we have more than a few bytes left in our output buffer, try
- // formatting directly onto its end.
- size_t NextBufferSize = 127;
- size_t BufferBytesLeft = OutBufEnd - OutBufCur;
- if (BufferBytesLeft > 3) {
- size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
-
- // Common case is that we have plenty of space.
- if (BytesUsed <= BufferBytesLeft) {
- OutBufCur += BytesUsed;
- return *this;
- }
-
- // Otherwise, we overflowed and the return value tells us the size to try
- // again with.
- NextBufferSize = BytesUsed;
- }
-
- // If we got here, we didn't have enough space in the output buffer for the
- // string. Try printing into a SmallVector that is resized to have enough
- // space. Iterate until we win.
- SmallVector<char, 128> V;
-
- while (true) {
- V.resize(NextBufferSize);
-
- // Try formatting into the SmallVector.
- size_t BytesUsed = Fmt.print(V.data(), NextBufferSize);
-
- // If BytesUsed fit into the vector, we win.
- if (BytesUsed <= NextBufferSize)
- return write(V.data(), BytesUsed);
-
- // Otherwise, try again with a new size.
- assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
- NextBufferSize = BytesUsed;
- }
-}
-
-raw_ostream &raw_ostream::operator<<(const formatv_object_base &Obj) {
- Obj.format(*this);
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
- unsigned LeftIndent = 0;
- unsigned RightIndent = 0;
- const ssize_t Difference = FS.Width - FS.Str.size();
- if (Difference > 0) {
- switch (FS.Justify) {
- case FormattedString::JustifyNone:
- break;
- case FormattedString::JustifyLeft:
- RightIndent = Difference;
- break;
- case FormattedString::JustifyRight:
- LeftIndent = Difference;
- break;
- case FormattedString::JustifyCenter:
- LeftIndent = Difference / 2;
- RightIndent = Difference - LeftIndent;
- break;
- }
- }
- indent(LeftIndent);
- (*this) << FS.Str;
- indent(RightIndent);
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
- if (FN.Hex) {
- HexPrintStyle Style;
- if (FN.Upper && FN.HexPrefix)
- Style = HexPrintStyle::PrefixUpper;
- else if (FN.Upper && !FN.HexPrefix)
- Style = HexPrintStyle::Upper;
- else if (!FN.Upper && FN.HexPrefix)
- Style = HexPrintStyle::PrefixLower;
- else
- Style = HexPrintStyle::Lower;
- llvm::write_hex(*this, FN.HexValue, Style, FN.Width);
- } else {
- llvm::SmallString<16> Buffer;
- llvm::raw_svector_ostream Stream(Buffer);
- llvm::write_integer(Stream, FN.DecValue, 0, IntegerStyle::Integer);
- if (Buffer.size() < FN.Width)
- indent(FN.Width - Buffer.size());
- (*this) << Buffer;
- }
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
- if (FB.Bytes.empty())
- return *this;
-
- size_t LineIndex = 0;
- auto Bytes = FB.Bytes;
- const size_t Size = Bytes.size();
- HexPrintStyle HPS = FB.Upper ? HexPrintStyle::Upper : HexPrintStyle::Lower;
- uint64_t OffsetWidth = 0;
- if (FB.FirstByteOffset.hasValue()) {
- // Figure out how many nibbles are needed to print the largest offset
- // represented by this data set, so that we can align the offset field
- // to the right width.
- size_t Lines = Size / FB.NumPerLine;
- uint64_t MaxOffset = *FB.FirstByteOffset + Lines * FB.NumPerLine;
- unsigned Power = 0;
- if (MaxOffset > 0)
- Power = llvm::Log2_64_Ceil(MaxOffset);
- OffsetWidth = std::max<uint64_t>(4, llvm::alignTo(Power, 4) / 4);
- }
-
- // The width of a block of data including all spaces for group separators.
- unsigned NumByteGroups =
- alignTo(FB.NumPerLine, FB.ByteGroupSize) / FB.ByteGroupSize;
- unsigned BlockCharWidth = FB.NumPerLine * 2 + NumByteGroups - 1;
-
- while (!Bytes.empty()) {
- indent(FB.IndentLevel);
-
- if (FB.FirstByteOffset.hasValue()) {
- uint64_t Offset = FB.FirstByteOffset.getValue();
- llvm::write_hex(*this, Offset + LineIndex, HPS, OffsetWidth);
- *this << ": ";
- }
-
- auto Line = Bytes.take_front(FB.NumPerLine);
-
- size_t CharsPrinted = 0;
- // Print the hex bytes for this line in groups
- for (size_t I = 0; I < Line.size(); ++I, CharsPrinted += 2) {
- if (I && (I % FB.ByteGroupSize) == 0) {
- ++CharsPrinted;
- *this << " ";
- }
- llvm::write_hex(*this, Line[I], HPS, 2);
- }
-
- if (FB.ASCII) {
- // Print any spaces needed for any bytes that we didn't print on this
- // line so that the ASCII bytes are correctly aligned.
- assert(BlockCharWidth >= CharsPrinted);
- indent(BlockCharWidth - CharsPrinted + 2);
- *this << "|";
-
- // Print the ASCII char values for each byte on this line
- for (uint8_t Byte : Line) {
- if (isPrint(Byte))
- *this << static_cast<char>(Byte);
- else
- *this << '.';
- }
- *this << '|';
- }
-
- Bytes = Bytes.drop_front(Line.size());
- LineIndex += Line.size();
- if (LineIndex < Size)
- *this << '\n';
- }
- return *this;
-}
template <char C>
static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
@@ -507,63 +298,8 @@ raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
return write_padding<'\0'>(*this, NumZeros);
}
-bool raw_ostream::prepare_colors() {
- // Colors were explicitly disabled.
- if (!ColorEnabled)
- return false;
-
- // Colors require changing the terminal but this stream is not going to a
- // terminal.
- if (sys::Process::ColorNeedsFlush() && !is_displayed())
- return false;
-
- if (sys::Process::ColorNeedsFlush())
- flush();
-
- return true;
-}
-
-raw_ostream &raw_ostream::changeColor(enum Colors colors, bool bold, bool bg) {
- if (!prepare_colors())
- return *this;
-
- const char *colorcode =
- (colors == SAVEDCOLOR)
- ? sys::Process::OutputBold(bg)
- : sys::Process::OutputColor(static_cast<char>(colors), bold, bg);
- if (colorcode)
- write(colorcode, strlen(colorcode));
- return *this;
-}
-
-raw_ostream &raw_ostream::resetColor() {
- if (!prepare_colors())
- return *this;
-
- if (const char *colorcode = sys::Process::ResetColor())
- write(colorcode, strlen(colorcode));
- return *this;
-}
-
-raw_ostream &raw_ostream::reverseColor() {
- if (!prepare_colors())
- return *this;
-
- if (const char *colorcode = sys::Process::OutputReverse())
- write(colorcode, strlen(colorcode));
- return *this;
-}
-
void raw_ostream::anchor() {}
-//===----------------------------------------------------------------------===//
-// Formatted Output
-//===----------------------------------------------------------------------===//
-
-// Out of line virtual method.
-void format_object_base::home() {
-}
-
//===----------------------------------------------------------------------===//
// raw_fd_ostream
//===----------------------------------------------------------------------===//
@@ -854,31 +590,6 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
#endif
}
-bool raw_fd_ostream::is_displayed() const {
- return sys::Process::FileDescriptorIsDisplayed(FD);
-}
-
-bool raw_fd_ostream::has_colors() const {
- if (!HasColors)
- HasColors = sys::Process::FileDescriptorHasColors(FD);
- return *HasColors;
-}
-
-Expected<sys::fs::FileLocker> raw_fd_ostream::lock() {
- std::error_code EC = sys::fs::lockFile(FD);
- if (!EC)
- return sys::fs::FileLocker(FD);
- return errorCodeToError(EC);
-}
-
-Expected<sys::fs::FileLocker>
-raw_fd_ostream::tryLockFor(std::chrono::milliseconds Timeout) {
- std::error_code EC = sys::fs::tryLockFile(FD, Timeout);
- if (!EC)
- return sys::fs::FileLocker(FD);
- return errorCodeToError(EC);
-}
-
void raw_fd_ostream::anchor() {}
//===----------------------------------------------------------------------===//
@@ -922,16 +633,6 @@ raw_fd_stream::raw_fd_stream(std::string_view Filename, std::error_code &EC)
EC = std::make_error_code(std::errc::invalid_argument);
}
-ssize_t raw_fd_stream::read(char *Ptr, size_t Size) {
- assert(get_fd() >= 0 && "File already closed.");
- ssize_t Ret = ::read(get_fd(), (void *)Ptr, Size);
- if (Ret >= 0)
- inc_pos(Ret);
- else
- error_detected(std::error_code(errno, std::generic_category()));
- return Ret;
-}
-
bool raw_fd_stream::classof(const raw_ostream *OS) {
return OS->get_kind() == OStreamKind::OK_FDStream;
}
@@ -991,31 +692,3 @@ void raw_pwrite_stream::anchor() {}
void buffer_ostream::anchor() {}
void buffer_unique_ostream::anchor() {}
-
-Error llvm::writeToOutput(std::string_view OutputFileName,
- std::function<Error(raw_ostream &)> Write) {
- if (OutputFileName == "-")
- return Write(outs());
-
- if (OutputFileName == "/dev/null") {
- raw_null_ostream Out;
- return Write(Out);
- }
-
- unsigned Mode = sys::fs::all_read | sys::fs::all_write | sys::fs::all_exe;
- Expected<sys::fs::TempFile> Temp =
- sys::fs::TempFile::create(OutputFileName + ".temp-stream-%%%%%%", Mode);
- if (!Temp)
- return createFileError(OutputFileName, Temp.takeError());
-
- raw_fd_ostream Out(Temp->FD, false);
-
- if (Error E = Write(Out)) {
- if (Error DiscardError = Temp->discard())
- return joinErrors(std::move(E), std::move(DiscardError));
- return E;
- }
- Out.flush();
-
- return Temp->keep(OutputFileName);
-}
--
2.20.1.windows.1

View File

@@ -0,0 +1,143 @@
From b887e8f6e34e2ff2a3ad69f67f84f49ceb1f455e Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Thu, 5 May 2022 23:18:34 -0400
Subject: [PATCH 15/31] Detemplatize small vector base
---
llvm/include/llvm/ADT/SmallVector.h | 21 +++++++-----------
llvm/lib/Support/SmallVector.cpp | 34 +++++------------------------
2 files changed, 13 insertions(+), 42 deletions(-)
diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h
index 690d512a43c8..695015ae3248 100644
--- a/llvm/include/llvm/ADT/SmallVector.h
+++ b/llvm/include/llvm/ADT/SmallVector.h
@@ -50,14 +50,14 @@ namespace llvm {
/// Using 64 bit size is desirable for cases like SmallVector<char>, where a
/// 32 bit size would limit the vector to ~4GB. SmallVectors are used for
/// buffering bitcode output - which can exceed 4GB.
-template <class Size_T> class SmallVectorBase {
+class SmallVectorBase {
protected:
void *BeginX;
- Size_T Size = 0, Capacity;
+ unsigned Size = 0, Capacity;
/// The maximum value of the Size_T used.
static constexpr size_t SizeTypeMax() {
- return (std::numeric_limits<Size_T>::max)();
+ return (std::numeric_limits<unsigned>::max)();
}
SmallVectorBase() = delete;
@@ -95,15 +95,10 @@ public:
}
};
-template <class T>
-using SmallVectorSizeType =
- typename std::conditional<sizeof(T) < 4 && sizeof(void *) >= 8, uint64_t,
- uint32_t>::type;
-
/// Figure out the offset of the first element.
template <class T, typename = void> struct SmallVectorAlignmentAndSize {
- alignas(SmallVectorBase<SmallVectorSizeType<T>>) char Base[sizeof(
- SmallVectorBase<SmallVectorSizeType<T>>)];
+ alignas(SmallVectorBase) char Base[sizeof(
+ SmallVectorBase)];
alignas(T) char FirstEl[sizeof(T)];
};
@@ -112,8 +107,8 @@ template <class T, typename = void> struct SmallVectorAlignmentAndSize {
/// to avoid unnecessarily requiring T to be complete.
template <typename T, typename = void>
class SmallVectorTemplateCommon
- : public SmallVectorBase<SmallVectorSizeType<T>> {
- using Base = SmallVectorBase<SmallVectorSizeType<T>>;
+ : public SmallVectorBase {
+ using Base = SmallVectorBase;
/// Find the address of the first element. For this pointer math to be valid
/// with small-size of 0 for T with lots of alignment, it's important that
@@ -360,7 +355,7 @@ protected:
/// in \p NewCapacity. This is the first section of \a grow().
T *mallocForGrow(size_t MinSize, size_t &NewCapacity) {
return static_cast<T *>(
- SmallVectorBase<SmallVectorSizeType<T>>::mallocForGrow(
+ SmallVectorBase::mallocForGrow(
MinSize, sizeof(T), NewCapacity));
}
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp
index 26901fe97d20..3fc16097bd30 100644
--- a/llvm/lib/Support/SmallVector.cpp
+++ b/llvm/lib/Support/SmallVector.cpp
@@ -41,10 +41,6 @@ static_assert(sizeof(SmallVector<void *, 1>) ==
sizeof(unsigned) * 2 + sizeof(void *) * 2,
"wasted space in SmallVector size 1");
-static_assert(sizeof(SmallVector<char, 0>) ==
- sizeof(void *) * 2 + sizeof(void *),
- "1 byte elements have word-sized type for size and capacity");
-
/// Report that MinSize doesn't fit into this vector's size type. Throws
/// std::length_error or calls report_fatal_error.
LLVM_ATTRIBUTE_NORETURN
@@ -76,9 +72,8 @@ static void report_at_maximum_capacity(size_t MaxSize) {
}
// Note: Moving this function into the header may cause performance regression.
-template <class Size_T>
static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
- constexpr size_t MaxSize = std::numeric_limits<Size_T>::max();
+ 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.
@@ -99,18 +94,16 @@ static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
}
// Note: Moving this function into the header may cause performance regression.
-template <class Size_T>
-void *SmallVectorBase<Size_T>::mallocForGrow(size_t MinSize, size_t TSize,
+void *SmallVectorBase::mallocForGrow(size_t MinSize, size_t TSize,
size_t &NewCapacity) {
- NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
+ NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
return llvm::safe_malloc(NewCapacity * TSize);
}
// Note: Moving this function into the header may cause performance regression.
-template <class Size_T>
-void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize,
+void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSize,
size_t TSize) {
- size_t NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
+ size_t NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
void *NewElts;
if (BeginX == FirstEl) {
NewElts = safe_malloc(NewCapacity * TSize);
@@ -125,20 +118,3 @@ void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize,
this->BeginX = NewElts;
this->Capacity = NewCapacity;
}
-
-template class llvm::SmallVectorBase<uint32_t>;
-
-// Disable the uint64_t instantiation for 32-bit builds.
-// Both uint32_t and uint64_t instantiations are needed for 64-bit builds.
-// This instantiation will never be used in 32-bit builds, and will cause
-// warnings when sizeof(Size_T) > sizeof(size_t).
-#if SIZE_MAX > UINT32_MAX
-template class llvm::SmallVectorBase<uint64_t>;
-
-// Assertions to ensure this #if stays in sync with SmallVectorSizeType.
-static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint64_t),
- "Expected SmallVectorBase<uint64_t> variant to be in use.");
-#else
-static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint32_t),
- "Expected SmallVectorBase<uint32_t> variant to be in use.");
-#endif
--
2.20.1.windows.1

View File

@@ -0,0 +1,217 @@
From eada33299195b46a8942e198ae8ae41185cd4f45 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 13:48:59 -0400
Subject: [PATCH 16/31] Add vectors to raw_ostream
---
llvm/include/llvm/Support/raw_ostream.h | 115 ++++++++++++++++++++++++
llvm/lib/Support/raw_ostream.cpp | 47 ++++++++++
2 files changed, 162 insertions(+)
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index 50443e018aaf..8008170be3e5 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -26,6 +26,7 @@
#endif
#include <system_error>
#include <type_traits>
+#include <vector>
namespace llvm {
@@ -249,12 +250,24 @@ public:
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 llvm::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);
@@ -600,6 +613,108 @@ public:
}
};
+/// 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.
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 611043dc5925..3abeed3dac21 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -664,6 +664,53 @@ void raw_svector_ostream::pwrite_impl(const char *Ptr, size_t Size,
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
//===----------------------------------------------------------------------===//
--
2.20.1.windows.1

View File

@@ -0,0 +1,165 @@
From fc8a16f804f5d37e179f8eac521f8430e663d1a0 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Tue, 3 May 2022 22:16:10 -0400
Subject: [PATCH 17/31] Extra collections features
---
llvm/include/llvm/ADT/StringMap.h | 103 +++++++++++++++++++++++++++++-
llvm/lib/Support/raw_ostream.cpp | 8 +++
2 files changed, 110 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
index 3b40bba37f58..af4be84e469d 100644
--- a/llvm/include/llvm/ADT/StringMap.h
+++ b/llvm/include/llvm/ADT/StringMap.h
@@ -40,7 +40,7 @@ protected:
protected:
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
- StringMapImpl(StringMapImpl &&RHS)
+ StringMapImpl(StringMapImpl &&RHS) noexcept
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
ItemSize(RHS.ItemSize) {
@@ -390,11 +390,27 @@ public:
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>
@@ -459,6 +475,91 @@ 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 llvm
#endif // LLVM_ADT_STRINGMAP_H
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 3abeed3dac21..27bba0ca2f06 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -78,6 +78,14 @@ 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.
--
2.20.1.windows.1

View File

@@ -0,0 +1,25 @@
From 0986c8a95cad971a1bf84259e1ab698497ca205c Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Wed, 4 May 2022 00:01:00 -0400
Subject: [PATCH 18/31] EpochTracker abi macro
---
llvm/include/llvm/ADT/EpochTracker.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ADT/EpochTracker.h b/llvm/include/llvm/ADT/EpochTracker.h
index 7a2e4220afec..8f98f3d582c7 100644
--- a/llvm/include/llvm/ADT/EpochTracker.h
+++ b/llvm/include/llvm/ADT/EpochTracker.h
@@ -21,7 +21,7 @@
namespace llvm {
-#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+#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
--
2.20.1.windows.1

View File

@@ -0,0 +1,59 @@
From f2b2850258fe3aed54c64f8afac2565b00ddf4b0 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Thu, 5 May 2022 18:09:45 -0400
Subject: [PATCH 19/31] Delete numbers from mathextras
---
llvm/include/llvm/Support/MathExtras.h | 36 --------------------------
1 file changed, 36 deletions(-)
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index fac12dd0e4c6..e8f1f2aca610 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -50,42 +50,6 @@ enum ZeroBehavior {
ZB_Width
};
-/// Mathematical constants.
-namespace numbers {
-// TODO: Track C++20 std::numbers.
-// TODO: Favor using the hexadecimal FP constants (requires C++17).
-constexpr double e = 2.7182818284590452354, // (0x1.5bf0a8b145749P+1) https://oeis.org/A001113
- egamma = .57721566490153286061, // (0x1.2788cfc6fb619P-1) https://oeis.org/A001620
- ln2 = .69314718055994530942, // (0x1.62e42fefa39efP-1) https://oeis.org/A002162
- ln10 = 2.3025850929940456840, // (0x1.24bb1bbb55516P+1) https://oeis.org/A002392
- log2e = 1.4426950408889634074, // (0x1.71547652b82feP+0)
- log10e = .43429448190325182765, // (0x1.bcb7b1526e50eP-2)
- pi = 3.1415926535897932385, // (0x1.921fb54442d18P+1) https://oeis.org/A000796
- inv_pi = .31830988618379067154, // (0x1.45f306bc9c883P-2) https://oeis.org/A049541
- sqrtpi = 1.7724538509055160273, // (0x1.c5bf891b4ef6bP+0) https://oeis.org/A002161
- inv_sqrtpi = .56418958354775628695, // (0x1.20dd750429b6dP-1) https://oeis.org/A087197
- sqrt2 = 1.4142135623730950488, // (0x1.6a09e667f3bcdP+0) https://oeis.org/A00219
- inv_sqrt2 = .70710678118654752440, // (0x1.6a09e667f3bcdP-1)
- sqrt3 = 1.7320508075688772935, // (0x1.bb67ae8584caaP+0) https://oeis.org/A002194
- inv_sqrt3 = .57735026918962576451, // (0x1.279a74590331cP-1)
- phi = 1.6180339887498948482; // (0x1.9e3779b97f4a8P+0) https://oeis.org/A001622
-constexpr float ef = 2.71828183F, // (0x1.5bf0a8P+1) https://oeis.org/A001113
- egammaf = .577215665F, // (0x1.2788d0P-1) https://oeis.org/A001620
- ln2f = .693147181F, // (0x1.62e430P-1) https://oeis.org/A002162
- ln10f = 2.30258509F, // (0x1.26bb1cP+1) https://oeis.org/A002392
- log2ef = 1.44269504F, // (0x1.715476P+0)
- log10ef = .434294482F, // (0x1.bcb7b2P-2)
- pif = 3.14159265F, // (0x1.921fb6P+1) https://oeis.org/A000796
- inv_pif = .318309886F, // (0x1.45f306P-2) https://oeis.org/A049541
- sqrtpif = 1.77245385F, // (0x1.c5bf8aP+0) https://oeis.org/A002161
- inv_sqrtpif = .564189584F, // (0x1.20dd76P-1) https://oeis.org/A087197
- sqrt2f = 1.41421356F, // (0x1.6a09e6P+0) https://oeis.org/A002193
- inv_sqrt2f = .707106781F, // (0x1.6a09e6P-1)
- sqrt3f = 1.73205081F, // (0x1.bb67aeP+0) https://oeis.org/A002194
- inv_sqrt3f = .577350269F, // (0x1.279a74P-1)
- phif = 1.61803399F; // (0x1.9e377aP+0) https://oeis.org/A001622
-} // namespace numbers
-
namespace detail {
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
static unsigned count(T Val, ZeroBehavior) {
--
2.20.1.windows.1

View File

@@ -0,0 +1,43 @@
From 2a2ac87a1ac74a1c6e29c205b3fd979ab77722b4 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Tue, 3 May 2022 22:50:24 -0400
Subject: [PATCH 20/31] Add lerp and sgn
---
llvm/include/llvm/Support/MathExtras.h | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index e8f1f2aca610..8116c58bd0d6 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -930,6 +930,26 @@ std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) {
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 llvm namespace
#endif
--
2.20.1.windows.1

View File

@@ -0,0 +1,172 @@
From b013523b36cba3c8fc0ced2ca013a8763573d5a0 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 16:38:11 -0400
Subject: [PATCH 21/31] Fixup includes
---
llvm/include/llvm/ADT/StringMap.h | 5 ++++-
llvm/include/llvm/ADT/StringMapEntry.h | 4 ++++
llvm/include/llvm/Support/PointerLikeTypeTraits.h | 1 +
llvm/lib/Support/ConvertUTFWrapper.cpp | 1 +
llvm/lib/Support/ErrorHandling.cpp | 7 +++----
llvm/lib/Support/raw_ostream.cpp | 12 ++++++------
llvm/unittests/ADT/SmallPtrSetTest.cpp | 2 ++
llvm/unittests/ADT/StringMapTest.cpp | 1 +
llvm/unittests/Support/ConvertUTFTest.cpp | 2 ++
9 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
index af4be84e469d..c41057cb6792 100644
--- a/llvm/include/llvm/ADT/StringMap.h
+++ b/llvm/include/llvm/ADT/StringMap.h
@@ -14,7 +14,10 @@
#define LLVM_ADT_STRINGMAP_H
#include "llvm/ADT/StringMapEntry.h"
-#include "llvm/Support/AllocatorBase.h"
+#include "llvm/Support/MemAlloc.h"
+#include "llvm/Support/SmallVector.h"
+#include "llvm/Support/iterator.h"
+#include "llvm/Support/iterator_range.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <initializer_list>
#include <iterator>
diff --git a/llvm/include/llvm/ADT/StringMapEntry.h b/llvm/include/llvm/ADT/StringMapEntry.h
index 66a30698d787..1201bb8e69d4 100644
--- a/llvm/include/llvm/ADT/StringMapEntry.h
+++ b/llvm/include/llvm/ADT/StringMapEntry.h
@@ -15,6 +15,10 @@
#ifndef LLVM_ADT_STRINGMAPENTRY_H
#define LLVM_ADT_STRINGMAPENTRY_H
+#include "wpi/MemAlloc.h"
+
+#include <cassert>
+#include <cstring>
#include <optional>
#include <string_view>
diff --git a/llvm/include/llvm/Support/PointerLikeTypeTraits.h b/llvm/include/llvm/Support/PointerLikeTypeTraits.h
index 1b15f930bd87..acadd5e89a16 100644
--- a/llvm/include/llvm/Support/PointerLikeTypeTraits.h
+++ b/llvm/include/llvm/Support/PointerLikeTypeTraits.h
@@ -16,6 +16,7 @@
#include "llvm/Support/DataTypes.h"
#include <cassert>
+#include <cstdint>
#include <type_traits>
namespace llvm {
diff --git a/llvm/lib/Support/ConvertUTFWrapper.cpp b/llvm/lib/Support/ConvertUTFWrapper.cpp
index 090ebb0f5af8..87da616b75d4 100644
--- a/llvm/lib/Support/ConvertUTFWrapper.cpp
+++ b/llvm/lib/Support/ConvertUTFWrapper.cpp
@@ -8,6 +8,7 @@
#include "llvm/ADT/span.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SwapByteOrder.h"
#include <string>
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index 9c0c6fb868f2..4b6ddd30c6e4 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -28,12 +28,11 @@
#include <mutex>
#include <new>
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
+#ifndef _WIN32
+#include <unistd.h>
#endif
#if defined(_MSC_VER)
-# include <io.h>
-# include <fcntl.h>
+#include <io.h>
#endif
using namespace llvm;
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 27bba0ca2f06..6b9e5f9e44bd 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -15,7 +15,8 @@
#endif
#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/STLExtras.h"
+#include "wpi/SmallString.h"
+#include "wpi/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
@@ -35,12 +36,11 @@
#include <sys/stat.h>
// <fcntl.h> may provide O_BINARY.
-#if defined(HAVE_FCNTL_H)
# include <fcntl.h>
-#endif
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/uio.h>
#endif
#if defined(__CYGWIN__)
@@ -62,7 +62,7 @@
#ifdef _WIN32
#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/Windows/WindowsSupport.h"
+#include "Windows/WindowsSupport.h"
#endif
using namespace llvm;
diff --git a/llvm/unittests/ADT/SmallPtrSetTest.cpp b/llvm/unittests/ADT/SmallPtrSetTest.cpp
index 531f81ab5b3f..3db8b6e37d31 100644
--- a/llvm/unittests/ADT/SmallPtrSetTest.cpp
+++ b/llvm/unittests/ADT/SmallPtrSetTest.cpp
@@ -15,6 +15,8 @@
#include "llvm/Support/PointerLikeTypeTraits.h"
#include "gtest/gtest.h"
+#include <algorithm>
+
using namespace llvm;
TEST(SmallPtrSetTest, Assignment) {
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
index 28d710fe69e9..60571cff6927 100644
--- a/llvm/unittests/ADT/StringMapTest.cpp
+++ b/llvm/unittests/ADT/StringMapTest.cpp
@@ -9,6 +9,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/DataTypes.h"
#include "gtest/gtest.h"
+#include <algorithm>
#include <limits>
#include <tuple>
using namespace llvm;
diff --git a/llvm/unittests/Support/ConvertUTFTest.cpp b/llvm/unittests/Support/ConvertUTFTest.cpp
index 9c798437a12d..2fee8ad5c012 100644
--- a/llvm/unittests/Support/ConvertUTFTest.cpp
+++ b/llvm/unittests/Support/ConvertUTFTest.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/SmallString.h"
+#include "llvm/Support/SmallVector.h"
#include "gtest/gtest.h"
#include <string>
#include <vector>
--
2.20.1.windows.1

View File

@@ -0,0 +1,141 @@
From 6df7cc04af50a1afad6f8baf8ea0520576944bed Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 16:42:09 -0400
Subject: [PATCH 22/31] use std is_trivially_copy_constructible
---
llvm/include/llvm/ADT/PointerIntPair.h | 12 ----
llvm/include/llvm/Support/type_traits.h | 91 +------------------------
2 files changed, 2 insertions(+), 101 deletions(-)
diff --git a/llvm/include/llvm/ADT/PointerIntPair.h b/llvm/include/llvm/ADT/PointerIntPair.h
index cb8b202c48b7..f9c4d2dd14c7 100644
--- a/llvm/include/llvm/ADT/PointerIntPair.h
+++ b/llvm/include/llvm/ADT/PointerIntPair.h
@@ -127,18 +127,6 @@ public:
}
};
-// Specialize is_trivially_copyable to avoid limitation of llvm::is_trivially_copyable
-// when compiled with gcc 4.9.
-template <typename PointerTy, unsigned IntBits, typename IntType,
- typename PtrTraits,
- typename Info>
-struct is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>> : std::true_type {
-#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
- static_assert(std::is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>::value,
- "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
-#endif
-};
-
template <typename PointerT, unsigned IntBits, typename PtrTraits>
struct PointerIntPairInfo {
diff --git a/llvm/include/llvm/Support/type_traits.h b/llvm/include/llvm/Support/type_traits.h
index 7b7d5d991f3f..72a2e84ad452 100644
--- a/llvm/include/llvm/Support/type_traits.h
+++ b/llvm/include/llvm/Support/type_traits.h
@@ -92,98 +92,11 @@ union trivial_helper {
} // end namespace detail
-/// An implementation of `std::is_trivially_copy_constructible` since we have
-/// users with STLs that don't yet include it.
template <typename T>
-struct is_trivially_copy_constructible
- : std::is_copy_constructible<
- ::llvm::detail::copy_construction_triviality_helper<T>> {};
-template <typename T>
-struct is_trivially_copy_constructible<T &> : std::true_type {};
-template <typename T>
-struct is_trivially_copy_constructible<T &&> : std::false_type {};
+using is_trivially_move_constructible = std::is_trivially_move_constructible<T>;
-/// An implementation of `std::is_trivially_move_constructible` since we have
-/// users with STLs that don't yet include it.
-template <typename T>
-struct is_trivially_move_constructible
- : std::is_move_constructible<
- ::llvm::detail::move_construction_triviality_helper<T>> {};
template <typename T>
-struct is_trivially_move_constructible<T &> : std::true_type {};
-template <typename T>
-struct is_trivially_move_constructible<T &&> : std::true_type {};
-
-
-template <typename T>
-struct is_copy_assignable {
- template<class F>
- static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{});
- static std::false_type get(...);
- static constexpr bool value = decltype(get((T*)nullptr))::value;
-};
-
-template <typename T>
-struct is_move_assignable {
- template<class F>
- static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{});
- static std::false_type get(...);
- static constexpr bool value = decltype(get((T*)nullptr))::value;
-};
-
-
-// An implementation of `std::is_trivially_copyable` since STL version
-// is not equally supported by all compilers, especially GCC 4.9.
-// Uniform implementation of this trait is important for ABI compatibility
-// as it has an impact on SmallVector's ABI (among others).
-template <typename T>
-class is_trivially_copyable {
-
- // copy constructors
- static constexpr bool has_trivial_copy_constructor =
- std::is_copy_constructible<detail::trivial_helper<T>>::value;
- static constexpr bool has_deleted_copy_constructor =
- !std::is_copy_constructible<T>::value;
-
- // move constructors
- static constexpr bool has_trivial_move_constructor =
- std::is_move_constructible<detail::trivial_helper<T>>::value;
- static constexpr bool has_deleted_move_constructor =
- !std::is_move_constructible<T>::value;
-
- // copy assign
- static constexpr bool has_trivial_copy_assign =
- is_copy_assignable<detail::trivial_helper<T>>::value;
- static constexpr bool has_deleted_copy_assign =
- !is_copy_assignable<T>::value;
-
- // move assign
- static constexpr bool has_trivial_move_assign =
- is_move_assignable<detail::trivial_helper<T>>::value;
- static constexpr bool has_deleted_move_assign =
- !is_move_assignable<T>::value;
-
- // destructor
- static constexpr bool has_trivial_destructor =
- std::is_destructible<detail::trivial_helper<T>>::value;
-
- public:
-
- static constexpr bool value =
- has_trivial_destructor &&
- (has_deleted_move_assign || has_trivial_move_assign) &&
- (has_deleted_move_constructor || has_trivial_move_constructor) &&
- (has_deleted_copy_assign || has_trivial_copy_assign) &&
- (has_deleted_copy_constructor || has_trivial_copy_constructor);
-
-#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
- static_assert(value == std::is_trivially_copyable<T>::value,
- "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
-#endif
-};
-template <typename T>
-class is_trivially_copyable<T*> : public std::true_type {
-};
+using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
} // end namespace llvm
--
2.20.1.windows.1

View File

@@ -0,0 +1,223 @@
From 403d6612f25ae09b3bbeffe3ed75e8c498f80da5 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Tue, 3 May 2022 20:22:38 -0400
Subject: [PATCH 23/31] Windows Support
---
.../llvm/Support/Windows/WindowsSupport.h | 45 +++++----
llvm/lib/Support/ConvertUTF.cpp | 95 +++++++++++++++++++
llvm/lib/Support/MemoryBuffer.cpp | 4 +-
3 files changed, 126 insertions(+), 18 deletions(-)
diff --git a/llvm/include/llvm/Support/Windows/WindowsSupport.h b/llvm/include/llvm/Support/Windows/WindowsSupport.h
index 551bd199551e..50b0843beb29 100644
--- a/llvm/include/llvm/Support/Windows/WindowsSupport.h
+++ b/llvm/include/llvm/Support/Windows/WindowsSupport.h
@@ -35,8 +35,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/llvm-config.h" // Get build system configuration settings
-#include "llvm/Support/Allocator.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
@@ -44,18 +42,46 @@
#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 llvm {
+/// 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 llvm::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 llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0,
+ info.dwBuildNumber);
+ }
+ }
+ }
+ return llvm::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.
-bool RunningWindows8OrGreater();
+inline bool RunningWindows8OrGreater() {
+ // Windows 8 is version 6.2, service pack 0.
+ return GetWindowsOSVersion() >= llvm::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.
@@ -228,19 +254,6 @@ inline FILETIME toFILETIME(TimePoint<> TP) {
return Time;
}
-namespace windows {
-// Returns command line arguments. Unlike arguments given to main(),
-// this function guarantees that the returned arguments are encoded in
-// UTF-8 regardless of the current code page setting.
-std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args,
- BumpPtrAllocator &Alloc);
-
-/// Convert UTF-8 path to a suitable UTF-16 path for use with the Win32 Unicode
-/// File API.
-std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16,
- size_t MaxPathLen = MAX_PATH);
-
-} // end namespace windows
} // end namespace sys
} // end namespace llvm.
diff --git a/llvm/lib/Support/ConvertUTF.cpp b/llvm/lib/Support/ConvertUTF.cpp
index e24a918c5c89..b4c7fffee8f7 100644
--- a/llvm/lib/Support/ConvertUTF.cpp
+++ b/llvm/lib/Support/ConvertUTF.cpp
@@ -51,6 +51,11 @@
#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.
@@ -733,6 +738,96 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
--------------------------------------------------------------------- */
+#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 llvm
ConvertUTF_RESTORE_WARNINGS
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp
index bcf13d828a5d..cddad9ca0660 100644
--- a/llvm/lib/Support/MemoryBuffer.cpp
+++ b/llvm/lib/Support/MemoryBuffer.cpp
@@ -225,8 +225,8 @@ public:
static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) {
- const ssize_t ChunkSize = 4096*4;
- SmallString<ChunkSize> Buffer;
+ constexpr size_t ChunkSize = 4096*4;
+ SmallVector<uint8_t, ChunkSize> Buffer;
// Read into Buffer until we hit EOF.
for (;;) {
Buffer.reserve(Buffer.size() + ChunkSize);
--
2.20.1.windows.1

View File

@@ -0,0 +1,58 @@
From c67b1c2baf278050fb43bee7a7241392d64fbb0d Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 16:46:20 -0400
Subject: [PATCH 24/31] Prefer fmtlib
---
llvm/lib/Support/ErrorHandling.cpp | 20 ++++++--------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index 4b6ddd30c6e4..9ee52a02c214 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -22,7 +22,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/WindowsError.h"
-#include "llvm/Support/raw_ostream.h"
+#include "fmt/format.h"
#include <cassert>
#include <cstdlib>
#include <mutex>
@@ -93,15 +93,7 @@ void llvm::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
if (handler) {
handler(handlerData, std::string{Reason}, GenCrashDiag);
} else {
- // Blast the result out to stderr. We don't try hard to make sure this
- // succeeds (e.g. handling EINTR) and we can't use errs() here because
- // raw ostreams can call report_fatal_error.
- SmallVector<char, 64> Buffer;
- raw_svector_ostream OS(Buffer);
- OS << "LLVM ERROR: " << Reason << "\n";
- std::string_view MessageStr = OS.str();
- ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
- (void)written; // If something went wrong, we deliberately just give up.
+ fmt::print(stderr, "LLVM ERROR: {}\n", Reason);
}
// If we reached here, we are failing ungracefully. Run the interrupt handlers
@@ -173,11 +165,11 @@ void llvm::llvm_unreachable_internal(const char *msg, const char *file,
// llvm_unreachable is intended to be used to indicate "impossible"
// situations, and not legitimate runtime errors.
if (msg)
- dbgs() << msg << "\n";
- dbgs() << "UNREACHABLE executed";
+ fmt::print(stderr, "{}\n", msg);
+ std::fputs("UNREACHABLE executed", stderr);
if (file)
- dbgs() << " at " << file << ":" << line;
- dbgs() << "!\n";
+ fmt::print(stderr, " at {}:{}", file, line);
+ fmt::print(stderr, "{}", "!\n");
abort();
#ifdef LLVM_BUILTIN_UNREACHABLE
// Windows systems and possibly others don't declare abort() to be noreturn,
--
2.20.1.windows.1

View File

@@ -0,0 +1,37 @@
From 07ffe44dd483a6fd847030ca9b76a225d5b7b2de Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 16:49:36 -0400
Subject: [PATCH 25/31] prefer wpi's fs.h
---
llvm/include/llvm/Support/raw_ostream.h | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index 8008170be3e5..27fb5c03e474 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -28,18 +28,15 @@
#include <type_traits>
#include <vector>
-namespace llvm {
-
-template <class T> class LLVM_NODISCARD Expected;
-namespace sys {
namespace fs {
enum FileAccess : unsigned;
enum OpenFlags : unsigned;
enum CreationDisposition : unsigned;
class FileLocker;
} // end namespace fs
-} // end namespace sys
+
+namespace llvm {
/// This class implements an extremely fast bulk output stream that can *only*
/// output to a stream. It does not support seeking, reopening, rewinding, line
--
2.20.1.windows.1

View File

@@ -0,0 +1,266 @@
From 7bac24e5310d67d6828b687aec2043966a955093 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 19:16:51 -0400
Subject: [PATCH 26/31] Remove unused functions
---
llvm/include/llvm/Support/raw_ostream.h | 3 +-
llvm/lib/Support/ErrorHandling.cpp | 16 -----
llvm/lib/Support/raw_ostream.cpp | 48 +++++++--------
llvm/unittests/ADT/SmallStringTest.cpp | 81 -------------------------
4 files changed, 22 insertions(+), 126 deletions(-)
diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h
index 27fb5c03e474..d228b05f4f9b 100644
--- a/llvm/include/llvm/Support/raw_ostream.h
+++ b/llvm/include/llvm/Support/raw_ostream.h
@@ -72,7 +72,6 @@ private:
/// for a \see write_impl() call to handle the data which has been put into
/// this buffer.
char *OutBufStart, *OutBufEnd, *OutBufCur;
- bool ColorEnabled = false;
/// Optional stream this stream is tied to. If this stream is written to, the
/// tied-to stream will be flushed first.
@@ -305,7 +304,7 @@ public:
// 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) { ColorEnabled = enable; }
+ 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.
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index 9ee52a02c214..77c3a37475d0 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -178,22 +178,6 @@ void llvm::llvm_unreachable_internal(const char *msg, const char *file,
#endif
}
-static void bindingsErrorHandler(void *user_data, const std::string& reason,
- bool gen_crash_diag) {
- LLVMFatalErrorHandler handler =
- LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data);
- handler(reason.c_str());
-}
-
-void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler) {
- install_fatal_error_handler(bindingsErrorHandler,
- LLVM_EXTENSION reinterpret_cast<void *>(Handler));
-}
-
-void LLVMResetFatalErrorHandler() {
- remove_fatal_error_handler();
-}
-
#ifdef _WIN32
#include <winerror.h>
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 6b9e5f9e44bd..6fa250a68ed8 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -169,16 +169,6 @@ raw_ostream &raw_ostream::write_escaped(std::string_view Str,
return *this;
}
-raw_ostream &raw_ostream::operator<<(const void *P) {
- llvm::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower);
- return *this;
-}
-
-raw_ostream &raw_ostream::operator<<(double N) {
- llvm::write_double(*this, N, FloatStyle::Exponent);
- return *this;
-}
-
void raw_ostream::flush_nonempty() {
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
size_t Length = OutBufCur - OutBufStart;
@@ -323,15 +313,22 @@ static int getFD(std::string_view Filename, std::error_code &EC,
if (Filename == "-") {
EC = std::error_code();
// Change stdout's text/binary mode based on the Flags.
- sys::ChangeStdoutMode(Flags);
+ if (!(Flags & fs::OF_Text)) {
+#if defined(_WIN32)
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+ }
return STDOUT_FILENO;
}
- int FD;
- if (Access & sys::fs::FA_Read)
- EC = sys::fs::openFileForReadWrite(Filename, FD, Disp, Flags);
+ 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
- EC = sys::fs::openFileForWrite(Filename, FD, Disp, Flags);
+ 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;
@@ -392,10 +389,7 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);
#ifdef _WIN32
- // MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes.
- sys::fs::file_status Status;
- std::error_code EC = status(FD, Status);
- SupportsSeeking = !EC && Status.type() == sys::fs::file_type::regular_file;
+ SupportsSeeking = loc != (off_t)-1 && ::GetFileType(reinterpret_cast<HANDLE>(::_get_osfhandle(FD))) != FILE_TYPE_PIPE;
#else
SupportsSeeking = loc != (off_t)-1;
#endif
@@ -408,10 +402,8 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
raw_fd_ostream::~raw_fd_ostream() {
if (FD >= 0) {
flush();
- if (ShouldClose) {
- if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
- error_detected(EC);
- }
+ if (ShouldClose && ::close(FD) < 0)
+ error_detected(std::error_code(errno, std::generic_category()));
}
#ifdef __MINGW32__
@@ -506,7 +498,11 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
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.
@@ -541,8 +537,8 @@ void raw_fd_ostream::close() {
assert(ShouldClose);
ShouldClose = false;
flush();
- if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
- error_detected(EC);
+ if (::close(FD) < 0)
+ error_detected(std::error_code(errno, std::generic_category()));
FD = -1;
}
@@ -551,8 +547,6 @@ uint64_t raw_fd_ostream::seek(uint64_t off) {
flush();
#ifdef _WIN32
pos = ::_lseeki64(FD, off, SEEK_SET);
-#elif defined(HAVE_LSEEK64)
- pos = ::lseek64(FD, off, SEEK_SET);
#else
pos = ::lseek(FD, off, SEEK_SET);
#endif
diff --git a/llvm/unittests/ADT/SmallStringTest.cpp b/llvm/unittests/ADT/SmallStringTest.cpp
index bee3875d11c9..87600ea4704b 100644
--- a/llvm/unittests/ADT/SmallStringTest.cpp
+++ b/llvm/unittests/ADT/SmallStringTest.cpp
@@ -129,23 +129,6 @@ TEST_F(SmallStringTest, StdStringConversion) {
EXPECT_EQ("abc", theStdString);
}
-TEST_F(SmallStringTest, Substr) {
- theString = "hello";
- EXPECT_EQ("lo", theString.substr(3));
- EXPECT_EQ("", theString.substr(100));
- EXPECT_EQ("hello", theString.substr(0, 100));
- EXPECT_EQ("o", theString.substr(4, 10));
-}
-
-TEST_F(SmallStringTest, Slice) {
- theString = "hello";
- EXPECT_EQ("l", theString.slice(2, 3));
- EXPECT_EQ("ell", theString.slice(1, 4));
- EXPECT_EQ("llo", theString.slice(2, 100));
- EXPECT_EQ("", theString.slice(2, 1));
- EXPECT_EQ("", theString.slice(10, 20));
-}
-
TEST_F(SmallStringTest, Find) {
theString = "hello";
EXPECT_EQ(2U, theString.find('l'));
@@ -180,68 +163,4 @@ TEST_F(SmallStringTest, Find) {
EXPECT_EQ(0U, theString.find(""));
}
-TEST_F(SmallStringTest, Count) {
- theString = "hello";
- EXPECT_EQ(2U, theString.count('l'));
- EXPECT_EQ(1U, theString.count('o'));
- EXPECT_EQ(0U, theString.count('z'));
- EXPECT_EQ(0U, theString.count("helloworld"));
- EXPECT_EQ(1U, theString.count("hello"));
- EXPECT_EQ(1U, theString.count("ello"));
- EXPECT_EQ(0U, theString.count("zz"));
-}
-
-TEST_F(SmallStringTest, Realloc) {
- theString = "abcd";
- theString.reserve(100);
- EXPECT_EQ("abcd", theString);
- unsigned const N = 100000;
- theString.reserve(N);
- for (unsigned i = 0; i < N - 4; ++i)
- theString.push_back('y');
- EXPECT_EQ("abcdyyy", theString.slice(0, 7));
-}
-
-TEST_F(SmallStringTest, Comparisons) {
- EXPECT_EQ(-1, SmallString<10>("aab").compare("aad"));
- EXPECT_EQ( 0, SmallString<10>("aab").compare("aab"));
- EXPECT_EQ( 1, SmallString<10>("aab").compare("aaa"));
- EXPECT_EQ(-1, SmallString<10>("aab").compare("aabb"));
- EXPECT_EQ( 1, SmallString<10>("aab").compare("aa"));
- EXPECT_EQ( 1, SmallString<10>("\xFF").compare("\1"));
-
- EXPECT_EQ(-1, SmallString<10>("AaB").compare_insensitive("aAd"));
- EXPECT_EQ( 0, SmallString<10>("AaB").compare_insensitive("aab"));
- EXPECT_EQ( 1, SmallString<10>("AaB").compare_insensitive("AAA"));
- EXPECT_EQ(-1, SmallString<10>("AaB").compare_insensitive("aaBb"));
- EXPECT_EQ( 1, SmallString<10>("AaB").compare_insensitive("aA"));
- EXPECT_EQ( 1, SmallString<10>("\xFF").compare_insensitive("\1"));
-
- EXPECT_EQ(-1, SmallString<10>("aab").compare_numeric("aad"));
- EXPECT_EQ( 0, SmallString<10>("aab").compare_numeric("aab"));
- EXPECT_EQ( 1, SmallString<10>("aab").compare_numeric("aaa"));
- EXPECT_EQ(-1, SmallString<10>("aab").compare_numeric("aabb"));
- EXPECT_EQ( 1, SmallString<10>("aab").compare_numeric("aa"));
- EXPECT_EQ(-1, SmallString<10>("1").compare_numeric("10"));
- EXPECT_EQ( 0, SmallString<10>("10").compare_numeric("10"));
- EXPECT_EQ( 0, SmallString<10>("10a").compare_numeric("10a"));
- EXPECT_EQ( 1, SmallString<10>("2").compare_numeric("1"));
- EXPECT_EQ( 0, SmallString<10>("llvm_v1i64_ty").compare_numeric("llvm_v1i64_ty"));
- EXPECT_EQ( 1, SmallString<10>("\xFF").compare_numeric("\1"));
- EXPECT_EQ( 1, SmallString<10>("V16").compare_numeric("V1_q0"));
- EXPECT_EQ(-1, SmallString<10>("V1_q0").compare_numeric("V16"));
- EXPECT_EQ(-1, SmallString<10>("V8_q0").compare_numeric("V16"));
- EXPECT_EQ( 1, SmallString<10>("V16").compare_numeric("V8_q0"));
- EXPECT_EQ(-1, SmallString<10>("V1_q0").compare_numeric("V8_q0"));
- EXPECT_EQ( 1, SmallString<10>("V8_q0").compare_numeric("V1_q0"));
-}
-
-// Check gtest prints SmallString as a string instead of a container of chars.
-// The code is in utils/unittest/googletest/internal/custom/gtest-printers.h
-TEST_F(SmallStringTest, GTestPrinter) {
- EXPECT_EQ(R"("foo")", ::testing::PrintToString(SmallString<1>("foo")));
- const SmallVectorImpl<char> &ErasedSmallString = SmallString<1>("foo");
- EXPECT_EQ(R"("foo")", ::testing::PrintToString(ErasedSmallString));
-}
-
} // namespace
--
2.20.1.windows.1

View File

@@ -0,0 +1,31 @@
From 0e20a9a457bbcef8bd07a0c06fceb9641fba0ad2 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Mon, 9 May 2022 00:18:29 -0400
Subject: [PATCH 27/31] Add convienence feature to SmallString
---
llvm/include/llvm/ADT/SmallString.h | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/ADT/SmallString.h b/llvm/include/llvm/ADT/SmallString.h
index 85987811f3c4..d3d469d45d15 100644
--- a/llvm/include/llvm/ADT/SmallString.h
+++ b/llvm/include/llvm/ADT/SmallString.h
@@ -188,9 +188,11 @@ public:
/// Implicit conversion to std::string_view.
operator std::string_view() const { return str(); }
- explicit operator std::string() const {
- return std::string(this->data(), this->size());
- }
+ /// 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) {
--
2.20.1.windows.1

View File

@@ -0,0 +1,46 @@
From 96ace137b394c0af8b3f1d9f3862cdf171adcfa4 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Sun, 8 May 2022 19:30:43 -0400
Subject: [PATCH 28/31] OS specific changes
---
llvm/lib/Support/ErrorHandling.cpp | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index 77c3a37475d0..f70f15f27da4 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -96,12 +96,7 @@ void llvm::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
fmt::print(stderr, "LLVM ERROR: {}\n", Reason);
}
- // If we reached here, we are failing ungracefully. Run the interrupt handlers
- // to make sure any special cleanups get done, in particular that we remove
- // files registered with RemoveFileOnSignal.
- sys::RunInterruptHandlers();
-
- abort();
+ exit(1);
}
void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
@@ -138,9 +133,15 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
// 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();
}
--
2.20.1.windows.1

View File

@@ -0,0 +1,155 @@
From 6ec969e4a7a0bcbb3b54a48dc2bff84e1b431632 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Mon, 9 May 2022 00:04:30 -0400
Subject: [PATCH 29/31] Use smallvector for UTF conversion
---
llvm/include/llvm/Support/ConvertUTF.h | 6 +++---
llvm/lib/Support/ConvertUTFWrapper.cpp | 6 +++---
llvm/unittests/Support/ConvertUTFTest.cpp | 22 +++++++++++-----------
3 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/Support/ConvertUTF.h b/llvm/include/llvm/Support/ConvertUTF.h
index b085c8a179e8..c82947006afb 100644
--- a/llvm/include/llvm/Support/ConvertUTF.h
+++ b/llvm/include/llvm/Support/ConvertUTF.h
@@ -213,7 +213,7 @@ 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, std::string &Result);
+bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result);
/**
@@ -268,7 +268,7 @@ bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
* \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
-bool convertUTF16ToUTF8String(span<const char> SrcBytes, std::string &Out);
+bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out);
/**
* Converts a UTF16 string into a UTF8 std::string.
@@ -277,7 +277,7 @@ bool convertUTF16ToUTF8String(span<const char> SrcBytes, std::string &Out);
* \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
-bool convertUTF16ToUTF8String(span<const UTF16> Src, std::string &Out);
+bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out);
/**
* Converts a UTF-8 string into a UTF-16 string with native endianness.
diff --git a/llvm/lib/Support/ConvertUTFWrapper.cpp b/llvm/lib/Support/ConvertUTFWrapper.cpp
index 87da616b75d4..c6c52d25adb1 100644
--- a/llvm/lib/Support/ConvertUTFWrapper.cpp
+++ b/llvm/lib/Support/ConvertUTFWrapper.cpp
@@ -84,7 +84,7 @@ bool hasUTF16ByteOrderMark(span<const char> S) {
(S[0] == '\xfe' && S[1] == '\xff')));
}
-bool convertUTF16ToUTF8String(span<const char> SrcBytes, std::string &Out) {
+bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
assert(Out.empty());
// Error out on an uneven byte count.
@@ -135,7 +135,7 @@ bool convertUTF16ToUTF8String(span<const char> SrcBytes, std::string &Out) {
return true;
}
-bool convertUTF16ToUTF8String(span<const UTF16> Src, std::string &Out)
+bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out)
{
return convertUTF16ToUTF8String(
span<const char>(reinterpret_cast<const char *>(Src.data()),
@@ -213,7 +213,7 @@ bool ConvertUTF8toWide(const char *Source, std::wstring &Result) {
return ConvertUTF8toWide(std::string_view(Source), Result);
}
-bool convertWideToUTF8(const std::wstring &Source, std::string &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 =
diff --git a/llvm/unittests/Support/ConvertUTFTest.cpp b/llvm/unittests/Support/ConvertUTFTest.cpp
index 2fee8ad5c012..bbdc041cf1d1 100644
--- a/llvm/unittests/Support/ConvertUTFTest.cpp
+++ b/llvm/unittests/Support/ConvertUTFTest.cpp
@@ -19,22 +19,22 @@ TEST(ConvertUTFTest, ConvertUTF16LittleEndianToUTF8String) {
// Src is the look of disapproval.
alignas(UTF16) static const char Src[] = "\xff\xfe\xa0\x0c_\x00\xa0\x0c";
span<const char> Ref(Src, sizeof(Src) - 1);
- std::string Result;
+ SmallString<20> Result;
bool Success = convertUTF16ToUTF8String(Ref, Result);
EXPECT_TRUE(Success);
std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, Result.string());
}
TEST(ConvertUTFTest, ConvertUTF16BigEndianToUTF8String) {
// Src is the look of disapproval.
alignas(UTF16) static const char Src[] = "\xfe\xff\x0c\xa0\x00_\x0c\xa0";
span<const char> Ref(Src, sizeof(Src) - 1);
- std::string Result;
+ SmallString<20> Result;
bool Success = convertUTF16ToUTF8String(Ref, Result);
EXPECT_TRUE(Success);
std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, Result.string());
}
TEST(ConvertUTFTest, ConvertUTF8ToUTF16String) {
@@ -51,16 +51,16 @@ TEST(ConvertUTFTest, ConvertUTF8ToUTF16String) {
}
TEST(ConvertUTFTest, OddLengthInput) {
- std::string Result;
+ SmallString<20> Result;
bool Success = convertUTF16ToUTF8String(span<const char>("xxxxx", 5), Result);
EXPECT_FALSE(Success);
}
TEST(ConvertUTFTest, Empty) {
- std::string Result;
+ SmallString<20> Result;
bool Success = convertUTF16ToUTF8String(span<const char>(), Result);
EXPECT_TRUE(Success);
- EXPECT_TRUE(Result.empty());
+ EXPECT_TRUE(Result.string().empty());
}
TEST(ConvertUTFTest, HasUTF16BOM) {
@@ -83,11 +83,11 @@ TEST(ConvertUTFTest, UTF16WrappersForConvertUTF16ToUTF8String) {
// Src is the look of disapproval.
alignas(UTF16) static const char Src[] = "\xff\xfe\xa0\x0c_\x00\xa0\x0c";
span<const UTF16> SrcRef((const UTF16 *)Src, 4);
- std::string Result;
+ SmallString<20> Result;
bool Success = convertUTF16ToUTF8String(SrcRef, Result);
EXPECT_TRUE(Success);
std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, Result.string());
}
TEST(ConvertUTFTest, ConvertUTF8toWide) {
@@ -107,11 +107,11 @@ TEST(ConvertUTFTest, ConvertUTF8toWide) {
TEST(ConvertUTFTest, convertWideToUTF8) {
// Src is the look of disapproval.
static const wchar_t Src[] = L"\x0ca0_\x0ca0";
- std::string Result;
+ SmallString<20> Result;
bool Success = convertWideToUTF8(Src, Result);
EXPECT_TRUE(Success);
std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, Result.string());
}
struct ConvertUTFResultContainer {
--
2.20.1.windows.1

View File

@@ -0,0 +1,37 @@
From 6f0f7e6e4256d642673e3441468f44f6bd94fe12 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Thu, 19 May 2022 00:58:36 -0400
Subject: [PATCH 30/31] Prefer to use static pointers in raw_ostream
See #1401
---
llvm/lib/Support/raw_ostream.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 6fa250a68ed8..6be6809ad951 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -601,15 +601,15 @@ void raw_fd_ostream::anchor() {}
raw_fd_ostream &llvm::outs() {
// Set buffer settings to model stdout behavior.
std::error_code EC;
- static raw_fd_ostream S("-", EC, sys::fs::OF_None);
+ static raw_fd_ostream* S = new raw_fd_ostream("-", EC, sys::fs::OF_None);
assert(!EC);
- return S;
+ return *S;
}
raw_fd_ostream &llvm::errs() {
// Set standard error to be unbuffered and tied to outs() by default.
- static raw_fd_ostream S(STDERR_FILENO, false, true);
- return S;
+ 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.
--
2.20.1.windows.1

View File

@@ -0,0 +1,27 @@
From 63e46567fe7f9d3e48beaca7827125bfe06e1004 Mon Sep 17 00:00:00 2001
From: PJ Reiniger <pj.reiniger@gmail.com>
Date: Thu, 19 May 2022 01:12:41 -0400
Subject: [PATCH 31/31] constexpr endian byte swap
---
llvm/include/llvm/Support/Endian.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Support/Endian.h b/llvm/include/llvm/Support/Endian.h
index 5e7c1e961b9d..2e883ff05b7e 100644
--- a/llvm/include/llvm/Support/Endian.h
+++ b/llvm/include/llvm/Support/Endian.h
@@ -55,7 +55,9 @@ inline value_type byte_swap(value_type value, endianness endian) {
/// Swap the bytes of value to match the given endianness.
template<typename value_type, endianness endian>
inline value_type byte_swap(value_type value) {
- return byte_swap(value, endian);
+ if constexpr ((endian != native) && (endian != system_endianness()))
+ sys::swapByteOrder(value);
+ return value;
}
/// Read a value of a particular endianness from memory.
--
2.20.1.windows.1

View File

@@ -0,0 +1,202 @@
#!/usr/bin/env python3
import os
import shutil
from upstream_utils import setup_upstream_repo, comment_out_invalid_includes, walk_cwd_and_copy_if, am_patches, walk_if, copy_to
def run_global_replacements(wpiutil_llvm_files):
for wpi_file in wpiutil_llvm_files:
with open(wpi_file) as f:
content = f.read()
# Rename namespace from llvm to wpi
content = content.replace("namespace llvm", "namespace wpi")
content = content.replace("llvm::", "wpi::")
# Fix #includes
content = content.replace("include \"llvm/ADT", "include \"wpi")
content = content.replace("include \"llvm/Config", "include \"wpi")
content = content.replace("include \"llvm/Support", "include \"wpi")
# Remove unused headers
content = content.replace("#include \"llvm-c/ErrorHandling.h\"\n", "")
content = content.replace("#include \"wpi/Debug.h\"\n", "")
content = content.replace("#include \"wpi/Error.h\"\n", "")
content = content.replace("#include \"wpi/Format.h\"\n", "")
content = content.replace("#include \"wpi/FormatVariadic.h\"\n", "")
content = content.replace("#include \"wpi/NativeFormatting.h\"\n", "")
content = content.replace("#include \"wpi/Threading.h\"\n", "")
content = content.replace("#include \"wpi/DataTypes.h\"\n", "")
content = content.replace("#include \"wpi/llvm-config.h\"\n", "")
content = content.replace("#include \"wpi/abi-breaking.h\"\n", "")
content = content.replace("#include \"wpi/config.h\"\n", "")
content = content.replace("#include \"wpi/Signals.h\"\n", "")
content = content.replace("#include \"wpi/Process.h\"\n", "")
content = content.replace("#include \"wpi/Path.h\"\n", "")
content = content.replace("#include \"wpi/Program.h\"\n", "")
# Fix include guards
content = content.replace("LLVM_ADT_", "WPIUTIL_WPI_")
content = content.replace("LLVM_SUPPORT_", "WPIUTIL_WPI_")
content = content.replace("LLVM_DEFINED_HAS_FEATURE",
"WPI_DEFINED_HAS_FEATURE")
content = content.replace("const std::string_view &",
"std::string_view ")
content = content.replace("sys::fs::openFileForRead",
"fs::OpenFileForRead")
content = content.replace("sys::fs::closeFile", "fs::CloseFile")
content = content.replace("sys::fs::", "fs::")
# Replace wpi/FileSystem.h with wpi/fs.h
content = content.replace("include \"wpi/FileSystem.h\"",
"include \"wpi/fs.h\"")
content = content.replace("#include \"wpi/ReverseIteration.h\"",
"#include \"wpi/PointerLikeTypeTraits.h\"")
# Replace llvm_unreachable() with wpi_unreachable()
content = content.replace("llvm_unreachable", "wpi_unreachable")
content = content.replace("llvm_shutdown", "wpi_shutdown")
content = content.replace("llvm_is_multithreaded()", "1")
# Revert message in copyright header
content = content.replace("/// Defines the wpi::",
"/// Defines the llvm::")
content = content.replace("// end llvm namespace",
"// end wpi namespace")
content = content.replace("// end namespace llvm",
"// end namespace wpi")
content = content.replace("// End llvm namespace",
"// End wpi namespace")
content = content.replace("fs::openFileForRead", "fs::OpenFileForRead")
with open(wpi_file, "w") as f:
f.write(content)
def flattened_llvm_files(llvm, dirs_to_keep):
file_lookup = {}
for dir_to_keep in dirs_to_keep:
dir_to_crawl = os.path.join(llvm, dir_to_keep)
for root, _, files in os.walk(dir_to_crawl):
for f in files:
file_lookup[f] = os.path.join(root, f)
return file_lookup
def find_wpiutil_llvm_files(wpiutil_root, subfolder):
# These files have substantial changes, not worth managing with the patching process
ignore_list = [
"StringExtras.h", "StringExtras.cpp", "MemoryBuffer.cpp",
"MemoryBuffer.h", "SmallVectorMemoryBuffer.h"
]
wpiutil_files = []
for root, _, files in os.walk(os.path.join(wpiutil_root, subfolder)):
for f in files:
if f not in ignore_list:
full_file = os.path.join(root, f)
with open(full_file, 'r') as ff:
contents = ff.read()
if "LLVM Compiler" in contents or "LLVM Project" in contents:
wpiutil_files.append(full_file)
return wpiutil_files
def overwrite_files(wpiutil_files, llvm_files):
# Very sparse rips from LLVM sources. Not worth tyring to make match upstream
unmatched_files_whitelist = ["fs.h", "fs.cpp", "function_ref.h"]
for wpi_file in wpiutil_files:
wpi_base_name = os.path.basename(wpi_file)
if wpi_base_name not in llvm_files:
if wpi_base_name not in unmatched_files_whitelist:
print(f"No file match for {wpi_file}, check if LLVM deleted it")
else:
shutil.copyfile(llvm_files[wpi_base_name], wpi_file)
def overwrite_source(wpiutil_root, llvm_root):
llvm_files = flattened_llvm_files(llvm_root, [
"llvm/include/llvm/ADT/", "llvm/include/llvm/Config",
"llvm/include/llvm/Support/", "llvm/lib/Support/"
])
wpi_files = find_wpiutil_llvm_files(
wpiutil_root, "src/main/native/include/wpi") + find_wpiutil_llvm_files(
wpiutil_root, "src/main/native/cpp/llvm")
overwrite_files(wpi_files, llvm_files)
run_global_replacements(wpi_files)
def overwrite_tests(wpiutil_root, llvm_root):
llvm_files = flattened_llvm_files(llvm_root, [
"llvm/unittests/ADT/", "llvm/unittests/Config",
"llvm/unittests/Support/"
])
wpi_files = find_wpiutil_llvm_files(wpiutil_root,
"src/test/native/cpp/llvm")
overwrite_files(wpi_files, llvm_files)
run_global_replacements(wpi_files)
def main():
root, repo = setup_upstream_repo("https://github.com/llvm/llvm-project",
"llvmorg-13.0.0")
wpiutil = os.path.join(root, "wpiutil")
patch_root = os.path.join(root, "upstream_utils/llvm_patches")
# yapf: disable
frontend_patches = [
os.path.join(patch_root, "0001-Fix-spelling-language-errors.patch"),
os.path.join(patch_root, "0002-Remove-StringRef-ArrayRef-and-Optional.patch"),
os.path.join(patch_root, "0003-Wrap-std-min-max-calls-in-parens-for-windows-warning.patch"),
os.path.join(patch_root, "0004-Change-uniqe_function-storage-size.patch"),
os.path.join(patch_root, "0005-Threading-updates.patch"),
os.path.join(patch_root, "0006-Remove-DJB-hash-dependency.patch"),
os.path.join(patch_root, "0007-ifdef-guard-safety.patch"),
os.path.join(patch_root, "0008-Explicitly-use-std.patch"),
os.path.join(patch_root, "0009-Remove-format_provider.patch"),
os.path.join(patch_root, "0010-Remove-reverse-iterator.patch"),
os.path.join(patch_root, "0011-Remove-allocator-from-collections.patch"),
os.path.join(patch_root, "0012-Remove-EpochTracker.patch"),
os.path.join(patch_root, "0013-Add-compiler-warning-pragrams.patch"),
os.path.join(patch_root, "0014-Remove-unused-functions.patch"),
os.path.join(patch_root, "0015-Detemplatize-small-vector-base.patch"),
os.path.join(patch_root, "0016-Add-vectors-to-raw_ostream.patch"),
os.path.join(patch_root, "0017-Extra-collections-features.patch"),
os.path.join(patch_root, "0018-EpochTracker-abi-macro.patch"),
os.path.join(patch_root, "0019-Delete-numbers-from-mathextras.patch"),
os.path.join(patch_root, "0020-Add-lerp-and-sgn.patch"),
os.path.join(patch_root, "0021-Fixup-includes.patch"),
os.path.join(patch_root, "0022-use-std-is_trivially_copy_constructible.patch"),
os.path.join(patch_root, "0023-Windows-Support.patch"),
os.path.join(patch_root, "0024-Prefer-fmtlib.patch"),
os.path.join(patch_root, "0025-prefer-wpi-s-fs.h.patch"),
os.path.join(patch_root, "0026-Remove-unused-functions.patch"),
os.path.join(patch_root, "0027-Add-convienence-feature-to-SmallString.patch"),
os.path.join(patch_root, "0028-OS-specific-changes.patch"),
os.path.join(patch_root, "0029-Use-smallvector-for-UTF-conversion.patch"),
os.path.join(patch_root, "0030-Prefer-to-use-static-pointers-in-raw_ostream.patch"),
os.path.join(patch_root, "0031-constexpr-endian-byte-swap.patch"),
]
# yapf: enable
am_patches(repo, frontend_patches, use_threeway=True)
overwrite_source(wpiutil, repo)
overwrite_tests(wpiutil, repo)
if __name__ == "__main__":
main()

View File

@@ -4,6 +4,7 @@
#pragma once
#include <algorithm>
#include <array>
#include <functional>
#include <map>

View File

@@ -48,6 +48,8 @@ generatedFileExclude {
src/main/native/include/wpi/SmallString\.h$
src/main/native/include/wpi/SmallVector\.h$
src/main/native/include/wpi/StringMap\.h$
src/main/native/include/wpi/StringMapEntry\.h$
src/main/native/include/wpi/STLForwardCompat\.h$
src/main/native/include/wpi/StringRef\.h$
src/main/native/include/wpi/SwapByteOrder\.h$
src/main/native/include/wpi/Twine\.h$

View File

@@ -49,6 +49,7 @@
#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"

View File

@@ -1,9 +1,8 @@
/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
* 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
*
*===------------------------------------------------------------------------=*/
/*
@@ -829,6 +828,6 @@ std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
#endif // _WIN32
} // namespace llvm
} // namespace wpi
ConvertUTF_RESTORE_WARNINGS

View File

@@ -1,19 +1,68 @@
//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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;
@@ -35,23 +84,28 @@ bool hasUTF16ByteOrderMark(span<const char> S) {
(S[0] == '\xfe' && S[1] == '\xff')));
}
bool convertUTF16ToUTF8String(span<const UTF16> SrcUTF16,
SmallVectorImpl<char> &DstUTF8) {
assert(DstUTF8.empty());
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 (SrcUTF16.empty())
if (SrcBytes.empty())
return true;
const UTF16 *Src = SrcUTF16.begin();
const UTF16 *SrcEnd = SrcUTF16.end();
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] = (ByteSwapped[I] << 8) | (ByteSwapped[I] >> 8);
ByteSwapped[I] = wpi::ByteSwap_16(ByteSwapped[I]);
Src = &ByteSwapped[0];
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
}
@@ -62,25 +116,32 @@ bool convertUTF16ToUTF8String(span<const UTF16> SrcUTF16,
// Just allocate enough space up front. We'll shrink it later. Allocate
// enough that we can fit a null terminator without reallocating.
DstUTF8.resize(SrcUTF16.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
UTF8 *Dst = reinterpret_cast<UTF8*>(&DstUTF8[0]);
UTF8 *DstEnd = Dst + DstUTF8.size();
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) {
DstUTF8.clear();
Out.clear();
return false;
}
DstUTF8.resize(reinterpret_cast<char*>(Dst) - &DstUTF8[0]);
DstUTF8.push_back(0);
DstUTF8.pop_back();
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());
@@ -119,5 +180,74 @@ bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
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

View File

@@ -1,9 +1,8 @@
//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -14,10 +13,10 @@
#include "wpi/ErrorHandling.h"
#include "wpi/SmallVector.h"
#include "wpi/Errc.h"
#include "wpi/WindowsError.h"
#include "fmt/format.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <mutex>
#include <new>
@@ -25,7 +24,6 @@
#ifndef _WIN32
#include <unistd.h>
#endif
#if defined(_MSC_VER)
#include <io.h>
#endif
@@ -53,7 +51,7 @@ static std::mutex ErrorHandlerMutex;
static std::mutex BadAllocErrorHandlerMutex;
void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
void *user_data) {
void *user_data) {
std::scoped_lock Lock(ErrorHandlerMutex);
assert(!ErrorHandler && "Error handler already registered!\n");
ErrorHandler = handler;
@@ -95,7 +93,7 @@ void wpi::report_fatal_error(std::string_view Reason, bool GenCrashDiag) {
}
void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
void *user_data) {
void *user_data) {
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
BadAllocErrorHandler = handler;
@@ -126,13 +124,17 @@ void wpi::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
// Don't call the normal error handler. It may allocate memory. Directly write
// an OOM to stderr and abort.
char OOMMessage[] = "LLVM ERROR: out of memory\n";
const char *OOMMessage = "LLVM ERROR: out of memory\n";
const char *Newline = "\n";
#ifdef _WIN32
int written = ::_write(2, OOMMessage, strlen(OOMMessage));
(void)!::_write(2, OOMMessage, strlen(OOMMessage));
(void)!::_write(2, Reason, strlen(Reason));
(void)!::_write(2, Newline, strlen(Newline));
#else
ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage));
(void)!::write(2, OOMMessage, strlen(OOMMessage));
(void)!::write(2, Reason, strlen(Reason));
(void)!::write(2, Newline, strlen(Newline));
#endif
(void)written;
abort();
}
@@ -142,28 +144,17 @@ static void out_of_memory_new_handler() {
wpi::report_bad_alloc_error("Allocation failed");
}
// Installs new handler that causes crash on allocation failure. It does not
// need to be called explicitly, if this file is linked to application, because
// in this case it is called during construction of 'new_handler_installer'.
// Installs new handler that causes crash on allocation failure. It is called by
// InitLLVM.
void wpi::install_out_of_memory_new_handler() {
static bool out_of_memory_new_handler_installed = false;
if (!out_of_memory_new_handler_installed) {
std::set_new_handler(out_of_memory_new_handler);
out_of_memory_new_handler_installed = true;
}
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");
}
// Static object that causes installation of 'out_of_memory_new_handler' before
// execution of 'main'.
static class NewHandlerInstaller {
public:
NewHandlerInstaller() {
install_out_of_memory_new_handler();
}
} new_handler_installer;
void wpi::wpi_unreachable_internal(const char *msg, const char *file,
unsigned line) {
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.
@@ -183,7 +174,6 @@ void wpi::wpi_unreachable_internal(const char *msg, const char *file,
#ifdef _WIN32
#include <system_error>
#include <winerror.h>
// I'd rather not double the line count of the following.

View File

@@ -1,9 +1,8 @@
//===-------------- lib/Support/Hashing.cpp -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//

View File

@@ -1,9 +1,8 @@
//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -18,43 +17,32 @@
using namespace wpi;
static const ManagedStaticBase *StaticList = nullptr;
static wpi::mutex *ManagedStaticMutex = nullptr;
static std::once_flag mutex_init_flag;
static void initializeMutex() {
ManagedStaticMutex = new wpi::mutex();
}
static wpi::mutex* getManagedStaticMutex() {
std::call_once(mutex_init_flag, initializeMutex);
return ManagedStaticMutex;
}
void ManagedStaticBase::RegisterManagedStatic(void* created,
void (*Deleter)(void*)) const {
std::scoped_lock Lock(*getManagedStaticMutex());
if (!Ptr.load(std::memory_order_relaxed)) {
void *Tmp = created;
Ptr.store(Tmp, std::memory_order_release);
DeleterFn = Deleter;
// Add to list of managed statics.
Next = StaticList;
StaticList = this;
}
static wpi::mutex *getManagedStaticMutex() {
static wpi::mutex m;
return &m;
}
void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
void (*Deleter)(void*)) const {
assert(Creator);
std::scoped_lock Lock(*getManagedStaticMutex());
if (1) {
std::scoped_lock Lock(*getManagedStaticMutex());
if (!Ptr.load(std::memory_order_relaxed)) {
void *Tmp = Creator();
if (!Ptr.load(std::memory_order_relaxed)) {
void *Tmp = Creator();
Ptr.store(Tmp, std::memory_order_release);
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.
@@ -80,9 +68,10 @@ void ManagedStaticBase::destroy() const {
}
/// 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() {
std::scoped_lock Lock(*getManagedStaticMutex());
while (StaticList)
StaticList->destroy();
}

View 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
);
}

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -14,9 +13,9 @@
#include "wpi/SmallPtrSet.h"
#include "wpi/DenseMapInfo.h"
#include "wpi/ErrorHandling.h"
#include "wpi/MathExtras.h"
#include "wpi/MemAlloc.h"
#include "wpi/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -12,21 +11,99 @@
//===----------------------------------------------------------------------===//
#include "wpi/SmallVector.h"
#include "wpi/MemAlloc.h"
#include <cstdint>
#ifdef LLVM_ENABLE_EXCEPTIONS
#include <stdexcept>
#endif
using namespace wpi;
/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like datatypes and is out of line to reduce code duplication.
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
size_t TSize) {
// Ensure we can fit the new capacity in 32 bits.
if (MinCapacity > UINT32_MAX)
report_bad_alloc_error("SmallVector capacity overflow during allocation");
// 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");
size_t NewCapacity = 2 * capacity() + 1; // Always grow.
NewCapacity =
std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
/// 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);

View File

@@ -1,9 +1,8 @@
//===--- StringMap.cpp - String Hash table map implementation -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,7 +14,6 @@
#include "wpi/StringExtras.h"
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
#include <cassert>
using namespace wpi;
@@ -65,23 +63,22 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
}
void StringMapImpl::init(unsigned InitSize) {
assert((InitSize & (InitSize-1)) == 0 &&
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)));
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;
TheTable[NumBuckets] = (StringMapEntryBase *)2;
}
/// LookupBucketFor - Look up the bucket that the specified string should end
@@ -91,12 +88,12 @@ void StringMapImpl::init(unsigned InitSize) {
/// of the string.
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
unsigned HTSize = NumBuckets;
if (HTSize == 0) { // Hash table unallocated so far?
if (HTSize == 0) { // Hash table unallocated so far?
init(16);
HTSize = NumBuckets;
}
unsigned FullHashValue = HashString(Name);
unsigned BucketNo = FullHashValue & (HTSize-1);
unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
unsigned ProbeAmt = 1;
@@ -118,7 +115,8 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
if (BucketItem == getTombstoneVal()) {
// Skip over tombstones. However, remember the first one we see.
if (FirstTombstone == -1) FirstTombstone = BucketNo;
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
@@ -127,7 +125,7 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
// Do the comparison like this because Name isn't necessarily
// null-terminated!
char *ItemStr = (char*)BucketItem+ItemSize;
char *ItemStr = (char *)BucketItem + ItemSize;
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
// We found a match!
return BucketNo;
@@ -135,7 +133,7 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
}
// Okay, we didn't find the item. Probe to the next bucket.
BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
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.
@@ -148,9 +146,10 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
/// 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?
if (HTSize == 0)
return -1; // Really empty table?
unsigned FullHashValue = HashString(Key);
unsigned BucketNo = FullHashValue & (HTSize-1);
unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
unsigned ProbeAmt = 1;
@@ -170,7 +169,7 @@ int StringMapImpl::FindKey(std::string_view Key) const {
// Do the comparison like this because NameStart isn't necessarily
// null-terminated!
char *ItemStr = (char*)BucketItem+ItemSize;
char *ItemStr = (char *)BucketItem + ItemSize;
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
// We found a match!
return BucketNo;
@@ -178,7 +177,7 @@ int StringMapImpl::FindKey(std::string_view Key) const {
}
// Okay, we didn't find the item. Probe to the next bucket.
BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
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.
@@ -189,7 +188,7 @@ int StringMapImpl::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 StringMapImpl::RemoveKey(StringMapEntryBase *V) {
const char *VStr = (char*)V + ItemSize;
const char *VStr = (char *)V + ItemSize;
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
(void)V2;
assert(V == V2 && "Didn't find key?");
@@ -199,7 +198,8 @@ void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
/// 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;
if (Bucket == -1)
return nullptr;
StringMapEntryBase *Result = TheTable[Bucket];
TheTable[Bucket] = getTombstoneVal();
@@ -220,7 +220,7 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
// 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;
NewSize = NumBuckets * 2;
} else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
NumBuckets / 8)) {
NewSize = NumBuckets;
@@ -231,11 +231,11 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
unsigned NewBucketNo = BucketNo;
// Allocate one extra bucket which will always be non-empty. This allows the
// iterators to stop at end.
auto NewTableArray = static_cast<StringMapEntryBase **>(
safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
auto NewTableArray = static_cast<StringMapEntryBase **>(safe_calloc(
NewSize + 1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
NewTableArray[NewSize] = (StringMapEntryBase*)2;
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.
@@ -244,10 +244,10 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
if (Bucket && Bucket != getTombstoneVal()) {
// Fast case, bucket available.
unsigned FullHash = HashTable[I];
unsigned NewBucket = FullHash & (NewSize-1);
unsigned NewBucket = FullHash & (NewSize - 1);
if (!NewTableArray[NewBucket]) {
NewTableArray[FullHash & (NewSize-1)] = Bucket;
NewHashArray[FullHash & (NewSize-1)] = FullHash;
NewTableArray[FullHash & (NewSize - 1)] = Bucket;
NewHashArray[FullHash & (NewSize - 1)] = FullHash;
if (I == BucketNo)
NewBucketNo = NewBucket;
continue;
@@ -256,7 +256,7 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
// Otherwise probe for a spot.
unsigned ProbeSize = 1;
do {
NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
} while (NewTableArray[NewBucket]);
// Finally found a slot. Fill it in.

View File

@@ -1,9 +1,8 @@
//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -19,8 +18,8 @@
//=== is guaranteed to work on *all* Win32 variants.
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H
#define LLVM_SUPPORT_WINDOWSSUPPORT_H
#ifndef WPIUTIL_WPI_WINDOWSSUPPORT_H
#define WPIUTIL_WPI_WINDOWSSUPPORT_H
// mingw-w64 tends to define it as 0x0502 in its headers.
#undef _WIN32_WINNT
@@ -38,10 +37,10 @@
#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 <string_view>
#include <system_error>
#define WIN32_NO_STATUS
#include <windows.h>
@@ -49,6 +48,9 @@
#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
@@ -81,23 +83,19 @@ inline bool RunningWindows8OrGreater() {
return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
}
inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) {
if (!ErrMsg)
return true;
char *buffer = NULL;
DWORD LastError = GetLastError();
DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, LastError, 0, (LPSTR)&buffer, 1, NULL);
if (R)
*ErrMsg = prefix + ": " + buffer;
else
*ErrMsg = prefix + ": Unknown error";
*ErrMsg += " (0x" + wpi::utohexstr(LastError) + ")";
/// 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();
LocalFree(buffer);
return R != 0;
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>
@@ -164,6 +162,22 @@ struct JobHandleTraits : CommonHandleTraits {
}
};
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;
@@ -190,6 +204,7 @@ 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;

View File

@@ -1,9 +1,8 @@
//===--- raw_os_ostream.cpp - Implement the raw_os_ostream class ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//

View File

@@ -1,9 +1,8 @@
//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -21,19 +20,17 @@
#include "wpi/StringExtras.h"
#include "wpi/Compiler.h"
#include "wpi/ErrorHandling.h"
#include "wpi/MathExtras.h"
#include "wpi/WindowsError.h"
#include "wpi/fs.h"
#include "wpi/MathExtras.h"
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <cstdio>
#include <iterator>
#include <sys/stat.h>
#include <system_error>
// <fcntl.h> may provide O_BINARY.
#include <fcntl.h>
# include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
@@ -64,6 +61,17 @@
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>
@@ -78,13 +86,10 @@ raw_ostream::~raw_ostream() {
assert(OutBufCur == OutBufStart &&
"raw_ostream destructor called with non-empty buffer!");
if (BufferMode == InternalBuffer)
if (BufferMode == BufferKind::InternalBuffer)
delete [] OutBufStart;
}
// An out of line virtual method to provide a home for the class vtable.
void raw_ostream::handle() {}
size_t raw_ostream::preferred_buffer_size() const {
// BUFSIZ is intended to be a reasonable default.
return BUFSIZ;
@@ -101,14 +106,14 @@ void raw_ostream::SetBuffered() {
void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
BufferKind Mode) {
assert(((Mode == Unbuffered && !BufferStart && Size == 0) ||
(Mode != Unbuffered && BufferStart && Size != 0)) &&
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 == InternalBuffer)
if (BufferMode == BufferKind::InternalBuffer)
delete [] OutBufStart;
OutBufStart = BufferStart;
OutBufEnd = OutBufStart+Size;
@@ -162,15 +167,15 @@ void raw_ostream::flush_nonempty() {
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
size_t Length = OutBufCur - OutBufStart;
OutBufCur = OutBufStart;
write_impl(OutBufStart, Length);
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 == Unbuffered) {
write_impl(reinterpret_cast<char*>(&C), 1);
if (BufferMode == BufferKind::Unbuffered) {
flush_tied_then_write(reinterpret_cast<char *>(&C), 1);
return *this;
}
// Set up a buffer and start over.
@@ -189,8 +194,8 @@ 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 == Unbuffered) {
write_impl(Ptr, Size);
if (BufferMode == BufferKind::Unbuffered) {
flush_tied_then_write(Ptr, Size);
return *this;
}
// Set up a buffer and start over.
@@ -206,7 +211,7 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
assert(NumBytes != 0 && "undefined behavior");
size_t BytesToWrite = Size - (Size % NumBytes);
write_impl(Ptr, BytesToWrite);
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.
@@ -247,6 +252,13 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
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,
@@ -294,8 +306,7 @@ static int getFD(std::string_view Filename, std::error_code &EC,
// the owner of stdout and may set the "binary" flag globally based on Flags.
if (Filename == "-") {
EC = std::error_code();
// If user requested binary then put stdout into binary mode if
// possible.
// Change stdout's text/binary mode based on the Flags.
if (!(Flags & fs::OF_Text)) {
#if defined(_WIN32)
_setmode(_fileno(stdout), _O_BINARY);
@@ -305,11 +316,10 @@ static int getFD(std::string_view Filename, std::error_code &EC,
}
fs::file_t F;
if (Access & fs::FA_Read) {
if (Access & fs::FA_Read)
F = fs::OpenFileForReadWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
} else {
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);
@@ -345,13 +355,16 @@ raw_fd_ostream::raw_fd_ostream(std::string_view Filename, std::error_code &EC,
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
/// closes the file when the stream is destroyed.
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
: raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) {
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
@@ -370,7 +383,6 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);
#ifdef _WIN32
// MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes.
SupportsSeeking = loc != (off_t)-1 && ::GetFileType(reinterpret_cast<HANDLE>(::_get_osfhandle(FD))) != FILE_TYPE_PIPE;
#else
SupportsSeeking = loc != (off_t)-1;
@@ -402,7 +414,7 @@ raw_fd_ostream::~raw_fd_ostream() {
// destructing raw_ostream objects which may have errors.
if (has_error())
report_fatal_error("IO failure on output stream: " + error().message(),
/*GenCrashDiag=*/false);
/*gen_crash_diag=*/false);
}
#if defined(_WIN32)
@@ -565,7 +577,7 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
// 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) && isatty(FD))
if (S_ISCHR(statbuf.st_mode) && is_displayed())
return 0;
// Return the preferred block size.
return statbuf.st_blksize;
@@ -580,28 +592,45 @@ void raw_fd_ostream::anchor() {}
// outs(), errs(), nulls()
//===----------------------------------------------------------------------===//
/// outs() - This returns a reference to a raw_ostream for standard output.
/// Use it like: outs() << "foo" << "bar";
raw_ostream &wpi::outs() {
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::F_None);
static raw_fd_ostream* S = new raw_fd_ostream("-", EC, fs::OF_None);
assert(!EC);
return *S;
}
/// errs() - This returns a reference to a raw_ostream for standard error.
/// Use it like: errs() << "foo" << "bar";
raw_ostream &wpi::errs() {
// Set standard error to be unbuffered by default.
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 = new raw_null_ostream;
return *S;
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;
}
//===----------------------------------------------------------------------===//
@@ -691,15 +720,18 @@ raw_null_ostream::~raw_null_ostream() {
#endif
}
void raw_null_ostream::write_impl(const char * /*Ptr*/, size_t /*Size*/) {}
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_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() {}

View File

@@ -1,146 +1,34 @@
//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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 AlignedCharArray and AlignedCharArrayUnion classes.
// This file defines the AlignedCharArrayUnion class.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_ALIGNOF_H
#define WPIUTIL_WPI_ALIGNOF_H
#include "wpi/Compiler.h"
#include <cstddef>
#include <type_traits>
namespace wpi {
/// \struct AlignedCharArray
/// Helper for building an aligned character array type.
/// A suitably aligned and sized character array member which can hold elements
/// of any type.
///
/// This template is used to explicitly build up a collection of aligned
/// character array types. We have to build these up using a macro and explicit
/// specialization to cope with MSVC (at least till 2015) where only an
/// integer literal can be used to specify an alignment constraint. Once built
/// up here, we can then begin to indirect between these using normal C++
/// template parameters.
// MSVC requires special handling here.
#ifndef _MSC_VER
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray {
alignas(Alignment) char buffer[Size];
/// 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)];
};
#else // _MSC_VER
/// Create a type with an aligned char buffer.
template<std::size_t Alignment, std::size_t Size>
struct AlignedCharArray;
// We provide special variations of this template for the most common
// alignments because __declspec(align(...)) doesn't actually work when it is
// a member of a by-value function argument in MSVC, even if the alignment
// request is something reasonably like 8-byte or 16-byte. Note that we can't
// even include the declspec with the union that forces the alignment because
// MSVC warns on the existence of the declspec despite the union member forcing
// proper alignment.
template<std::size_t Size>
struct AlignedCharArray<1, Size> {
union {
char aligned;
char buffer[Size];
};
};
template<std::size_t Size>
struct AlignedCharArray<2, Size> {
union {
short aligned;
char buffer[Size];
};
};
template<std::size_t Size>
struct AlignedCharArray<4, Size> {
union {
int aligned;
char buffer[Size];
};
};
template<std::size_t Size>
struct AlignedCharArray<8, Size> {
union {
double aligned;
char buffer[Size];
};
};
// The rest of these are provided with a __declspec(align(...)) and we simply
// can't pass them by-value as function arguments on MSVC.
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
template<std::size_t Size> \
struct AlignedCharArray<x, Size> { \
__declspec(align(x)) char buffer[Size]; \
};
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
#endif // _MSC_VER
namespace detail {
template <typename T1,
typename T2 = char, typename T3 = char, typename T4 = char,
typename T5 = char, typename T6 = char, typename T7 = char,
typename T8 = char, typename T9 = char, typename T10 = char>
class AlignerImpl {
T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10;
AlignerImpl() = delete;
};
template <typename T1,
typename T2 = char, typename T3 = char, typename T4 = char,
typename T5 = char, typename T6 = char, typename T7 = char,
typename T8 = char, typename T9 = char, typename T10 = char>
union SizerImpl {
char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)],
arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)],
arr9[sizeof(T9)], arr10[sizeof(T10)];
};
} // end namespace detail
/// This union template exposes a suitably aligned and sized character
/// array member which can hold elements of any of up to ten types.
///
/// These types may be arrays, structs, or any other types. The goal is to
/// expose a char array buffer member which can be used as suitable storage for
/// a placement new of any of these types. Support for more than ten types can
/// be added at the cost of more boilerplate.
template <typename T1,
typename T2 = char, typename T3 = char, typename T4 = char,
typename T5 = char, typename T6 = char, typename T7 = char,
typename T8 = char, typename T9 = char, typename T10 = char>
struct AlignedCharArrayUnion : wpi::AlignedCharArray<
alignof(wpi::detail::AlignerImpl<T1, T2, T3, T4, T5,
T6, T7, T8, T9, T10>),
sizeof(::wpi::detail::SizerImpl<T1, T2, T3, T4, T5,
T6, T7, T8, T9, T10>)> {
};
} // end namespace wpi
#endif // LLVM_SUPPORT_ALIGNOF_H
#endif // WPIUTIL_WPI_ALIGNOF_H

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
@@ -33,21 +32,21 @@ template <typename D = std::chrono::nanoseconds>
using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
/// Convert a TimePoint to std::time_t
LLVM_ATTRIBUTE_ALWAYS_INLINE std::time_t toTimeT(TimePoint<> TP) {
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
LLVM_ATTRIBUTE_ALWAYS_INLINE TimePoint<std::chrono::seconds>
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
LLVM_ATTRIBUTE_ALWAYS_INLINE 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))

View File

@@ -1,21 +1,24 @@
//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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.
// 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)
@@ -34,14 +37,20 @@
# define __has_attribute(x) 0
#endif
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
// 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.
@@ -61,14 +70,22 @@
/// \macro LLVM_MSC_PREREQ
/// Is the compiler MSVC of at least the specified version?
/// The common \param version values to check for are:
/// * 1900: Microsoft Visual Studio 2015 / 14.0
/// * 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 2015.
#if !LLVM_MSC_PREREQ(1900)
#error wpiutil requires at least MSVC 2015.
// We require at least MSVC 2017.
#if !LLVM_MSC_PREREQ(1910)
#error LLVM requires at least MSVC 2017.
#endif
#else
@@ -79,9 +96,11 @@
/// 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.
/// 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)
#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
@@ -100,6 +119,24 @@
#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)
@@ -117,25 +154,37 @@
#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 __cplusplus > 201402L && __has_cpp_attribute(nodiscard)
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
#define LLVM_NODISCARD [[nodiscard]]
// Detect MSVC directly, since __cplusplus still defaults to old version
#elif _MSVC_LANG >= 201703L
#define LLVM_NODISCARD [[nodiscard]]
#elif _MSC_VER
#define LLVM_NODISCARD
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define LLVM_NODISCARD
#elif __has_cpp_attribute(clang::warn_unused_result)
#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.
@@ -152,6 +201,14 @@
#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.
@@ -200,7 +257,7 @@
/// errors, just use it in GCC 4.0 and later.
#ifndef LLVM_ATTRIBUTE_ALWAYS_INLINE
#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) inline
#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER)
#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
#else
@@ -242,26 +299,44 @@
/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
#ifndef LLVM_FALLTHROUGH
#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
#define LLVM_FALLTHROUGH [[fallthrough]]
// Detect MSVC directly, since __cplusplus still defaults to old version
#elif _MSVC_LANG >= 201703L
#define LLVM_FALLTHROUGH [[fallthrough]]
#elif _MSC_VER
#define LLVM_FALLTHROUGH
#elif __has_cpp_attribute(gnu::fallthrough)
#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
#elif !__cplusplus
// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
// error when __has_cpp_attribute is given a scoped attribute in C mode.
#define LLVM_FALLTHROUGH
#elif __has_cpp_attribute(clang::fallthrough)
#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
@@ -273,20 +348,10 @@
#endif
// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
// This macro will be removed.
// Use C++14's attribute instead: [[deprecated("message")]]
#ifndef LLVM_ATTRIBUTE_DEPRECATED
#if __has_feature(attribute_deprecated_with_message)
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
decl __attribute__((deprecated(message)))
#elif defined(__GNUC__)
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
decl __attribute__((deprecated))
#elif defined(_MSC_VER)
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
__declspec(deprecated(message)) decl
#else
# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
decl
#endif
#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
#endif
/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
@@ -341,7 +406,6 @@
#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
#elif defined(LLVM_BUILTIN_UNREACHABLE)
// As of today, clang does not support __builtin_assume_aligned.
# define LLVM_ASSUME_ALIGNED(p, a) \
(((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
#else
@@ -349,16 +413,6 @@
#endif
#endif
/// \macro LLVM_ALIGNAS
/// Used to specify a minimum alignment for a structure or variable.
#ifndef LLVM_ALIGNAS
#if __GNUC__ && !__has_feature(cxx_alignas) && !LLVM_GNUC_PREREQ(4, 8, 1)
# define LLVM_ALIGNAS(x) __attribute__((aligned(x)))
#else
# define LLVM_ALIGNAS(x) alignas(x)
#endif
#endif
/// \macro LLVM_PACKED
/// Used to specify a packed structure.
/// LLVM_PACKED(
@@ -391,8 +445,8 @@
/// \macro LLVM_PTR_SIZE
/// A constant integer equivalent to the value of sizeof(void*).
/// Generally used in combination with LLVM_ALIGNAS or when doing computation in
/// the preprocessor.
/// 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__
@@ -407,6 +461,73 @@
#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
@@ -451,66 +572,28 @@
/// extern globals, and static globals.
///
/// This is essentially an extremely restricted analog to C++11's thread_local
/// support, and uses that when available. However, it falls back on
/// platform-specific or vendor-provided extensions when necessary. These
/// extensions don't support many of the C++11 thread_local's features. You
/// should only use this for PODs that you can statically initialize to
/// some constant value. In almost all circumstances this is most appropriate
/// for use with a pointer, integer, or small aggregation of pointers and
/// integers.
#ifndef LLVM_THREAD_LOCAL
#if __has_feature(cxx_thread_local)
/// 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
#elif defined(_MSC_VER)
// MSVC supports this with a __declspec.
#define LLVM_THREAD_LOCAL __declspec(thread)
#else
// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
// we only need the restricted functionality that provides.
#define LLVM_THREAD_LOCAL __thread
#endif
/// \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
namespace wpi {
/// 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.
inline void *allocate_buffer(size_t Size, size_t Alignment) {
return ::operator new(Size
#ifdef __cpp_aligned_new
,
std::align_val_t(Alignment)
#endif
);
}
/// 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.
inline void 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
);
}
} // End namespace wpi
#endif

View File

@@ -1,9 +1,8 @@
/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
* 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
*
*==------------------------------------------------------------------------==*/
/*
@@ -87,8 +86,8 @@
------------------------------------------------------------------------ */
#ifndef LLVM_SUPPORT_CONVERTUTF_H
#define LLVM_SUPPORT_CONVERTUTF_H
#ifndef WPIUTIL_WPI_CONVERTUTF_H
#define WPIUTIL_WPI_CONVERTUTF_H
#include "wpi/span.h"
@@ -97,14 +96,11 @@
#include <string_view>
#include <system_error>
// Wrap everything in namespace wpi so that programs can link with wpiutil and
// Wrap everything in namespace wpi so that programs can link with llvm and
// their own version of the unicode libraries.
namespace wpi {
template <typename T>
class SmallVectorImpl;
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
@@ -187,6 +183,38 @@ 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.
@@ -215,10 +243,10 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
*
* \sa ConvertUTF8toUTF32
*/
static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
const UTF8 *sourceEnd,
UTF32 *target,
ConversionFlags flags) {
inline ConversionResult convertUTF8Sequence(const UTF8 **source,
const UTF8 *sourceEnd,
UTF32 *target,
ConversionFlags flags) {
if (*source == sourceEnd)
return sourceExhausted;
unsigned size = getNumBytesForUTF8(**source);
@@ -234,12 +262,22 @@ static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
/**
* Converts a UTF-16 string into a UTF-8 string.
* 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 UTF16> SrcUTF16,
SmallVectorImpl<char> &DstUTF8);
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.

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -19,12 +18,14 @@
#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
#include "wpi/MemAlloc.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <new>
#include <type_traits>
@@ -38,6 +39,8 @@ namespace detail {
// implementation without requiring two members.
template <typename KeyT, typename ValueT>
struct DenseMapPair : public std::pair<KeyT, ValueT> {
using std::pair<KeyT, ValueT>::pair;
KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
@@ -113,8 +116,8 @@ public:
}
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
if (isPodLike<KeyT>::value && isPodLike<ValueT>::value) {
// Use a simpler loop when these are trivial types.
if (std::is_trivially_destructible<ValueT>::value) {
// Use a simpler loop when values don't need destruction.
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
P->getFirst() = EmptyKey;
} else {
@@ -143,13 +146,15 @@ public:
iterator find(const_arg_type_t<KeyT> Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeIterator(TheBucket, getBucketsEnd(), *this, true);
return makeIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
const_iterator find(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
return makeConstIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
@@ -162,14 +167,16 @@ public:
iterator find_as(const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeIterator(TheBucket, getBucketsEnd(), *this, true);
return makeIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
template<class LookupKeyT>
const_iterator find_as(const LookupKeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
return makeConstIterator(TheBucket, getBucketsEnd(),
*this, true);
return end();
}
@@ -203,16 +210,16 @@ public:
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket =
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
// Inserts key,value pair into the map if the key isn't already in the map.
@@ -222,15 +229,15 @@ public:
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
/// Alternate version of insert() which allows a different, and possibly
@@ -243,16 +250,16 @@ public:
const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), *this, true),
true);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
*this, true),
true);
}
/// insert - Range insertion of pairs.
@@ -389,7 +396,8 @@ protected:
setNumEntries(other.getNumEntries());
setNumTombstones(other.getNumTombstones());
if (isPodLike<KeyT>::value && isPodLike<ValueT>::value)
if (std::is_trivially_copyable<KeyT>::value &&
std::is_trivially_copyable<ValueT>::value)
memcpy(reinterpret_cast<void *>(getBuckets()), other.getBuckets(),
getNumBuckets() * sizeof(BucketT));
else
@@ -679,7 +687,7 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
unsigned NumBuckets;
public:
/// Create a DenseMap wth an optional \p InitialReserve that guarantee that
/// Create a DenseMap with an optional \p InitialReserve that guarantee that
/// this number of elements can be inserted in the map without grow()
explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); }
@@ -706,7 +714,7 @@ public:
~DenseMap() {
this->destroyAll();
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
}
void swap(DenseMap& RHS) {
@@ -726,7 +734,7 @@ public:
DenseMap& operator=(DenseMap &&other) {
this->destroyAll();
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
init(0);
swap(other);
return *this;
@@ -734,7 +742,7 @@ public:
void copyFrom(const DenseMap& other) {
this->destroyAll();
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
if (allocateBuckets(other.NumBuckets)) {
this->BaseT::copyFrom(other);
} else {
@@ -767,10 +775,12 @@ public:
this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets);
// Free the old table.
operator delete(OldBuckets);
deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets,
alignof(BucketT));
}
void shrink_and_clear() {
unsigned OldNumBuckets = NumBuckets;
unsigned OldNumEntries = NumEntries;
this->destroyAll();
@@ -783,7 +793,8 @@ public:
return;
}
operator delete(Buckets);
deallocate_buffer(Buckets, sizeof(BucketT) * OldNumBuckets,
alignof(BucketT));
init(NewNumBuckets);
}
@@ -819,7 +830,8 @@ private:
return false;
}
Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT) * NumBuckets));
Buckets = static_cast<BucketT *>(
allocate_buffer(sizeof(BucketT) * NumBuckets, alignof(BucketT)));
return true;
}
};
@@ -874,6 +886,9 @@ public:
this->insert(I, E);
}
SmallDenseMap(std::initializer_list<typename BaseT::value_type> Vals)
: SmallDenseMap(Vals.begin(), Vals.end()) {}
~SmallDenseMap() {
this->destroyAll();
deallocateBuckets();
@@ -904,7 +919,7 @@ public:
std::swap(*LHSB, *RHSB);
continue;
}
// Swap separately and handle any assymetry.
// Swap separately and handle any asymmetry.
std::swap(LHSB->getFirst(), RHSB->getFirst());
if (hasLHSValue) {
::new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond()));
@@ -986,16 +1001,13 @@ public:
}
void grow(unsigned AtLeast) {
if (AtLeast >= InlineBuckets)
if (AtLeast > InlineBuckets)
AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast-1));
if (Small) {
if (AtLeast < InlineBuckets)
return; // Nothing to do.
// First move the inline buckets into a temporary storage.
AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage;
BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer);
BucketT *TmpBegin = reinterpret_cast<BucketT *>(&TmpStorage);
BucketT *TmpEnd = TmpBegin;
// Loop over the buckets, moving non-empty, non-tombstones into the
@@ -1015,10 +1027,13 @@ public:
P->getFirst().~KeyT();
}
// Now make this map use the large rep, and move all the entries back
// into it.
Small = false;
new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
// AtLeast == InlineBuckets can happen if there are many tombstones,
// and grow() is used to remove them. Usually we always switch to the
// large rep here.
if (AtLeast > InlineBuckets) {
Small = false;
new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
}
this->moveFromOldBuckets(TmpBegin, TmpEnd);
return;
}
@@ -1034,7 +1049,8 @@ public:
this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets);
// Free the old table.
operator delete(OldRep.Buckets);
deallocate_buffer(OldRep.Buckets, sizeof(BucketT) * OldRep.NumBuckets,
alignof(BucketT));
}
void shrink_and_clear() {
@@ -1081,8 +1097,8 @@ private:
assert(Small);
// Note that this cast does not violate aliasing rules as we assert that
// the memory's dynamic type is the small, inline bucket buffer, and the
// 'storage.buffer' static type is 'char *'.
return reinterpret_cast<const BucketT *>(storage.buffer);
// 'storage' is a POD containing a char buffer.
return reinterpret_cast<const BucketT *>(&storage);
}
BucketT *getInlineBuckets() {
@@ -1093,7 +1109,7 @@ private:
const LargeRep *getLargeRep() const {
assert(!Small);
// Note, same rule about aliasing as with getInlineBuckets.
return reinterpret_cast<const LargeRep *>(storage.buffer);
return reinterpret_cast<const LargeRep *>(&storage);
}
LargeRep *getLargeRep() {
@@ -1118,15 +1134,17 @@ private:
if (Small)
return;
operator delete(getLargeRep()->Buckets);
deallocate_buffer(getLargeRep()->Buckets,
sizeof(BucketT) * getLargeRep()->NumBuckets,
alignof(BucketT));
getLargeRep()->~LargeRep();
}
LargeRep allocateBuckets(unsigned Num) {
assert(Num > InlineBuckets && "Must allocate more buckets than are inline");
LargeRep Rep = {
static_cast<BucketT*>(operator new(sizeof(BucketT) * Num)), Num
};
LargeRep Rep = {static_cast<BucketT *>(allocate_buffer(
sizeof(BucketT) * Num, alignof(BucketT))),
Num};
return Rep;
}
};
@@ -1137,8 +1155,6 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
using ConstIterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
public:
using difference_type = ptrdiff_t;
using value_type =
@@ -1167,7 +1183,7 @@ public:
// for const iterator destinations so it doesn't end up as a user defined copy
// constructor.
template <bool IsConstSrc,
typename = typename std::enable_if<!IsConstSrc && IsConst>::type>
typename = std::enable_if_t<!IsConstSrc && IsConst>>
DenseMapIterator(
const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
: DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
@@ -1181,19 +1197,18 @@ public:
return Ptr;
}
bool operator==(const ConstIterator &RHS) const {
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
friend bool operator==(const DenseMapIterator &LHS,
const DenseMapIterator &RHS) {
assert((!LHS.Ptr || LHS.isHandleInSync()) && "handle not in sync!");
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
assert(getEpochAddress() == RHS.getEpochAddress() &&
assert(LHS.getEpochAddress() == RHS.getEpochAddress() &&
"comparing incomparable iterators!");
return Ptr == RHS.Ptr;
return LHS.Ptr == RHS.Ptr;
}
bool operator!=(const ConstIterator &RHS) const {
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
assert(getEpochAddress() == RHS.getEpochAddress() &&
"comparing incomparable iterators!");
return Ptr != RHS.Ptr;
friend bool operator!=(const DenseMapIterator &LHS,
const DenseMapIterator &RHS) {
return !(LHS == RHS);
}
inline DenseMapIterator& operator++() { // Preincrement
@@ -1236,4 +1251,4 @@ inline size_t capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
} // end namespace wpi
#endif // LLVM_ADT_DENSEMAP_H
#endif // WPIUTIL_WPI_DENSEMAP_H

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,16 +14,31 @@
#define WPIUTIL_WPI_DENSEMAPINFO_H
#include "wpi/Hashing.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/span.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <string_view>
#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();
@@ -33,18 +47,28 @@ struct DenseMapInfo {
//static bool isEqual(const T &LHS, const T &RHS);
};
// Provide DenseMapInfo for all pointers.
// 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 <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
Val <<= Log2MaxAlign;
return reinterpret_cast<T*>(Val);
}
static inline T* getTombstoneKey() {
uintptr_t Val = static_cast<uintptr_t>(-2);
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
Val <<= Log2MaxAlign;
return reinterpret_cast<T*>(Val);
}
@@ -67,6 +91,17 @@ template<> struct DenseMapInfo<char> {
}
};
// 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; }
@@ -187,17 +222,8 @@ struct DenseMapInfo<std::pair<T, U>> {
}
static unsigned getHashValue(const Pair& PairVal) {
uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
| (uint64_t)SecondInfo::getHashValue(PairVal.second);
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;
return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first),
SecondInfo::getHashValue(PairVal.second));
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
@@ -206,59 +232,53 @@ struct DenseMapInfo<std::pair<T, U>> {
}
};
// Provide DenseMapInfo for std::string_view.
template <> struct DenseMapInfo<std::string_view> {
static inline std::string_view getEmptyKey() {
return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
0);
// 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 std::string_view getTombstoneKey() {
return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
0);
static inline Tuple getTombstoneKey() {
return Tuple(DenseMapInfo<Ts>::getTombstoneKey()...);
}
static unsigned getHashValue(std::string_view Val) {
assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
assert(Val.data() != getTombstoneKey().data() &&
"Cannot hash the tombstone key!");
return (unsigned)(hash_value(Val));
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));
}
static bool isEqual(std::string_view LHS, std::string_view RHS) {
if (RHS.data() == getEmptyKey().data())
return LHS.data() == getEmptyKey().data();
if (RHS.data() == getTombstoneKey().data())
return LHS.data() == getTombstoneKey().data();
return LHS == RHS;
}
};
// Provide DenseMapInfo for spans.
template <typename T> struct DenseMapInfo<span<T>> {
static inline span<T> getEmptyKey() {
return span<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(0)),
size_t(0));
template <unsigned I>
static unsigned getHashValueImpl(const Tuple &, std::true_type) {
return 0;
}
static inline span<T> getTombstoneKey() {
return span<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(1)),
size_t(0));
static unsigned getHashValue(const std::tuple<Ts...> &values) {
std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
return getHashValueImpl<0>(values, atEnd);
}
static unsigned getHashValue(span<T> Val) {
assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
assert(Val.data() != getTombstoneKey().data() &&
"Cannot hash the tombstone key!");
return (unsigned)(hash_value(Val));
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);
}
static bool isEqual(span<T> LHS, span<T> RHS) {
if (RHS.data() == getEmptyKey().data())
return LHS.data() == getEmptyKey().data();
if (RHS.data() == getTombstoneKey().data())
return LHS.data() == getTombstoneKey().data();
return LHS == RHS;
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);
}
};
@@ -271,4 +291,4 @@ template <> struct DenseMapInfo<hash_code> {
} // end namespace wpi
#endif // LLVM_ADT_DENSEMAPINFO_H
#endif // WPIUTIL_WPI_DENSEMAPINFO_H

View File

@@ -1,9 +1,8 @@
//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -14,14 +13,8 @@
#ifndef WPIUTIL_WPI_ENDIAN_H
#define WPIUTIL_WPI_ENDIAN_H
#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/SwapByteOrder.h"
#if defined(__linux__) || defined(__GNU__)
#include <endian.h>
#endif
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -38,7 +31,7 @@ enum {aligned = 0, unaligned = 1};
namespace detail {
// value is either alignment, or alignof(T) if alignment is 0.
/// ::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 };
@@ -49,13 +42,7 @@ struct PickAlignment {
namespace endian {
constexpr endianness system_endianness() {
#ifdef _WIN32
return little;
#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
return big;
#else
return little;
#endif
return sys::IsBigEndianHost ? big : little;
}
template <typename value_type>
@@ -89,13 +76,7 @@ template<typename value_type,
endianness endian,
std::size_t alignment>
inline value_type read(const void *memory) {
value_type ret;
memcpy(&ret,
LLVM_ASSUME_ALIGNED(
memory, (detail::PickAlignment<value_type, alignment>::value)),
sizeof(value_type));
return byte_swap<value_type, endian>(ret);
return read<value_type, alignment>(memory, endian);
}
/// Read a value of a particular endianness from a buffer, and increment the
@@ -110,9 +91,7 @@ inline value_type readNext(const CharT *&memory, endianness endian) {
template<typename value_type, endianness endian, std::size_t alignment,
typename CharT>
inline value_type readNext(const CharT *&memory) {
value_type ret = read<value_type, endian, alignment>(memory);
memory += sizeof(value_type);
return ret;
return readNext<value_type, alignment, CharT>(memory, endian);
}
/// Write a value to memory with a particular endianness.
@@ -128,12 +107,12 @@ template<typename value_type,
endianness endian,
std::size_t alignment>
inline void write(void *memory, value_type value) {
value = byte_swap<value_type, endian>(value);
memcpy(LLVM_ASSUME_ALIGNED(
memory, (detail::PickAlignment<value_type, alignment>::value)),
&value, sizeof(value_type));
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>
@@ -152,15 +131,15 @@ inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
val[1] = byte_swap<value_type, endian>(val[1]);
// Shift bits from the lower value into place.
std::make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
// Mask off upper bits after right shift in case of signed type.
std::make_unsigned_t<value_type> numBitsFirstVal =
make_unsigned_t<value_type> numBitsFirstVal =
(sizeof(value_type) * 8) - startBit;
lowerVal &= ((std::make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
// Get the bits from the upper value.
std::make_unsigned_t<value_type> upperVal =
val[1] & (((std::make_unsigned_t<value_type>)1 << startBit) - 1);
make_unsigned_t<value_type> upperVal =
val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
// Shift them in to place.
upperVal <<= numBitsFirstVal;
@@ -188,15 +167,15 @@ inline void writeAtBitAlignment(void *memory, value_type value,
// Mask off any existing bits in the upper part of the lower value that
// we want to replace.
val[0] &= ((std::make_unsigned_t<value_type>)1 << startBit) - 1;
std::make_unsigned_t<value_type> numBitsFirstVal =
val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
make_unsigned_t<value_type> numBitsFirstVal =
(sizeof(value_type) * 8) - startBit;
std::make_unsigned_t<value_type> lowerVal = value;
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 &= (((std::make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
// Now shift the new bits into place
lowerVal <<= startBit;
}
@@ -204,11 +183,11 @@ inline void writeAtBitAlignment(void *memory, value_type value,
// Mask off any existing bits in the lower part of the upper value that
// we want to replace.
val[1] &= ~(((std::make_unsigned_t<value_type>)1 << startBit) - 1);
val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
// Next shift the bits that go into the upper value into position.
std::make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
// Mask off upper bits after right shift in case of signed type.
upperVal &= ((std::make_unsigned_t<value_type>)1 << startBit) - 1;
upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
val[1] |= upperVal;
// Finally, rewrite values.
@@ -224,10 +203,13 @@ inline void writeAtBitAlignment(void *memory, value_type value,
namespace detail {
template<typename value_type,
endianness endian,
std::size_t alignment>
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; }
@@ -263,8 +245,9 @@ struct packed_endian_specific_integral {
}
private:
AlignedCharArray<PickAlignment<value_type, alignment>::value,
sizeof(value_type)> Value;
struct {
alignas(ALIGN) char buffer[sizeof(value_type)];
} Value;
public:
struct ref {
@@ -355,6 +338,17 @@ using unaligned_int32_t =
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) {

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -13,29 +12,15 @@
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_EPOCH_TRACKER_H
#define WPIUTIL_WPI_EPOCH_TRACKER_H
#ifndef WPIUTIL_WPI_EPOCHTRACKER_H
#define WPIUTIL_WPI_EPOCHTRACKER_H
#include <cstdint>
namespace wpi {
#ifdef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
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; }
};
};
#else
#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
@@ -90,6 +75,21 @@ public:
};
};
#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

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/Errc.h - Defines the llvm::errc enum --------*- C++ -*-===//
//===- llvm/Support/Errc.h - Defines the wpi::errc enum --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -11,7 +10,7 @@
// some problems with std::errc that can be avoided by using our own
// enumeration:
//
// * std::errc is a namespace in some implementations. That meas that ADL
// * 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;
@@ -23,7 +22,7 @@
// the intersection of all the ones we support.
//
// * std::errc is just marked with is_error_condition_enum. This means that
// common patters like AnErrorCode == errc::no_such_file_or_directory take
// common patterns like AnErrorCode == errc::no_such_file_or_directory take
// 4 virtual calls instead of two comparisons.
//===----------------------------------------------------------------------===//

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -22,8 +21,8 @@ namespace wpi {
namespace sys {
template <typename FailT, typename Fun, typename... Args>
inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
const Args &... As) -> decltype(F(As...)) {
inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F,
const Args &... As) {
decltype(F(As...)) Res;
do {
errno = 0;
@@ -35,4 +34,4 @@ inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
} // namespace sys
} // namespace wpi
#endif // WPIUTIL_WPI_ERRNO_H
#endif // WPIUTIL_WPI_ERRNO_H

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -20,6 +19,7 @@
#include <string_view>
namespace wpi {
/// An error handler callback.
typedef void (*fatal_error_handler_t)(void *user_data,
const std::string& reason,
@@ -65,7 +65,7 @@ namespace wpi {
///
/// 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 exit(1), it
/// 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);
@@ -100,31 +100,32 @@ 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 is expected to return, e.g. the user
/// defined error handler throws an exception.
/// 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), then a bad_alloc exception
/// is thrown, if LLVM is compiled with exception support, otherwise an
/// assertion is called.
void report_bad_alloc_error(const char *Reason, bool GenCrashDiag = true);
/// 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);
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.
/// 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.

View File

@@ -1,9 +1,8 @@
//===- FunctionExtras.h - Function type erasure utilities -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
@@ -12,11 +11,11 @@
/// in `<function>`.
///
/// It provides `unique_function`, which works like `std::function` but supports
/// move-only callable objects.
/// move-only callable objects and const-qualification.
///
/// Future plans:
/// - Add a `function` that provides const, volatile, and ref-qualified support,
/// which doesn't work with `std::function`.
/// - 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
@@ -30,17 +29,29 @@
///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_FUNCTION_EXTRAS_H
#define WPIUTIL_WPI_FUNCTION_EXTRAS_H
#ifndef WPIUTIL_WPI_FUNCTIONEXTRAS_H
#define WPIUTIL_WPI_FUNCTIONEXTRAS_H
#include "wpi/Compiler.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
@@ -49,16 +60,32 @@ template <typename FunctionT> class unique_function;
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <typename ReturnT, typename... ParamTs>
class unique_function<ReturnT(ParamTs...)> {
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;
// MSVC has a bug and ICEs if we give it a particular dependent value
// expression as part of the `std::conditional` below. To work around this,
// we build that into a template struct's constexpr bool.
template <typename T> struct IsSizeLessThanThresholdT {
static constexpr bool value = sizeof(T) <= (2 * sizeof(void *));
};
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
@@ -69,13 +96,24 @@ class unique_function<ReturnT(ParamTs...)> {
// 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 std::conditional<
!std::is_reference<T>::value &&
std::is_trivially_copy_constructible<T>::value &&
std::is_trivially_move_constructible<T>::value &&
IsSizeLessThanThresholdT<T>::value,
T, T &>::type;
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.
@@ -120,8 +158,11 @@ class unique_function<ReturnT(ParamTs...)> {
// For in-line storage, we just provide an aligned character buffer. We
// provide four pointers worth of storage here.
typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
InlineStorage;
// 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
@@ -144,11 +185,25 @@ class unique_function<ReturnT(ParamTs...)> {
.template get<NonTrivialCallbacks *>();
}
void *getInlineStorage() { return &StorageUnion.InlineStorage; }
CallPtrT getCallPtr() const {
return isTrivialCallback() ? getTrivialCallback()
: getNonTrivialCallbacks()->CallPtr;
}
void *getOutOfLineStorage() {
// 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;
}
@@ -160,10 +215,11 @@ class unique_function<ReturnT(ParamTs...)> {
StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
}
template <typename CallableT>
static ReturnT CallImpl(void *CallableAddr, AdjustedParamT<ParamTs>... Params) {
return (*reinterpret_cast<CallableT *>(CallableAddr))(
std::forward<ParamTs>(Params)...);
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>
@@ -177,11 +233,54 @@ class unique_function<ReturnT(ParamTs...)> {
reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
}
public:
unique_function() = default;
unique_function(std::nullptr_t /*null_callable*/) {}
// 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).
~unique_function() {
// 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;
@@ -197,7 +296,7 @@ public:
getOutOfLineStorageAlignment());
}
unique_function(unique_function &&RHS) noexcept {
UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept {
// Copy the callback and inline flag.
CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
@@ -226,83 +325,96 @@ public:
#endif
}
unique_function &operator=(unique_function &&RHS) noexcept {
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->~unique_function();
new (this) unique_function(std::move(RHS));
this->~UniqueFunctionBase();
new (this) UniqueFunctionBase(std::move(RHS));
return *this;
}
template <typename CallableT>
unique_function(CallableT Callable,
std::enable_if_t<
std::is_invocable_r_v<
ReturnT, CallableT, ParamTs...>>* = nullptr) {
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));
// 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.
//
// FIXME: We should use constexpr if here and below to avoid instantiating
// the non-trivial static objects when unnecessary. While the linker should
// remove them, it is still wasteful.
if (std::is_trivially_move_constructible<CallableT>::value &&
std::is_trivially_destructible<CallableT>::value) {
// We need to create a nicely aligned object. We use a static variable
// for this because it is a trivial struct.
static TrivialCallback Callback = { &CallImpl<CallableT> };
CallbackAndInlineFlag = {&Callback, IsInlineStorage};
return;
}
// Otherwise, we need to point at an object that contains all the different
// type erased behaviors needed. Create a static instance of the struct type
// here and then use a pointer to that.
static NonTrivialCallbacks Callbacks = {
&CallImpl<CallableT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
CallbackAndInlineFlag = {&Callbacks, IsInlineStorage};
}
ReturnT operator()(ParamTs... Params) {
void *CallableAddr =
isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
return (isTrivialCallback()
? getTrivialCallback()
: getNonTrivialCallbacks()->CallPtr)(CallableAddr, Params...);
}
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_FUNCTION_H
#endif // WPIUTIL_WPI_FUNCTIONEXTRAS_H

View File

@@ -1,9 +1,8 @@
//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -45,15 +44,14 @@
#ifndef WPIUTIL_WPI_HASHING_H
#define WPIUTIL_WPI_HASHING_H
#include "wpi/Endian.h"
#include "wpi/ErrorHandling.h"
#include "wpi/SwapByteOrder.h"
#include "wpi/type_traits.h"
#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#ifdef _WIN32
@@ -108,8 +106,7 @@ public:
/// differing argument types even if they would implicit promote to a common
/// type without changing the value.
template <typename T>
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
hash_value(T value);
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.
///
@@ -120,6 +117,10 @@ template <typename T> hash_code hash_value(const T *ptr);
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);
@@ -151,7 +152,7 @@ namespace detail {
inline uint64_t fetch64(const char *p) {
uint64_t result;
memcpy(&result, p, sizeof(result));
if (support::endian::system_endianness() == support::big)
if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
}
@@ -159,16 +160,16 @@ inline uint64_t fetch64(const char *p) {
inline uint32_t fetch32(const char *p) {
uint32_t result;
memcpy(&result, p, sizeof(result));
if (support::endian::system_endianness() == support::big)
if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
}
/// Some primes between 2^63 and 2^64 for various uses.
static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
static const uint64_t k1 = 0xb492b66fbe98f273ULL;
static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
static const uint64_t k3 = 0xc949d7c7509e6557ULL;
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
@@ -198,7 +199,7 @@ inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) {
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<uint64_t>(c) << 2));
uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
}
@@ -264,7 +265,7 @@ inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
/// Currently, the algorithm for computing hash codes is based on CityHash and
/// keeps 56 bytes of arbitrary state.
struct hash_state {
uint64_t h0, h1, h2, h3, h4, h5, h6;
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.
@@ -367,7 +368,7 @@ template <typename T, typename U> struct is_hashable_data<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>
typename std::enable_if<is_hashable_data<T>::value, T>::type
std::enable_if_t<is_hashable_data<T>::value, T>
get_hashable_data(const T &value) {
return value;
}
@@ -375,7 +376,7 @@ get_hashable_data(const T &value) {
/// This variant is enabled when we must first call hash_value and use the
/// result as our data.
template <typename T>
typename std::enable_if<!is_hashable_data<T>::value, size_t>::type
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);
@@ -449,7 +450,7 @@ hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
/// are stored in contiguous memory, this routine avoids copying each value
/// and directly reads from the underlying memory.
template <typename ValueT>
typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type
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);
@@ -499,7 +500,7 @@ namespace detail {
/// 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];
char buffer[64] = {};
hash_state state;
const uint64_t seed;
@@ -547,7 +548,7 @@ public:
// store types smaller than the buffer.
if (!store_and_advance(buffer_ptr, buffer_end, data,
partial_store_size))
abort();
wpi_unreachable("buffer smaller than stored type");
}
return buffer_ptr;
}
@@ -574,7 +575,7 @@ public:
// 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 static_cast<size_t>(hash_short(buffer, buffer_ptr - buffer, seed));
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
@@ -586,7 +587,7 @@ public:
state.mix(buffer);
length += buffer_ptr - buffer;
return static_cast<size_t>(state.finalize(length));
return state.finalize(length);
}
};
@@ -625,7 +626,7 @@ inline hash_code hash_integer_value(uint64_t value) {
const uint64_t seed = get_execution_seed();
const char *s = reinterpret_cast<const char *>(&value);
const uint64_t a = fetch32(s);
return static_cast<size_t>(hash_16_bytes(seed + (a << 3), fetch32(s + 4)));
return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
}
} // namespace detail
@@ -634,8 +635,7 @@ inline hash_code hash_integer_value(uint64_t value) {
// Declared and documented above, but defined here so that any of the hashing
// infrastructure is available.
template <typename T>
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
hash_value(T value) {
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));
}
@@ -654,6 +654,26 @@ 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>
@@ -661,11 +681,6 @@ hash_code hash_value(const std::basic_string<T> &arg) {
return hash_combine_range(arg.begin(), arg.end());
}
template <typename T>
hash_code hash_value(const std::basic_string_view<T> &arg) {
return hash_combine_range(arg.begin(), arg.end());
}
} // namespace wpi
#ifdef _WIN32

View File

@@ -1,9 +1,8 @@
//===-- llvm/Support/ManagedStatic.h - Static Global wrapper ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -33,19 +32,41 @@ 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 void (*DeleterFn)(void *);
mutable const ManagedStaticBase *Next;
#endif
void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
void RegisterManagedStatic(void *created, 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; }
@@ -61,12 +82,6 @@ template <class C, class Creator = object_creator<C>,
class Deleter = object_deleter<C>>
class ManagedStatic : public ManagedStaticBase {
public:
ManagedStatic() = default;
ManagedStatic(C* created, void(*deleter)(void*)) {
RegisterManagedStatic(created, deleter);
}
// Accessors.
C &operator*() {
void *Tmp = Ptr.load(std::memory_order_acquire);
@@ -87,6 +102,12 @@ public:
}
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.

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -237,4 +236,4 @@ struct SmallMapVector
} // end namespace wpi
#endif // LLVM_ADT_MAPVECTOR_H
#endif // WPIUTIL_WPI_MAPVECTOR_H

View File

@@ -1,9 +1,8 @@
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,15 +14,18 @@
#define WPIUTIL_WPI_MATHEXTRAS_H
#include "wpi/Compiler.h"
#include <cstdint>
#include <algorithm>
#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.
@@ -37,6 +39,7 @@ 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.
@@ -49,14 +52,14 @@ enum ZeroBehavior {
namespace detail {
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) {
static unsigned count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
if (Val & 0x1)
return 0;
// Bisection method.
std::size_t ZeroBits = 0;
unsigned ZeroBits = 0;
T Shift = std::numeric_limits<T>::digits >> 1;
T Mask = (std::numeric_limits<T>::max)() >> Shift;
while (Shift) {
@@ -71,13 +74,13 @@ template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
}
};
#if __GNUC__ >= 4 || defined(_MSC_VER)
#if defined(__GNUC__) || defined(_MSC_VER)
template <typename T> struct TrailingZerosCounter<T, 4> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
#if __has_builtin(__builtin_ctz) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
return __builtin_ctz(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -89,11 +92,11 @@ template <typename T> struct TrailingZerosCounter<T, 4> {
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct TrailingZerosCounter<T, 8> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
#if __has_builtin(__builtin_ctzll) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
return __builtin_ctzll(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -114,7 +117,7 @@ template <typename T> struct TrailingZerosCounter<T, 8> {
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
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.");
@@ -123,12 +126,12 @@ std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
namespace detail {
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) {
static unsigned count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
// Bisection method.
std::size_t ZeroBits = 0;
unsigned ZeroBits = 0;
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
T Tmp = Val >> Shift;
if (Tmp)
@@ -140,13 +143,13 @@ template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
}
};
#if __GNUC__ >= 4 || defined(_MSC_VER)
#if defined(__GNUC__) || defined(_MSC_VER)
template <typename T> struct LeadingZerosCounter<T, 4> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
#if __has_builtin(__builtin_clz) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_clz) || defined(__GNUC__)
return __builtin_clz(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -158,11 +161,11 @@ template <typename T> struct LeadingZerosCounter<T, 4> {
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct LeadingZerosCounter<T, 8> {
static std::size_t count(T Val, ZeroBehavior ZB) {
static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
#if __has_builtin(__builtin_clzll) || LLVM_GNUC_PREREQ(4, 0, 0)
#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
return __builtin_clzll(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -183,7 +186,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
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.");
@@ -273,6 +276,34 @@ T reverseBits(T 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.
@@ -325,14 +356,12 @@ constexpr inline bool isShiftedInt(int64_t x) {
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
/// left too many places.
template <unsigned N>
constexpr inline typename std::enable_if<(N < 64), bool>::type
isUInt(uint64_t X) {
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 typename std::enable_if<N >= 64, bool>::type
isUInt(uint64_t X) {
constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t) {
return true;
}
@@ -379,7 +408,7 @@ inline uint64_t maxUIntN(uint64_t N) {
inline int64_t minIntN(int64_t N) {
assert(N > 0 && N <= 64 && "integer width out of range");
return -(UINT64_C(1)<<(N-1));
return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
}
#ifdef _WIN32
@@ -450,7 +479,7 @@ constexpr inline bool isPowerOf2_64(uint64_t Value) {
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
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.");
@@ -466,7 +495,7 @@ std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
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.");
@@ -478,7 +507,7 @@ 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 __GNUC__ >= 4
#if defined(__GNUC__)
return __builtin_popcount(Value);
#else
uint32_t v = Value;
@@ -491,7 +520,7 @@ template <typename T, std::size_t SizeOfT> struct PopulationCounter {
template <typename T> struct PopulationCounter<T, 8> {
static unsigned count(T Value) {
#if __GNUC__ >= 4
#if defined(__GNUC__)
return __builtin_popcountll(Value);
#else
uint64_t v = Value;
@@ -515,6 +544,16 @@ inline unsigned countPopulation(T Value) {
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
@@ -551,15 +590,20 @@ inline unsigned Log2_64_Ceil(uint64_t Value) {
}
/// Return the greatest common divisor of the values using Euclid's algorithm.
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
template <typename T>
inline T greatestCommonDivisor(T A, T B) {
while (B) {
uint64_t T = B;
T Tmp = B;
B = A % B;
A = T;
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;
@@ -607,25 +651,6 @@ constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
return (A | B) & (1 + ~(A | B));
}
/// Aligns \c Addr to \c Alignment bytes, rounding up.
///
/// Alignment should be a power of two. This method rounds up, so
/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
assert(Alignment && isPowerOf2_64((uint64_t)Alignment) &&
"Alignment is not a power of two!");
assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr);
return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
}
/// Returns the necessary adjustment for aligning \c Ptr to \c Alignment
/// bytes, rounding up.
inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) {
return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
}
/// 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) {
@@ -691,18 +716,10 @@ inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
return alignTo(Numerator, Denominator) / Denominator;
}
/// \c alignTo for contexts where a constant expression is required.
/// \sa alignTo
///
/// \todo FIXME: remove when \c constexpr becomes really \c constexpr
template <uint64_t Align>
struct AlignTo {
static_assert(Align != 0u, "Align must be non-zero");
template <uint64_t Value>
struct from_value {
static const uint64_t value = (Value + Align - 1) / Align * Align;
};
};
/// Returns the 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
@@ -712,13 +729,6 @@ inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
return (Value - Skew) / Align * Align + Skew;
}
/// Returns the offset to 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.
inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
return alignTo(Value, Align) - Value;
}
/// 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) {
@@ -728,7 +738,7 @@ template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
}
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires 0 < B < 32.
/// 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.");
@@ -736,7 +746,7 @@ inline int32_t SignExtend32(uint32_t X, unsigned B) {
}
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires 0 < B < 64.
/// 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.");
@@ -744,7 +754,7 @@ template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
}
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires 0 < B < 64.
/// 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.");
@@ -754,16 +764,15 @@ inline int64_t SignExtend64(uint64_t X, unsigned B) {
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
/// value of the result.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
AbsoluteDifference(T X, T Y) {
return (std::max)(X, Y) - (std::min)(X, Y);
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>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
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;
@@ -780,7 +789,7 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
/// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
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;
@@ -826,7 +835,7 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
/// overflow. ResultOverflowed indicates if the result is larger than the
/// maximum representable value of type T.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
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;
@@ -838,6 +847,89 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
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>
@@ -858,7 +950,6 @@ template <typename T>
constexpr T Lerp(const T& startValue, const T& endValue, double t) {
return startValue + (endValue - startValue) * t;
}
} // namespace wpi
} // End wpi namespace
#endif

View File

@@ -1,9 +1,8 @@
//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
@@ -33,29 +32,69 @@ namespace wpi {
LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
void *Result = std::malloc(Sz);
if (Result == nullptr)
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)
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)
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

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -14,7 +13,9 @@
#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>
@@ -59,19 +60,19 @@ public:
IntType getInt() const { return (IntType)Info::getInt(Value); }
void setPointer(PointerTy PtrVal) {
void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
Value = Info::updatePointer(Value, PtrVal);
}
void setInt(IntType IntVal) {
void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
}
void initWithPointer(PointerTy PtrVal) {
void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
Value = Info::updatePointer(0, PtrVal);
}
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
static_cast<intptr_t>(IntVal));
}
@@ -89,7 +90,7 @@ public:
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
void setFromOpaqueValue(void *Val) {
void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
Value = reinterpret_cast<intptr_t>(Val);
}
@@ -126,6 +127,7 @@ public:
}
};
template <typename PointerT, unsigned IntBits, typename PtrTraits>
struct PointerIntPairInfo {
static_assert(PtrTraits::NumLowBitsAvailable <
@@ -133,7 +135,7 @@ struct PointerIntPairInfo {
"cannot use a pointer type that has all bits free");
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
"PointerIntPair with integer size too large for pointer");
enum : uintptr_t {
enum MaskAndShiftConstants : uintptr_t {
/// PointerBitMask - The bits that come from the pointer.
PointerBitMask =
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1),
@@ -176,12 +178,6 @@ struct PointerIntPairInfo {
}
};
template <typename T> struct isPodLike;
template <typename PointerTy, unsigned IntBits, typename IntType>
struct isPodLike<PointerIntPair<PointerTy, IntBits, IntType>> {
static const bool value = true;
};
// Provide specialization of DenseMapInfo for PointerIntPair.
template <typename PointerTy, unsigned IntBits, typename IntType>
struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>> {
@@ -227,7 +223,8 @@ struct PointerLikeTypeTraits<
return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
}
enum { NumLowBitsAvailable = PtrTraits::NumLowBitsAvailable - IntBits };
static constexpr int NumLowBitsAvailable =
PtrTraits::NumLowBitsAvailable - IntBits;
};
} // end namespace wpi

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,8 +14,8 @@
#ifndef WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
#define WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <type_traits>
namespace wpi {
@@ -38,8 +37,9 @@ template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
};
// sizeof(T) is valid only for a complete T.
template <typename T> struct HasPointerLikeTypeTraits<
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
template <typename T>
struct HasPointerLikeTypeTraits<
T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
static const bool value = true;
};
@@ -57,7 +57,8 @@ template <typename T> struct PointerLikeTypeTraits<T *> {
static inline void *getAsVoidPointer(T *P) { return P; }
static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value };
static constexpr int NumLowBitsAvailable =
detail::ConstantLog2<alignof(T)>::value;
};
template <> struct PointerLikeTypeTraits<void *> {
@@ -71,7 +72,7 @@ template <> struct PointerLikeTypeTraits<void *> {
///
/// All clients should use assertions to do a run-time check to ensure that
/// this is actually true.
enum { NumLowBitsAvailable = 2 };
static constexpr int NumLowBitsAvailable = 2;
};
// Provide PointerLikeTypeTraits for const things.
@@ -84,7 +85,7 @@ template <typename T> struct PointerLikeTypeTraits<const T> {
static inline const T getFromVoidPointer(const void *P) {
return NonConst::getFromVoidPointer(const_cast<void *>(P));
}
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
};
// Provide PointerLikeTypeTraits for const pointers.
@@ -97,7 +98,7 @@ template <typename T> struct PointerLikeTypeTraits<const T *> {
static inline const T *getFromVoidPointer(const void *P) {
return NonConst::getFromVoidPointer(const_cast<void *>(P));
}
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
};
// Provide PointerLikeTypeTraits for uintptr_t.
@@ -109,7 +110,7 @@ template <> struct PointerLikeTypeTraits<uintptr_t> {
return reinterpret_cast<uintptr_t>(P);
}
// No bits are available!
enum { NumLowBitsAvailable = 0 };
static constexpr int NumLowBitsAvailable = 0;
};
/// Provide suitable custom traits struct for function pointers.
@@ -122,7 +123,8 @@ template <> struct PointerLikeTypeTraits<uintptr_t> {
/// potentially use alignment attributes on functions to satisfy that.
template <int Alignment, typename FunctionPointerT>
struct FunctionPointerLikeTypeTraits {
enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value };
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 &&

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -54,22 +53,84 @@ struct PointerUnionTypeSelectorReturn<
typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
};
/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
/// for the two template arguments.
template <typename PT1, typename PT2> class PointerUnionUIntTraits {
public:
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
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;
}
enum {
PT1BitsAv = (int)(PointerLikeTypeTraits<PT1>::NumLowBitsAvailable),
PT2BitsAv = (int)(PointerLikeTypeTraits<PT2>::NumLowBitsAvailable),
NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
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;
};
};
/// A discriminated union of two pointer types, with the discriminator in the
/// low bit of the pointer.
/// 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.
@@ -84,49 +145,40 @@ public:
/// P = (float*)0;
/// Y = P.get<float*>(); // ok.
/// X = P.get<int*>(); // runtime assertion failure.
template <typename PT1, typename PT2> class PointerUnion {
public:
using ValTy =
PointerIntPair<void *, 1, bool, PointerUnionUIntTraits<PT1, PT2>>;
private:
ValTy Val;
struct IsPT1 {
static const int Num = 0;
};
struct IsPT2 {
static const int Num = 1;
};
template <typename T> struct UNION_DOESNT_CONTAIN_TYPE {};
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(PT1 V)
: Val(const_cast<void *>(
PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {}
PointerUnion(PT2 V)
: Val(const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)),
1) {}
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 {
// Convert from the void* to one of the pointer types, to make sure that
// we recursively strip off low bits if we have a nested PointerUnion.
return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
}
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> int is() const {
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, IsPT1,
::wpi::PointerUnionTypeSelector<PT2, T, IsPT2,
UNION_DOESNT_CONTAIN_TYPE<T>>>::Return;
int TyNo = Ty::Num;
return static_cast<int>(Val.getInt()) == TyNo;
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.
@@ -134,11 +186,11 @@ public:
/// If the specified pointer type is incorrect, assert.
template <typename T> T get() const {
assert(is<T>() && "Invalid accessor called");
return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
/// otherwise returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
@@ -147,342 +199,91 @@ public:
/// If the union is set to the first pointer type get an address pointing to
/// it.
PT1 const *getAddrOfPtr1() const {
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.
PT1 *getAddrOfPtr1() {
assert(is<PT1>() && "Val is not the first pointer");
First *getAddrOfPtr1() {
assert(is<First>() && "Val is not the first pointer");
assert(
get<PT1>() == Val.getPointer() &&
PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
this->Val.getPointer() &&
"Can't get the address because PointerLikeTypeTraits changes the ptr");
return const_cast<PT1 *>(
reinterpret_cast<const PT1 *>(Val.getAddrOfPointer()));
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) {
Val.initWithPointer(nullptr);
this->Val.initWithPointer(nullptr);
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion &operator=(const PT1 &RHS) {
Val.initWithPointer(
const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
return *this;
}
const PointerUnion &operator=(const PT2 &RHS) {
Val.setPointerAndInt(
const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)),
1);
return *this;
}
/// Assignment from elements of the union.
using Base::operator=;
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
static inline PointerUnion getFromOpaqueValue(void *VP) {
PointerUnion V;
V.Val = ValTy::getFromOpaqueValue(VP);
V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
return V;
}
};
template <typename PT1, typename PT2>
bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
template <typename ...PTs>
bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
template <typename PT1, typename PT2>
bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
template <typename ...PTs>
bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
}
template <typename PT1, typename PT2>
bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
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 PT1, typename PT2>
struct PointerLikeTypeTraits<PointerUnion<PT1, PT2>> {
static inline void *getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
template <typename ...PTs>
struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion<PT1, PT2> getFromVoidPointer(void *P) {
return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
return PointerUnion<PTs...>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion<PT1, PT2>::ValTy>::NumLowBitsAvailable
};
};
/// A pointer union of three pointer types. See documentation for PointerUnion
/// for usage.
template <typename PT1, typename PT2, typename PT3> class PointerUnion3 {
public:
using InnerUnion = PointerUnion<PT1, PT2>;
using ValTy = PointerUnion<InnerUnion, PT3>;
private:
ValTy Val;
struct IsInnerUnion {
ValTy Val;
IsInnerUnion(ValTy val) : Val(val) {}
template <typename T> int is() const {
return Val.template is<InnerUnion>() &&
Val.template get<InnerUnion>().template is<T>();
}
template <typename T> T get() const {
return Val.template get<InnerUnion>().template get<T>();
}
};
struct IsPT3 {
ValTy Val;
IsPT3(ValTy val) : Val(val) {}
template <typename T> int is() const { return Val.template is<T>(); }
template <typename T> T get() const { return Val.template get<T>(); }
};
public:
PointerUnion3() = default;
PointerUnion3(PT1 V) { Val = InnerUnion(V); }
PointerUnion3(PT2 V) { Val = InnerUnion(V); }
PointerUnion3(PT3 V) { Val = V; }
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const { return Val.isNull(); }
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
// If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, IsInnerUnion,
::wpi::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
return Ty(Val).template is<T>();
}
/// 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");
// If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, IsInnerUnion,
::wpi::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
return Ty(Val).template get<T>();
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
/// Assignment from nullptr which just clears the union.
const PointerUnion3 &operator=(std::nullptr_t) {
Val = nullptr;
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion3 &operator=(const PT1 &RHS) {
Val = InnerUnion(RHS);
return *this;
}
const PointerUnion3 &operator=(const PT2 &RHS) {
Val = InnerUnion(RHS);
return *this;
}
const PointerUnion3 &operator=(const PT3 &RHS) {
Val = RHS;
return *this;
}
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
static inline PointerUnion3 getFromOpaqueValue(void *VP) {
PointerUnion3 V;
V.Val = ValTy::getFromOpaqueValue(VP);
return V;
}
};
// Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
template <typename PT1, typename PT2, typename PT3>
struct PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3>> {
static inline void *getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion3<PT1, PT2, PT3> getFromVoidPointer(void *P) {
return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion3<PT1, PT2, PT3>::ValTy>::NumLowBitsAvailable
};
};
template <typename PT1, typename PT2, typename PT3>
bool operator<(PointerUnion3<PT1, PT2, PT3> lhs,
PointerUnion3<PT1, PT2, PT3> rhs) {
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
}
/// A pointer union of four pointer types. See documentation for PointerUnion
/// for usage.
template <typename PT1, typename PT2, typename PT3, typename PT4>
class PointerUnion4 {
public:
using InnerUnion1 = PointerUnion<PT1, PT2>;
using InnerUnion2 = PointerUnion<PT3, PT4>;
using ValTy = PointerUnion<InnerUnion1, InnerUnion2>;
private:
ValTy Val;
public:
PointerUnion4() = default;
PointerUnion4(PT1 V) { Val = InnerUnion1(V); }
PointerUnion4(PT2 V) { Val = InnerUnion1(V); }
PointerUnion4(PT3 V) { Val = InnerUnion2(V); }
PointerUnion4(PT4 V) { Val = InnerUnion2(V); }
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const { return Val.isNull(); }
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
// If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, InnerUnion1,
::wpi::PointerUnionTypeSelector<PT2, T, InnerUnion1,
InnerUnion2>>::Return;
return Val.template is<Ty>() && Val.template get<Ty>().template is<T>();
}
/// 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");
// If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
using Ty = typename ::wpi::PointerUnionTypeSelector<
PT1, T, InnerUnion1,
::wpi::PointerUnionTypeSelector<PT2, T, InnerUnion1,
InnerUnion2>>::Return;
return Val.template get<Ty>().template get<T>();
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
/// Assignment from nullptr which just clears the union.
const PointerUnion4 &operator=(std::nullptr_t) {
Val = nullptr;
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion4 &operator=(const PT1 &RHS) {
Val = InnerUnion1(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT2 &RHS) {
Val = InnerUnion1(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT3 &RHS) {
Val = InnerUnion2(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT4 &RHS) {
Val = InnerUnion2(RHS);
return *this;
}
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
static inline PointerUnion4 getFromOpaqueValue(void *VP) {
PointerUnion4 V;
V.Val = ValTy::getFromOpaqueValue(VP);
return V;
}
};
// Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
template <typename PT1, typename PT2, typename PT3, typename PT4>
struct PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4>> {
static inline void *
getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion4<PT1, PT2, PT3, PT4> getFromVoidPointer(void *P) {
return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>::NumLowBitsAvailable
};
// 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 T, typename U> struct DenseMapInfo<PointerUnion<T, U>> {
using Pair = PointerUnion<T, U>;
using FirstInfo = DenseMapInfo<T>;
using SecondInfo = DenseMapInfo<U>;
template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
using Union = PointerUnion<PTs...>;
using FirstInfo =
DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
static inline Pair getEmptyKey() { return Pair(FirstInfo::getEmptyKey()); }
static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
static inline Pair getTombstoneKey() {
return Pair(FirstInfo::getTombstoneKey());
static inline Union getTombstoneKey() {
return Union(FirstInfo::getTombstoneKey());
}
static unsigned getHashValue(const Pair &PairVal) {
intptr_t key = (intptr_t)PairVal.getOpaqueValue();
static unsigned getHashValue(const Union &UnionVal) {
intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
return DenseMapInfo<intptr_t>::getHashValue(key);
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
return LHS.template is<T>() == RHS.template is<T>() &&
(LHS.template is<T>() ? FirstInfo::isEqual(LHS.template get<T>(),
RHS.template get<T>())
: SecondInfo::isEqual(LHS.template get<U>(),
RHS.template get<U>()));
static bool isEqual(const Union &LHS, const Union &RHS) {
return LHS == RHS;
}
};

View 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

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -20,7 +19,6 @@
#include "wpi/type_traits.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
@@ -270,7 +268,7 @@ public:
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
: SmallPtrSetIteratorImpl(BP, E) {}
// Most methods provided by baseclass.
// Most methods are provided by the base class.
const PtrTy operator*() const {
assert(Bucket < End);
@@ -327,14 +325,8 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
protected:
// Constructors that forward to the base.
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
: SmallPtrSetImplBase(SmallStorage, that) {}
SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
SmallPtrSetImpl &&that)
: SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
// Forward constructors to the base.
using SmallPtrSetImplBase::SmallPtrSetImplBase;
public:
using iterator = SmallPtrSetIterator<PtrType>;
@@ -353,17 +345,28 @@ public:
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(Ptr) != end() ? 1 : 0; }
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) {
@@ -387,6 +390,32 @@ private:
}
};
/// 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
@@ -460,4 +489,4 @@ namespace std {
} // end namespace std
#endif // LLVM_ADT_SMALLPTRSET_H
#endif // WPIUTIL_WPI_SMALLPTRSET_H

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -16,8 +15,8 @@
#include "wpi/SmallPtrSet.h"
#include "wpi/SmallVector.h"
#include "wpi/Compiler.h"
#include "wpi/iterator.h"
#include "wpi/Compiler.h"
#include "wpi/type_traits.h"
#include <cstddef>
#include <functional>
@@ -233,6 +232,13 @@ public:
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(); }
@@ -249,6 +255,31 @@ private:
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 // LLVM_ADT_SMALLSET_H
#endif // WPIUTIL_WPI_SMALLSET_H

View File

@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -29,66 +28,58 @@ public:
SmallString() = default;
/// Initialize from a std::string_view.
SmallString(std::string_view S)
: SmallVector<char, InternalLen>(S.begin(), S.end()) {}
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) {}
// Note that in order to add new overloads for append & assign, we have to
// duplicate the inherited versions so as not to inadvertently hide them.
/// @}
/// @name String Assignment
/// @{
/// Assign from a repeated element.
void assign(size_t NumElts, char Elt) {
this->SmallVectorImpl<char>::assign(NumElts, Elt);
}
/// Assign from an iterator pair.
template<typename in_iter>
void assign(in_iter S, in_iter E) {
this->clear();
SmallVectorImpl<char>::append(S, E);
}
using SmallVector<char, InternalLen>::assign;
/// Assign from a std::string_view.
void assign(std::string_view RHS) {
this->clear();
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
SmallVectorImpl<char>::assign(RHS.begin(), RHS.end());
}
/// Assign from a SmallVector.
void assign(const SmallVectorImpl<char> &RHS) {
/// Assign from a list of std::string_views.
void assign(std::initializer_list<std::string_view> Refs) {
this->clear();
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
append(Refs);
}
/// @}
/// @name String Concatenation
/// @{
/// Append from an iterator pair.
template<typename in_iter>
void append(in_iter S, in_iter E) {
SmallVectorImpl<char>::append(S, E);
}
void append(size_t NumInputs, char Elt) {
SmallVectorImpl<char>::append(NumInputs, Elt);
}
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 SmallVector.
void append(const SmallVectorImpl<char> &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);
}
/// @}
@@ -185,10 +176,7 @@ public:
// Extra methods.
/// Explicit conversion to std::string_view.
std::string_view str() const { return {this->begin(), this->size()}; }
/// Explicit conversion to std::string.
std::string string() const { return {this->begin(), this->size()}; }
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() {
@@ -200,13 +188,16 @@ public:
/// 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.
const SmallString &operator=(std::string_view RHS) {
this->clear();
return *this += RHS;
SmallString &operator=(std::string_view RHS) {
this->assign(RHS);
return *this;
}
SmallString &operator+=(std::string_view RHS) {
@@ -221,4 +212,4 @@ public:
} // end namespace wpi
#endif // LLVM_ADT_SMALLSTRING_H
#endif // WPIUTIL_WPI_SMALLSTRING_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -14,38 +13,20 @@
#ifndef WPIUTIL_WPI_STRINGMAP_H
#define WPIUTIL_WPI_STRINGMAP_H
#include "wpi/StringMapEntry.h"
#include "wpi/MemAlloc.h"
#include "wpi/SmallVector.h"
#include "wpi/iterator.h"
#include "wpi/iterator_range.h"
#include "wpi/MemAlloc.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <string_view>
#include <utility>
namespace wpi {
template<typename ValueTy> class StringMapConstIterator;
template<typename ValueTy> class StringMapIterator;
template<typename ValueTy> class StringMapKeyIterator;
template<typename ValueTy> class StringMapEntry;
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
class StringMapEntryBase {
size_t StrLen;
public:
explicit StringMapEntryBase(size_t Len) : StrLen(Len) {}
size_t getKeyLength() const { return StrLen; }
};
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.
@@ -61,8 +42,7 @@ protected:
unsigned ItemSize;
protected:
explicit StringMapImpl(unsigned itemSize)
: ItemSize(itemSize) {}
explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
StringMapImpl(StringMapImpl &&RHS) noexcept
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
@@ -101,10 +81,12 @@ protected:
void init(unsigned Size);
public:
static constexpr uintptr_t TombstoneIntVal =
static_cast<uintptr_t>(-1)
<< PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
static StringMapEntryBase *getTombstoneVal() {
uintptr_t Val = static_cast<uintptr_t>(-1);
Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
return reinterpret_cast<StringMapEntryBase *>(Val);
return reinterpret_cast<StringMapEntryBase *>(TombstoneIntVal);
}
unsigned getNumBuckets() const { return NumBuckets; }
@@ -121,82 +103,6 @@ public:
}
};
/// 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 : public StringMapEntryBase {
public:
ValueTy second;
explicit StringMapEntry(size_t strLen)
: StringMapEntryBase(strLen), second() {}
template <typename... InitTy>
StringMapEntry(size_t strLen, InitTy &&... InitVals)
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
StringMapEntry(StringMapEntry &E) = delete;
std::string_view getKey() const {
return {getKeyData(), getKeyLength()};
}
const ValueTy &getValue() const { return second; }
ValueTy &getValue() { return second; }
void setValue(const ValueTy &V) { second = V; }
/// 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 {getKeyData(), getKeyLength()}; }
/// Create a StringMapEntry for the specified key construct the value using
/// \p InitiVals.
template <typename... InitTy>
static StringMapEntry *Create(std::string_view Key, InitTy &&... InitVals) {
size_t KeyLength = Key.size();
// Allocate a new item with space for the string at the end and a null
// terminator.
size_t AllocSize = sizeof(StringMapEntry) + KeyLength + 1;
StringMapEntry *NewItem =
static_cast<StringMapEntry*>(safe_malloc(AllocSize));
// Construct the value.
new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
// Copy the string information.
char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
if (KeyLength > 0)
memcpy(StrBuffer, Key.data(), KeyLength);
StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients.
return NewItem;
}
static StringMapEntry *Create(std::string_view Key) {
return Create(Key, ValueTy());
}
/// 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.
void Destroy() {
// Free memory referenced by the item.
this->~StringMapEntry();
std::free(static_cast<void *>(this));
}
};
/// 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,
@@ -209,7 +115,7 @@ public:
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
explicit StringMap(unsigned InitialSize)
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
@@ -268,14 +174,14 @@ public:
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
static_cast<MapEntryTy*>(Bucket)->Destroy();
static_cast<MapEntryTy *>(Bucket)->Destroy();
}
}
}
free(TheTable);
}
using key_type = const char*;
using key_type = const char *;
using mapped_type = ValueTy;
using value_type = StringMapEntry<ValueTy>;
using size_type = size_t;
@@ -283,17 +189,13 @@ public:
using const_iterator = StringMapConstIterator<ValueTy>;
using iterator = StringMapIterator<ValueTy>;
iterator begin() {
return iterator(TheTable, NumBuckets == 0);
}
iterator end() {
return iterator(TheTable+NumBuckets, true);
}
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);
return const_iterator(TheTable + NumBuckets, true);
}
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
@@ -303,14 +205,16 @@ public:
iterator find(std::string_view Key) {
int Bucket = FindKey(Key);
if (Bucket == -1) return end();
return iterator(TheTable+Bucket, true);
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);
if (Bucket == -1)
return end();
return const_iterator(TheTable + Bucket, true);
}
/// lookup - Return the entry for the specified key, or a default
@@ -327,10 +231,33 @@ public:
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;
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.
@@ -338,7 +265,7 @@ public:
unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
StringMapEntryBase *&Bucket = TheTable[BucketNo];
if (Bucket && Bucket != getTombstoneVal())
return false; // Already exists in map.
return false; // Already exists in map.
if (Bucket == getTombstoneVal())
--NumTombstones;
@@ -358,6 +285,16 @@ public:
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
@@ -382,14 +319,15 @@ public:
// clear - Empties out the StringMap
void clear() {
if (empty()) return;
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();
static_cast<MapEntryTy *>(Bucket)->Destroy();
}
Bucket = nullptr;
}
@@ -400,9 +338,7 @@ public:
/// 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 remove(MapEntryTy *KeyValue) { RemoveKey(KeyValue); }
void erase(iterator I) {
MapEntryTy &V = *I;
@@ -412,7 +348,8 @@ public:
bool erase(std::string_view Key) {
iterator I = find(Key);
if (I == end()) return false;
if (I == end())
return false;
erase(I);
return true;
}
@@ -431,7 +368,8 @@ public:
explicit StringMapIterBase(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: Ptr(Bucket) {
if (!NoAdvance) AdvancePastEmptyBuckets();
if (!NoAdvance)
AdvancePastEmptyBuckets();
}
DerivedTy &operator=(const DerivedTy &Other) {
@@ -439,13 +377,9 @@ public:
return static_cast<DerivedTy &>(*this);
}
#if __cplusplus < 202002L
bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
#else
friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
return LHS.Ptr == RHS.Ptr;
}
#endif
DerivedTy &operator++() { // Preincrement
++Ptr;
@@ -490,15 +424,13 @@ class StringMapConstIterator
const StringMapEntry<ValueTy>>;
public:
using value_type = const StringMapEntry<ValueTy>;
StringMapConstIterator() = default;
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: base(Bucket, NoAdvance) {}
value_type &operator*() const {
return *static_cast<value_type *>(*this->Ptr);
const StringMapEntry<ValueTy> &operator*() const {
return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
}
};
@@ -509,15 +441,13 @@ class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
public:
using value_type = StringMapEntry<ValueTy>;
StringMapIterator() = default;
explicit StringMapIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: base(Bucket, NoAdvance) {}
value_type &operator*() const {
return *static_cast<value_type *>(*this->Ptr);
StringMapEntry<ValueTy> &operator*() const {
return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
}
operator StringMapConstIterator<ValueTy>() const {
@@ -635,4 +565,4 @@ inline bool operator>=(const StringMap<ValueTy>& lhs,
} // end namespace wpi
#endif // LLVM_ADT_STRINGMAP_H
#endif // WPIUTIL_WPI_STRINGMAP_H

View File

@@ -0,0 +1,143 @@
//===- 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.
static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
std::string_view Key) {
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 = safe_malloc(AllocSize);
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... InitTy>
static StringMapEntry *Create(std::string_view key,
InitTy &&... initVals) {
return new (StringMapEntryBase::allocateWithKey(
sizeof(StringMapEntry), alignof(StringMapEntry), key))
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.
void Destroy() {
// Free memory referenced by the item.
this->~StringMapEntry();
std::free(static_cast<void *>(this));
}
};
} // end namespace wpi
#endif // WPIUTIL_WPI_STRINGMAPENTRY_H

View File

@@ -1,9 +1,8 @@
//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,19 +14,43 @@
#ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
#define WPIUTIL_WPI_SWAPBYTEORDER_H
#include "wpi/Compiler.h"
#include <cstddef>
#include <stdint.h>
#include <cstdint>
#include <type_traits>
#if defined(_MSC_VER) && !defined(_DEBUG)
#include <stdlib.h>
#endif
namespace wpi {
namespace sys {
#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
/// SwapByteOrder_16 - This function returns a byte-swapped representation of
namespace wpi {
/// ByteSwap_16 - This function returns a byte-swapped representation of
/// the 16-bit argument.
inline uint16_t SwapByteOrder_16(uint16_t value) {
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.
@@ -39,10 +62,9 @@ inline uint16_t SwapByteOrder_16(uint16_t value) {
#endif
}
/// SwapByteOrder_32 - This function returns a byte-swapped representation of
/// the 32-bit argument.
inline uint32_t SwapByteOrder_32(uint32_t value) {
#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !defined(__ICC))
/// 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);
@@ -55,45 +77,55 @@ inline uint32_t SwapByteOrder_32(uint32_t value) {
#endif
}
/// SwapByteOrder_64 - This function returns a byte-swapped representation of
/// the 64-bit argument.
inline uint64_t SwapByteOrder_64(uint64_t value) {
#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !defined(__ICC))
/// 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 = SwapByteOrder_32(uint32_t(value));
uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32));
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 SwapByteOrder_16(C); }
inline signed short getSwappedBytes( signed short C) { return SwapByteOrder_16(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 SwapByteOrder_32(C); }
inline signed int getSwappedBytes( signed int C) { return SwapByteOrder_32(C); }
inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); }
inline signed int getSwappedBytes( signed int C) { return ByteSwap_32(C); }
#if __LONG_MAX__ == __INT_MAX__
inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_32(C); }
inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_32(C); }
#elif __LONG_MAX__ == __LONG_LONG_MAX__
inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_64(C); }
inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_64(C); }
#else
#error "Unknown long size!"
#endif
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 SwapByteOrder_64(C);
return ByteSwap_64(C);
}
inline signed long long getSwappedBytes(signed long long C) {
return SwapByteOrder_64(C);
return ByteSwap_64(C);
}
inline float getSwappedBytes(float C) {
@@ -102,7 +134,7 @@ inline float getSwappedBytes(float C) {
float f;
} in, out;
in.f = C;
out.i = SwapByteOrder_32(in.i);
out.i = ByteSwap_32(in.i);
return out.f;
}
@@ -112,10 +144,16 @@ inline double getSwappedBytes(double C) {
double d;
} in, out;
in.d = C;
out.i = SwapByteOrder_64(in.i);
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);

View File

@@ -1,9 +1,8 @@
//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
///
@@ -15,10 +14,14 @@
#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 {
@@ -85,6 +88,27 @@ public:
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) {

View File

@@ -1,9 +1,8 @@
//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//

View File

@@ -1,9 +1,8 @@
//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
@@ -11,7 +10,6 @@
#define WPIUTIL_WPI_ITERATOR_H
#include "wpi/iterator_range.h"
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
@@ -65,9 +63,14 @@ namespace wpi {
template <typename DerivedT, typename IteratorCategoryT, typename T,
typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
typename ReferenceT = T &>
class iterator_facade_base
: public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT,
ReferenceT> {
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,
@@ -143,28 +146,30 @@ public:
return tmp;
}
#ifndef __cpp_impl_three_way_comparison
bool operator!=(const DerivedT &RHS) const {
return !static_cast<const DerivedT *>(this)->operator==(RHS);
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)->operator<(RHS) &&
!static_cast<const DerivedT *>(this)->operator==(RHS);
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)->operator>(RHS);
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)->operator<(RHS);
return !(static_cast<const DerivedT &>(*this) < RHS);
}
PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
@@ -195,14 +200,14 @@ template <
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
typename DifferenceTypeT =
typename std::iterator_traits<WrappedIteratorT>::difference_type,
typename PointerT = typename std::conditional<
typename PointerT = std::conditional_t<
std::is_same<T, typename std::iterator_traits<
WrappedIteratorT>::value_type>::value,
typename std::iterator_traits<WrappedIteratorT>::pointer, T *>::type,
typename ReferenceT = typename std::conditional<
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 &>::type>
typename std::iterator_traits<WrappedIteratorT>::reference, T &>>
class iterator_adaptor_base
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
DifferenceTypeT, PointerT, ReferenceT> {
@@ -261,12 +266,16 @@ public:
return *static_cast<DerivedT *>(this);
}
bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
bool operator<(const DerivedT &RHS) const {
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 I < RHS.I;
return LHS.I < RHS.I;
}
ReferenceT operator*() const { return *I; }
@@ -282,8 +291,8 @@ public:
/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
/// \endcode
template <typename WrappedIteratorT,
typename T = typename std::remove_reference<
decltype(**std::declval<WrappedIteratorT>())>::type>
typename T = std::remove_reference_t<decltype(
**std::declval<WrappedIteratorT>())>>
struct pointee_iterator
: iterator_adaptor_base<
pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT,
@@ -334,6 +343,13 @@ make_pointer_range(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 // LLVM_ADT_ITERATOR_H
#endif // WPIUTIL_WPI_ITERATOR_H

View File

@@ -1,9 +1,8 @@
//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
@@ -19,7 +18,6 @@
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
#define WPIUTIL_WPI_ITERATOR_RANGE_H
#include <iterator>
#include <utility>
namespace wpi {
@@ -45,6 +43,7 @@ public:
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.
@@ -59,11 +58,6 @@ 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));
}
template <typename T>
iterator_range<decltype(adl_begin(std::declval<T>()))> drop_begin(T &&t,
int n) {
return make_range(std::next(adl_begin(t), n), adl_end(t));
}
}
#endif

View File

@@ -1,9 +1,8 @@
//===- raw_os_ostream.h - std::ostream adaptor for raw_ostream --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//

View File

@@ -1,9 +1,8 @@
//===--- raw_ostream.h - Raw output stream ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -17,18 +16,24 @@
#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>
#include <vector>
#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 {
@@ -38,7 +43,16 @@ namespace wpi {
/// 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
@@ -59,7 +73,11 @@ private:
/// this buffer.
char *OutBufStart, *OutBufEnd, *OutBufCur;
enum BufferKind {
/// 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
@@ -67,7 +85,7 @@ private:
public:
// color order matches ANSI escape sequence, don't change
enum Colors {
enum class Colors {
BLACK = 0,
RED,
GREEN,
@@ -76,11 +94,25 @@ public:
MAGENTA,
CYAN,
WHITE,
SAVEDCOLOR
SAVEDCOLOR,
RESET,
};
explicit raw_ostream(bool unbuffered = false)
: BufferMode(unbuffered ? Unbuffered : InternalBuffer) {
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;
}
@@ -93,10 +125,19 @@ public:
/// 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();
@@ -104,13 +145,13 @@ public:
/// Set the stream to be buffered, using the specified buffer size.
void SetBufferSize(size_t Size) {
flush();
SetBufferAndMode(new char[Size], Size, InternalBuffer);
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 != Unbuffered && OutBufStart == nullptr)
if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr)
return preferred_buffer_size();
// Otherwise just return the size of the allocated buffer.
@@ -122,7 +163,7 @@ public:
/// when the stream is being set to unbuffered.
void SetUnbuffered() {
flush();
SetBufferAndMode(nullptr, 0, Unbuffered);
SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered);
}
size_t GetNumBytesInBuffer() const {
@@ -237,9 +278,8 @@ public:
/// @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) {
virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false,
bool BG = false) {
(void)Color;
(void)Bold;
(void)BG;
@@ -259,8 +299,17 @@ public:
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
//===--------------------------------------------------------------------===//
@@ -281,9 +330,6 @@ private:
/// \invariant { Size > 0 }
virtual void write_impl(const char *Ptr, size_t Size) = 0;
// An out of line virtual method to provide a home for the class vtable.
virtual void handle();
/// Return the current position within the stream, not counting the bytes
/// currently in the buffer.
virtual uint64_t current_pos() const = 0;
@@ -293,7 +339,7 @@ protected:
/// 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, ExternalBuffer);
SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
}
/// Return an efficient buffer size for the underlying output mechanism.
@@ -318,9 +364,23 @@ private:
/// 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.
@@ -329,10 +389,11 @@ class raw_pwrite_stream : public raw_ostream {
void anchor() override;
public:
explicit raw_pwrite_stream(bool Unbuffered = false)
: raw_ostream(Unbuffered) {}
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 NDBEBUG
#ifndef NDEBUG
uint64_t Pos = tell();
// /dev/null always reports a pos of 0, so we cannot perform this check
// in that case.
@@ -352,8 +413,7 @@ public:
class raw_fd_ostream : public raw_pwrite_stream {
int FD;
bool ShouldClose;
bool SupportsSeeking;
bool SupportsSeeking = false;
#ifdef _WIN32
/// True if this fd refers to a Windows console device. Mintty and other
@@ -363,7 +423,7 @@ class raw_fd_ostream : public raw_pwrite_stream {
std::error_code EC;
uint64_t pos;
uint64_t pos = 0;
/// See raw_ostream::write_impl.
void write_impl(const char *Ptr, size_t Size) override;
@@ -377,10 +437,17 @@ class raw_fd_ostream : public raw_pwrite_stream {
/// 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; }
void anchor() override;
/// 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
@@ -405,7 +472,8 @@ public:
/// 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);
raw_fd_ostream(int fd, bool shouldClose, bool unbuffered = false,
OStreamKind K = OStreamKind::OK_OStream);
~raw_fd_ostream() override;
@@ -413,7 +481,7 @@ public:
/// fsync.
void close();
bool supportsSeeking() { return SupportsSeeking; }
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.
@@ -439,17 +507,37 @@ public:
void clear_error() { EC = std::error_code(); }
};
/// This returns a reference to a raw_ostream for standard output. Use it like:
/// outs() << "foo" << "bar";
raw_ostream &outs();
/// 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";
raw_ostream &errs();
/// 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
//===----------------------------------------------------------------------===//
@@ -467,7 +555,9 @@ class raw_string_ostream : public raw_ostream {
uint64_t current_pos() const override { return OS.size(); }
public:
explicit raw_string_ostream(std::string &O) : OS(O) {}
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
@@ -476,6 +566,10 @@ public:
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
@@ -508,7 +602,11 @@ public:
void flush() = delete;
/// Return a std::string_view for the vector contents.
std::string_view str() { return std::string_view(OS.data(), OS.size()); }
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
@@ -639,6 +737,18 @@ public:
~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 // LLVM_SUPPORT_RAW_OSTREAM_H
#endif // WPIUTIL_WPI_RAW_OSTREAM_H

View File

@@ -1,9 +1,8 @@
//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
//
@@ -18,41 +17,8 @@
#include <type_traits>
#include <utility>
#ifndef __has_feature
#define WPI_DEFINED_HAS_FEATURE
#define __has_feature(x) 0
#endif
namespace wpi {
/// isPodLike - This is a type trait that is used to determine whether a given
/// type can be copied around with memcpy instead of running ctors etc.
template <typename T>
struct isPodLike {
// std::is_trivially_copyable is available in libc++ with clang, libstdc++
// that comes with GCC 5.
#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \
(defined(__GNUC__) && __GNUC__ >= 5)
// If the compiler supports the is_trivially_copyable trait use it, as it
// matches the definition of isPodLike closely.
static const bool value = std::is_trivially_copyable<T>::value;
#elif __has_feature(is_trivially_copyable)
// Use the internal name if the compiler supports is_trivially_copyable but we
// don't know if the standard library does. This is the case for clang in
// conjunction with libstdc++ from GCC 4.x.
static const bool value = __is_trivially_copyable(T);
#else
// If we don't know anything else, we can (at least) assume that all non-class
// types are PODs.
static const bool value = !std::is_class<T>::value;
#endif
};
// std::pair's are pod-like if their elements are.
template<typename T, typename U>
struct isPodLike<std::pair<T, U>> {
static const bool value = isPodLike<T>::value && isPodLike<U>::value;
};
/// Metafunction that determines whether the given type is either an
/// integral type or an enumeration type, including enum classes.
@@ -62,7 +28,7 @@ struct isPodLike<std::pair<T, U>> {
/// Also note that enum classes aren't implicitly convertible to integral types,
/// the value may therefore need to be explicitly converted before being used.
template <typename T> class is_integral_or_enum {
using UnderlyingT = typename std::remove_reference<T>::type;
using UnderlyingT = std::remove_reference_t<T>;
public:
static const bool value =
@@ -79,7 +45,7 @@ struct add_lvalue_reference_if_not_pointer { using type = T &; };
template <typename T>
struct add_lvalue_reference_if_not_pointer<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
T, std::enable_if_t<std::is_pointer<T>::value>> {
using type = T;
};
@@ -89,9 +55,8 @@ template<typename T, typename Enable = void>
struct add_const_past_pointer { using type = const T; };
template <typename T>
struct add_const_past_pointer<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
using type = const typename std::remove_pointer<T>::type *;
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>
@@ -99,27 +64,41 @@ struct const_pointer_or_const_ref {
using type = const T &;
};
template <typename T>
struct const_pointer_or_const_ref<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
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 wpi
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;
};
// If the compiler supports detecting whether a class is final, define
// an LLVM_IS_FINAL macro. If it cannot be defined properly, this
// macro will be left undefined.
#ifndef LLVM_IS_FINAL
#if __cplusplus >= 201402L || defined(_MSC_VER)
#define LLVM_IS_FINAL(Ty) std::is_final<Ty>()
#elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0)
#define LLVM_IS_FINAL(Ty) __is_final(Ty)
#endif
#endif
template<class T>
union trivial_helper {
T t;
};
#ifdef WPI_DEFINED_HAS_FEATURE
#undef __has_feature
#undef WPI_DEFINED_HAS_FEATURE
#endif
} // end namespace detail
#endif // LLVM_SUPPORT_TYPE_TRAITS_H
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

View File

@@ -35,6 +35,9 @@ SOFTWARE.
#include "gtest/gtest.h"
#include "unit-json.h"
#include <cmath>
using wpi::json;
#include <fstream>

View File

@@ -35,6 +35,7 @@ SOFTWARE.
#include "gtest/gtest.h"
#include <array>
#include <cmath>
#include <deque>
#include <forward_list>
#include <list>

View File

@@ -38,6 +38,7 @@ SOFTWARE.
using wpi::json;
using wpi::JsonTest;
#include <cmath>
#include <deque>
//#include <forward_list>
#include <list>

View File

@@ -35,6 +35,9 @@ SOFTWARE.
#include "gtest/gtest.h"
#include "unit-json.h"
#include <cmath>
using wpi::json;
class JsonElementObjectAccessTestBase {

View File

@@ -37,6 +37,7 @@ SOFTWARE.
#include "unit-json.h"
using wpi::json;
#include <cmath>
#include <fstream>
TEST(MessagePackDiscardedTest, Case)

View File

@@ -35,6 +35,9 @@ SOFTWARE.
#include "gtest/gtest.h"
#include "unit-json.h"
#include <cmath>
using wpi::json;
TEST(JsonPointerTest, TypesCreate)

View File

@@ -0,0 +1,49 @@
//===- llvm/unittest/Support/Chrono.cpp - Time utilities tests ------------===//
//
// 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/Chrono.h"
#include "wpi/SmallVector.h"
#include "gtest/gtest.h"
using namespace wpi;
using namespace wpi::sys;
using namespace std::chrono;
namespace {
TEST(Chrono, TimeTConversion) {
EXPECT_EQ(time_t(0), toTimeT(toTimePoint(time_t(0))));
EXPECT_EQ(time_t(1), toTimeT(toTimePoint(time_t(1))));
EXPECT_EQ(time_t(47), toTimeT(toTimePoint(time_t(47))));
TimePoint<> TP;
EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
TP += seconds(1);
EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
TP += hours(47);
EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
}
// Test that toTimePoint and toTimeT can be called with a arguments with varying
// precisions.
TEST(Chrono, ImplicitConversions) {
std::time_t TimeT = 47;
TimePoint<seconds> Sec = toTimePoint(TimeT);
TimePoint<milliseconds> Milli = toTimePoint(TimeT);
TimePoint<microseconds> Micro = toTimePoint(TimeT);
TimePoint<nanoseconds> Nano = toTimePoint(TimeT);
EXPECT_EQ(Sec, Milli);
EXPECT_EQ(Sec, Micro);
EXPECT_EQ(Sec, Nano);
EXPECT_EQ(TimeT, toTimeT(Sec));
EXPECT_EQ(TimeT, toTimeT(Milli));
EXPECT_EQ(TimeT, toTimeT(Micro));
EXPECT_EQ(TimeT, toTimeT(Nano));
}
} // anonymous namespace

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,637 @@
//===- llvm/unittest/ADT/DenseMapMap.cpp - DenseMap unit tests --*- 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
//
//===----------------------------------------------------------------------===//
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#include "wpi/DenseMap.h"
#include "gtest/gtest.h"
#include <map>
#include <set>
using namespace wpi;
namespace {
uint32_t getTestKey(int i, uint32_t *) { return i; }
uint32_t getTestValue(int i, uint32_t *) { return 42 + i; }
uint32_t *getTestKey(int i, uint32_t **) {
static uint32_t dummy_arr1[8192];
assert(i < 8192 && "Only support 8192 dummy keys.");
return &dummy_arr1[i];
}
uint32_t *getTestValue(int i, uint32_t **) {
static uint32_t dummy_arr1[8192];
assert(i < 8192 && "Only support 8192 dummy keys.");
return &dummy_arr1[i];
}
/// A test class that tries to check that construction and destruction
/// occur correctly.
class CtorTester {
static std::set<CtorTester *> Constructed;
int Value;
public:
explicit CtorTester(int Value = 0) : Value(Value) {
EXPECT_TRUE(Constructed.insert(this).second);
}
CtorTester(uint32_t Value) : Value(Value) {
EXPECT_TRUE(Constructed.insert(this).second);
}
CtorTester(const CtorTester &Arg) : Value(Arg.Value) {
EXPECT_TRUE(Constructed.insert(this).second);
}
CtorTester &operator=(const CtorTester &) = default;
~CtorTester() {
EXPECT_EQ(1u, Constructed.erase(this));
}
operator uint32_t() const { return Value; }
int getValue() const { return Value; }
bool operator==(const CtorTester &RHS) const { return Value == RHS.Value; }
};
std::set<CtorTester *> CtorTester::Constructed;
struct CtorTesterMapInfo {
static inline CtorTester getEmptyKey() { return CtorTester(-1); }
static inline CtorTester getTombstoneKey() { return CtorTester(-2); }
static unsigned getHashValue(const CtorTester &Val) {
return Val.getValue() * 37u;
}
static bool isEqual(const CtorTester &LHS, const CtorTester &RHS) {
return LHS == RHS;
}
};
CtorTester getTestKey(int i, CtorTester *) { return CtorTester(i); }
CtorTester getTestValue(int i, CtorTester *) { return CtorTester(42 + i); }
// Test fixture, with helper functions implemented by forwarding to global
// function overloads selected by component types of the type parameter. This
// allows all of the map implementations to be tested with shared
// implementations of helper routines.
template <typename T>
class DenseMapTest : public ::testing::Test {
protected:
T Map;
static typename T::key_type *const dummy_key_ptr;
static typename T::mapped_type *const dummy_value_ptr;
typename T::key_type getKey(int i = 0) {
return getTestKey(i, dummy_key_ptr);
}
typename T::mapped_type getValue(int i = 0) {
return getTestValue(i, dummy_value_ptr);
}
};
template <typename T>
typename T::key_type *const DenseMapTest<T>::dummy_key_ptr = nullptr;
template <typename T>
typename T::mapped_type *const DenseMapTest<T>::dummy_value_ptr = nullptr;
// Register these types for testing.
typedef ::testing::Types<DenseMap<uint32_t, uint32_t>,
DenseMap<uint32_t *, uint32_t *>,
DenseMap<CtorTester, CtorTester, CtorTesterMapInfo>,
SmallDenseMap<uint32_t, uint32_t>,
SmallDenseMap<uint32_t *, uint32_t *>,
SmallDenseMap<CtorTester, CtorTester, 4,
CtorTesterMapInfo>
> DenseMapTestTypes;
TYPED_TEST_SUITE(DenseMapTest, DenseMapTestTypes, );
// Empty map tests
TYPED_TEST(DenseMapTest, EmptyIntMapTest) {
// Size tests
EXPECT_EQ(0u, this->Map.size());
EXPECT_TRUE(this->Map.empty());
// Iterator tests
EXPECT_TRUE(this->Map.begin() == this->Map.end());
// Lookup tests
EXPECT_FALSE(this->Map.count(this->getKey()));
EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.end());
EXPECT_EQ(typename TypeParam::mapped_type(),
this->Map.lookup(this->getKey()));
}
// Constant map tests
TYPED_TEST(DenseMapTest, ConstEmptyMapTest) {
const TypeParam &ConstMap = this->Map;
EXPECT_EQ(0u, ConstMap.size());
EXPECT_TRUE(ConstMap.empty());
EXPECT_TRUE(ConstMap.begin() == ConstMap.end());
}
// A map with a single entry
TYPED_TEST(DenseMapTest, SingleEntryMapTest) {
this->Map[this->getKey()] = this->getValue();
// Size tests
EXPECT_EQ(1u, this->Map.size());
EXPECT_FALSE(this->Map.begin() == this->Map.end());
EXPECT_FALSE(this->Map.empty());
// Iterator tests
typename TypeParam::iterator it = this->Map.begin();
EXPECT_EQ(this->getKey(), it->first);
EXPECT_EQ(this->getValue(), it->second);
++it;
EXPECT_TRUE(it == this->Map.end());
// Lookup tests
EXPECT_TRUE(this->Map.count(this->getKey()));
EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.begin());
EXPECT_EQ(this->getValue(), this->Map.lookup(this->getKey()));
EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
}
// Test clear() method
TYPED_TEST(DenseMapTest, ClearTest) {
this->Map[this->getKey()] = this->getValue();
this->Map.clear();
EXPECT_EQ(0u, this->Map.size());
EXPECT_TRUE(this->Map.empty());
EXPECT_TRUE(this->Map.begin() == this->Map.end());
}
// Test erase(iterator) method
TYPED_TEST(DenseMapTest, EraseTest) {
this->Map[this->getKey()] = this->getValue();
this->Map.erase(this->Map.begin());
EXPECT_EQ(0u, this->Map.size());
EXPECT_TRUE(this->Map.empty());
EXPECT_TRUE(this->Map.begin() == this->Map.end());
}
// Test erase(value) method
TYPED_TEST(DenseMapTest, EraseTest2) {
this->Map[this->getKey()] = this->getValue();
this->Map.erase(this->getKey());
EXPECT_EQ(0u, this->Map.size());
EXPECT_TRUE(this->Map.empty());
EXPECT_TRUE(this->Map.begin() == this->Map.end());
}
// Test insert() method
TYPED_TEST(DenseMapTest, InsertTest) {
this->Map.insert(std::make_pair(this->getKey(), this->getValue()));
EXPECT_EQ(1u, this->Map.size());
EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
}
// Test copy constructor method
TYPED_TEST(DenseMapTest, CopyConstructorTest) {
this->Map[this->getKey()] = this->getValue();
TypeParam copyMap(this->Map);
EXPECT_EQ(1u, copyMap.size());
EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
}
// Test copy constructor method where SmallDenseMap isn't small.
TYPED_TEST(DenseMapTest, CopyConstructorNotSmallTest) {
for (int Key = 0; Key < 5; ++Key)
this->Map[this->getKey(Key)] = this->getValue(Key);
TypeParam copyMap(this->Map);
EXPECT_EQ(5u, copyMap.size());
for (int Key = 0; Key < 5; ++Key)
EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
}
// Test copying from a default-constructed map.
TYPED_TEST(DenseMapTest, CopyConstructorFromDefaultTest) {
TypeParam copyMap(this->Map);
EXPECT_TRUE(copyMap.empty());
}
// Test copying from an empty map where SmallDenseMap isn't small.
TYPED_TEST(DenseMapTest, CopyConstructorFromEmptyTest) {
for (int Key = 0; Key < 5; ++Key)
this->Map[this->getKey(Key)] = this->getValue(Key);
this->Map.clear();
TypeParam copyMap(this->Map);
EXPECT_TRUE(copyMap.empty());
}
// Test assignment operator method
TYPED_TEST(DenseMapTest, AssignmentTest) {
this->Map[this->getKey()] = this->getValue();
TypeParam copyMap = this->Map;
EXPECT_EQ(1u, copyMap.size());
EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
// test self-assignment.
copyMap = static_cast<TypeParam &>(copyMap);
EXPECT_EQ(1u, copyMap.size());
EXPECT_EQ(this->getValue(), copyMap[this->getKey()]);
}
TYPED_TEST(DenseMapTest, AssignmentTestNotSmall) {
for (int Key = 0; Key < 5; ++Key)
this->Map[this->getKey(Key)] = this->getValue(Key);
TypeParam copyMap = this->Map;
EXPECT_EQ(5u, copyMap.size());
for (int Key = 0; Key < 5; ++Key)
EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
// test self-assignment.
copyMap = static_cast<TypeParam &>(copyMap);
EXPECT_EQ(5u, copyMap.size());
for (int Key = 0; Key < 5; ++Key)
EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
}
// Test swap method
TYPED_TEST(DenseMapTest, SwapTest) {
this->Map[this->getKey()] = this->getValue();
TypeParam otherMap;
this->Map.swap(otherMap);
EXPECT_EQ(0u, this->Map.size());
EXPECT_TRUE(this->Map.empty());
EXPECT_EQ(1u, otherMap.size());
EXPECT_EQ(this->getValue(), otherMap[this->getKey()]);
this->Map.swap(otherMap);
EXPECT_EQ(0u, otherMap.size());
EXPECT_TRUE(otherMap.empty());
EXPECT_EQ(1u, this->Map.size());
EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
// Make this more interesting by inserting 100 numbers into the map.
for (int i = 0; i < 100; ++i)
this->Map[this->getKey(i)] = this->getValue(i);
this->Map.swap(otherMap);
EXPECT_EQ(0u, this->Map.size());
EXPECT_TRUE(this->Map.empty());
EXPECT_EQ(100u, otherMap.size());
for (int i = 0; i < 100; ++i)
EXPECT_EQ(this->getValue(i), otherMap[this->getKey(i)]);
this->Map.swap(otherMap);
EXPECT_EQ(0u, otherMap.size());
EXPECT_TRUE(otherMap.empty());
EXPECT_EQ(100u, this->Map.size());
for (int i = 0; i < 100; ++i)
EXPECT_EQ(this->getValue(i), this->Map[this->getKey(i)]);
}
// A more complex iteration test
TYPED_TEST(DenseMapTest, IterationTest) {
bool visited[100];
std::map<typename TypeParam::key_type, unsigned> visitedIndex;
// Insert 100 numbers into the map
for (int i = 0; i < 100; ++i) {
visited[i] = false;
visitedIndex[this->getKey(i)] = i;
this->Map[this->getKey(i)] = this->getValue(i);
}
// Iterate over all numbers and mark each one found.
for (typename TypeParam::iterator it = this->Map.begin();
it != this->Map.end(); ++it)
visited[visitedIndex[it->first]] = true;
// Ensure every number was visited.
for (int i = 0; i < 100; ++i)
ASSERT_TRUE(visited[i]) << "Entry #" << i << " was never visited";
}
// const_iterator test
TYPED_TEST(DenseMapTest, ConstIteratorTest) {
// Check conversion from iterator to const_iterator.
typename TypeParam::iterator it = this->Map.begin();
typename TypeParam::const_iterator cit(it);
EXPECT_TRUE(it == cit);
// Check copying of const_iterators.
typename TypeParam::const_iterator cit2(cit);
EXPECT_TRUE(cit == cit2);
}
namespace {
// Simple class that counts how many moves and copy happens when growing a map
struct CountCopyAndMove {
static int Move;
static int Copy;
CountCopyAndMove() {}
CountCopyAndMove(const CountCopyAndMove &) { Copy++; }
CountCopyAndMove &operator=(const CountCopyAndMove &) {
Copy++;
return *this;
}
CountCopyAndMove(CountCopyAndMove &&) { Move++; }
CountCopyAndMove &operator=(const CountCopyAndMove &&) {
Move++;
return *this;
}
};
int CountCopyAndMove::Copy = 0;
int CountCopyAndMove::Move = 0;
} // anonymous namespace
// Test initializer list construction.
TEST(DenseMapCustomTest, InitializerList) {
DenseMap<int, int> M({{0, 0}, {0, 1}, {1, 2}});
EXPECT_EQ(2u, M.size());
EXPECT_EQ(1u, M.count(0));
EXPECT_EQ(0, M[0]);
EXPECT_EQ(1u, M.count(1));
EXPECT_EQ(2, M[1]);
}
// Test initializer list construction.
TEST(DenseMapCustomTest, EqualityComparison) {
DenseMap<int, int> M1({{0, 0}, {1, 2}});
DenseMap<int, int> M2({{0, 0}, {1, 2}});
DenseMap<int, int> M3({{0, 0}, {1, 3}});
EXPECT_EQ(M1, M2);
EXPECT_NE(M1, M3);
}
// Test for the default minimum size of a DenseMap
TEST(DenseMapCustomTest, DefaultMinReservedSizeTest) {
// IF THIS VALUE CHANGE, please update InitialSizeTest, InitFromIterator, and
// ReserveTest as well!
const int ExpectedInitialBucketCount = 64;
// Formula from DenseMap::getMinBucketToReserveForEntries()
const int ExpectedMaxInitialEntries = ExpectedInitialBucketCount * 3 / 4 - 1;
DenseMap<int, CountCopyAndMove> Map;
// Will allocate 64 buckets
Map.reserve(1);
unsigned MemorySize = Map.getMemorySize();
CountCopyAndMove::Copy = 0;
CountCopyAndMove::Move = 0;
for (int i = 0; i < ExpectedMaxInitialEntries; ++i)
Map.insert(std::pair<int, CountCopyAndMove>(std::piecewise_construct,
std::forward_as_tuple(i),
std::forward_as_tuple()));
// Check that we didn't grow
EXPECT_EQ(MemorySize, Map.getMemorySize());
// Check that move was called the expected number of times
EXPECT_EQ(ExpectedMaxInitialEntries, CountCopyAndMove::Move);
// Check that no copy occurred
EXPECT_EQ(0, CountCopyAndMove::Copy);
// Adding one extra element should grow the map
Map.insert(std::pair<int, CountCopyAndMove>(
std::piecewise_construct,
std::forward_as_tuple(ExpectedMaxInitialEntries),
std::forward_as_tuple()));
// Check that we grew
EXPECT_NE(MemorySize, Map.getMemorySize());
// Check that move was called the expected number of times
// This relies on move-construction elision, and cannot be reliably tested.
// EXPECT_EQ(ExpectedMaxInitialEntries + 2, CountCopyAndMove::Move);
// Check that no copy occurred
EXPECT_EQ(0, CountCopyAndMove::Copy);
}
// Make sure creating the map with an initial size of N actually gives us enough
// buckets to insert N items without increasing allocation size.
TEST(DenseMapCustomTest, InitialSizeTest) {
// Test a few different sizes, 48 is *not* a random choice: we need a value
// that is 2/3 of a power of two to stress the grow() condition, and the power
// of two has to be at least 64 because of minimum size allocation in the
// DenseMap (see DefaultMinReservedSizeTest). 66 is a value just above the
// 64 default init.
for (auto Size : {1, 2, 48, 66}) {
DenseMap<int, CountCopyAndMove> Map(Size);
unsigned MemorySize = Map.getMemorySize();
CountCopyAndMove::Copy = 0;
CountCopyAndMove::Move = 0;
for (int i = 0; i < Size; ++i)
Map.insert(std::pair<int, CountCopyAndMove>(std::piecewise_construct,
std::forward_as_tuple(i),
std::forward_as_tuple()));
// Check that we didn't grow
EXPECT_EQ(MemorySize, Map.getMemorySize());
// Check that move was called the expected number of times
EXPECT_EQ(Size, CountCopyAndMove::Move);
// Check that no copy occurred
EXPECT_EQ(0, CountCopyAndMove::Copy);
}
}
// Make sure creating the map with a iterator range does not trigger grow()
TEST(DenseMapCustomTest, InitFromIterator) {
std::vector<std::pair<int, CountCopyAndMove>> Values;
// The size is a random value greater than 64 (hardcoded DenseMap min init)
const int Count = 65;
for (int i = 0; i < Count; i++)
Values.emplace_back(i, CountCopyAndMove());
CountCopyAndMove::Move = 0;
CountCopyAndMove::Copy = 0;
DenseMap<int, CountCopyAndMove> Map(Values.begin(), Values.end());
// Check that no move occurred
EXPECT_EQ(0, CountCopyAndMove::Move);
// Check that copy was called the expected number of times
EXPECT_EQ(Count, CountCopyAndMove::Copy);
}
// Make sure reserve actually gives us enough buckets to insert N items
// without increasing allocation size.
TEST(DenseMapCustomTest, ReserveTest) {
// Test a few different size, 48 is *not* a random choice: we need a value
// that is 2/3 of a power of two to stress the grow() condition, and the power
// of two has to be at least 64 because of minimum size allocation in the
// DenseMap (see DefaultMinReservedSizeTest). 66 is a value just above the
// 64 default init.
for (auto Size : {1, 2, 48, 66}) {
DenseMap<int, CountCopyAndMove> Map;
Map.reserve(Size);
unsigned MemorySize = Map.getMemorySize();
CountCopyAndMove::Copy = 0;
CountCopyAndMove::Move = 0;
for (int i = 0; i < Size; ++i)
Map.insert(std::pair<int, CountCopyAndMove>(std::piecewise_construct,
std::forward_as_tuple(i),
std::forward_as_tuple()));
// Check that we didn't grow
EXPECT_EQ(MemorySize, Map.getMemorySize());
// Check that move was called the expected number of times
EXPECT_EQ(Size, CountCopyAndMove::Move);
// Check that no copy occurred
EXPECT_EQ(0, CountCopyAndMove::Copy);
}
}
// Key traits that allows lookup with either an unsigned or char* key;
// In the latter case, "a" == 0, "b" == 1 and so on.
struct TestDenseMapInfo {
static inline unsigned getEmptyKey() { return ~0; }
static inline unsigned getTombstoneKey() { return ~0U - 1; }
static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
static unsigned getHashValue(const char* Val) {
return (unsigned)(Val[0] - 'a') * 37U;
}
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
return LHS == RHS;
}
static bool isEqual(const char* LHS, const unsigned& RHS) {
return (unsigned)(LHS[0] - 'a') == RHS;
}
};
// find_as() tests
TEST(DenseMapCustomTest, FindAsTest) {
DenseMap<unsigned, unsigned, TestDenseMapInfo> map;
map[0] = 1;
map[1] = 2;
map[2] = 3;
// Size tests
EXPECT_EQ(3u, map.size());
// Normal lookup tests
EXPECT_EQ(1u, map.count(1));
EXPECT_EQ(1u, map.find(0)->second);
EXPECT_EQ(2u, map.find(1)->second);
EXPECT_EQ(3u, map.find(2)->second);
EXPECT_TRUE(map.find(3) == map.end());
// find_as() tests
EXPECT_EQ(1u, map.find_as("a")->second);
EXPECT_EQ(2u, map.find_as("b")->second);
EXPECT_EQ(3u, map.find_as("c")->second);
EXPECT_TRUE(map.find_as("d") == map.end());
}
TEST(DenseMapCustomTest, SmallDenseMapInitializerList) {
SmallDenseMap<int, int> M = {{0, 0}, {0, 1}, {1, 2}};
EXPECT_EQ(2u, M.size());
EXPECT_EQ(1u, M.count(0));
EXPECT_EQ(0, M[0]);
EXPECT_EQ(1u, M.count(1));
EXPECT_EQ(2, M[1]);
}
struct ContiguousDenseMapInfo {
static inline unsigned getEmptyKey() { return ~0; }
static inline unsigned getTombstoneKey() { return ~0U - 1; }
static unsigned getHashValue(const unsigned& Val) { return Val; }
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
return LHS == RHS;
}
};
// Test that filling a small dense map with exactly the number of elements in
// the map grows to have enough space for an empty bucket.
TEST(DenseMapCustomTest, SmallDenseMapGrowTest) {
SmallDenseMap<unsigned, unsigned, 32, ContiguousDenseMapInfo> map;
// Add some number of elements, then delete a few to leave us some tombstones.
// If we just filled the map with 32 elements we'd grow because of not enough
// tombstones which masks the issue here.
for (unsigned i = 0; i < 20; ++i)
map[i] = i + 1;
for (unsigned i = 0; i < 10; ++i)
map.erase(i);
for (unsigned i = 20; i < 32; ++i)
map[i] = i + 1;
// Size tests
EXPECT_EQ(22u, map.size());
// Try to find an element which doesn't exist. There was a bug in
// SmallDenseMap which led to a map with num elements == small capacity not
// having an empty bucket any more. Finding an element not in the map would
// therefore never terminate.
EXPECT_TRUE(map.find(32) == map.end());
}
TEST(DenseMapCustomTest, LargeSmallDenseMapCompaction) {
SmallDenseMap<unsigned, unsigned, 128, ContiguousDenseMapInfo> map;
// Fill to < 3/4 load.
for (unsigned i = 0; i < 95; ++i)
map[i] = i;
// And erase, leaving behind tombstones.
for (unsigned i = 0; i < 95; ++i)
map.erase(i);
// Fill further, so that less than 1/8 are empty, but still below 3/4 load.
for (unsigned i = 95; i < 128; ++i)
map[i] = i;
EXPECT_EQ(33u, map.size());
// Similar to the previous test, check for a non-existing element, as an
// indirect check that tombstones have been removed.
EXPECT_TRUE(map.find(0) == map.end());
}
TEST(DenseMapCustomTest, TryEmplaceTest) {
DenseMap<int, std::unique_ptr<int>> Map;
std::unique_ptr<int> P(new int(2));
auto Try1 = Map.try_emplace(0, new int(1));
EXPECT_TRUE(Try1.second);
auto Try2 = Map.try_emplace(0, std::move(P));
EXPECT_FALSE(Try2.second);
EXPECT_EQ(Try1.first, Try2.first);
EXPECT_NE(nullptr, P);
}
TEST(DenseMapCustomTest, ConstTest) {
// Test that const pointers work okay for count and find, even when the
// underlying map is a non-const pointer.
DenseMap<int *, int> Map;
int A;
int *B = &A;
const int *C = &A;
Map.insert({B, 0});
EXPECT_EQ(Map.count(B), 1u);
EXPECT_EQ(Map.count(C), 1u);
EXPECT_NE(Map.find(B), Map.end());
EXPECT_NE(Map.find(C), Map.end());
}
struct IncompleteStruct;
TEST(DenseMapCustomTest, OpaquePointerKey) {
// Test that we can use a pointer to an incomplete type as a DenseMap key.
// This is an important build time optimization, since many classes have
// DenseMap members.
DenseMap<IncompleteStruct *, int> Map;
int Keys[3] = {0, 0, 0};
IncompleteStruct *K1 = reinterpret_cast<IncompleteStruct *>(&Keys[0]);
IncompleteStruct *K2 = reinterpret_cast<IncompleteStruct *>(&Keys[1]);
IncompleteStruct *K3 = reinterpret_cast<IncompleteStruct *>(&Keys[2]);
Map.insert({K1, 1});
Map.insert({K2, 2});
Map.insert({K3, 3});
EXPECT_EQ(Map.count(K1), 1u);
EXPECT_EQ(Map[K1], 1);
EXPECT_EQ(Map[K2], 2);
EXPECT_EQ(Map[K3], 3);
Map.clear();
EXPECT_EQ(Map.find(K1), Map.end());
EXPECT_EQ(Map.find(K2), Map.end());
EXPECT_EQ(Map.find(K3), Map.end());
}
}

View File

@@ -0,0 +1,211 @@
//===- unittests/Support/EndianTest.cpp - Endian.h tests ------------------===//
//
// 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/Endian.h"
#include "gtest/gtest.h"
#include <cstdlib>
#include <ctime>
using namespace wpi;
using namespace support;
#undef max
namespace {
TEST(Endian, Read) {
// These are 5 bytes so we can be sure at least one of the reads is unaligned.
unsigned char bigval[] = {0x00, 0x01, 0x02, 0x03, 0x04};
unsigned char littleval[] = {0x00, 0x04, 0x03, 0x02, 0x01};
int32_t BigAsHost = 0x00010203;
EXPECT_EQ(BigAsHost, (endian::read<int32_t, big, unaligned>(bigval)));
int32_t LittleAsHost = 0x02030400;
EXPECT_EQ(LittleAsHost,(endian::read<int32_t, little, unaligned>(littleval)));
EXPECT_EQ((endian::read<int32_t, big, unaligned>(bigval + 1)),
(endian::read<int32_t, little, unaligned>(littleval + 1)));
}
TEST(Endian, ReadBitAligned) {
// Simple test to make sure we properly pull out the 0x0 word.
unsigned char littleval[] = {0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff};
unsigned char bigval[] = {0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0};
EXPECT_EQ(
(endian::readAtBitAlignment<int, little, unaligned>(&littleval[0], 6)),
0x0);
EXPECT_EQ((endian::readAtBitAlignment<int, big, unaligned>(&bigval[0], 6)),
0x0);
// Test to make sure that signed right shift of 0xf0000000 is masked
// properly.
unsigned char littleval2[] = {0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00};
unsigned char bigval2[] = {0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
EXPECT_EQ(
(endian::readAtBitAlignment<int, little, unaligned>(&littleval2[0], 4)),
0x0f000000);
EXPECT_EQ((endian::readAtBitAlignment<int, big, unaligned>(&bigval2[0], 4)),
0x0f000000);
// Test to make sure left shift of start bit doesn't overflow.
EXPECT_EQ(
(endian::readAtBitAlignment<int, little, unaligned>(&littleval2[0], 1)),
0x78000000);
EXPECT_EQ((endian::readAtBitAlignment<int, big, unaligned>(&bigval2[0], 1)),
0x78000000);
// Test to make sure 64-bit int doesn't overflow.
unsigned char littleval3[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char bigval3[] = {0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
EXPECT_EQ((endian::readAtBitAlignment<int64_t, little, unaligned>(
&littleval3[0], 4)),
0x0f00000000000000);
EXPECT_EQ(
(endian::readAtBitAlignment<int64_t, big, unaligned>(&bigval3[0], 4)),
0x0f00000000000000);
}
TEST(Endian, WriteBitAligned) {
// This test ensures that signed right shift of 0xffffaa is masked
// properly.
unsigned char bigval[8] = {0x00};
endian::writeAtBitAlignment<int32_t, big, unaligned>(bigval, (int)0xffffaaaa,
4);
EXPECT_EQ(bigval[0], 0xff);
EXPECT_EQ(bigval[1], 0xfa);
EXPECT_EQ(bigval[2], 0xaa);
EXPECT_EQ(bigval[3], 0xa0);
EXPECT_EQ(bigval[4], 0x00);
EXPECT_EQ(bigval[5], 0x00);
EXPECT_EQ(bigval[6], 0x00);
EXPECT_EQ(bigval[7], 0x0f);
unsigned char littleval[8] = {0x00};
endian::writeAtBitAlignment<int32_t, little, unaligned>(littleval,
(int)0xffffaaaa, 4);
EXPECT_EQ(littleval[0], 0xa0);
EXPECT_EQ(littleval[1], 0xaa);
EXPECT_EQ(littleval[2], 0xfa);
EXPECT_EQ(littleval[3], 0xff);
EXPECT_EQ(littleval[4], 0x0f);
EXPECT_EQ(littleval[5], 0x00);
EXPECT_EQ(littleval[6], 0x00);
EXPECT_EQ(littleval[7], 0x00);
// This test makes sure 1<<31 doesn't overflow.
// Test to make sure left shift of start bit doesn't overflow.
unsigned char bigval2[8] = {0x00};
endian::writeAtBitAlignment<int32_t, big, unaligned>(bigval2, (int)0xffffffff,
1);
EXPECT_EQ(bigval2[0], 0xff);
EXPECT_EQ(bigval2[1], 0xff);
EXPECT_EQ(bigval2[2], 0xff);
EXPECT_EQ(bigval2[3], 0xfe);
EXPECT_EQ(bigval2[4], 0x00);
EXPECT_EQ(bigval2[5], 0x00);
EXPECT_EQ(bigval2[6], 0x00);
EXPECT_EQ(bigval2[7], 0x01);
unsigned char littleval2[8] = {0x00};
endian::writeAtBitAlignment<int32_t, little, unaligned>(littleval2,
(int)0xffffffff, 1);
EXPECT_EQ(littleval2[0], 0xfe);
EXPECT_EQ(littleval2[1], 0xff);
EXPECT_EQ(littleval2[2], 0xff);
EXPECT_EQ(littleval2[3], 0xff);
EXPECT_EQ(littleval2[4], 0x01);
EXPECT_EQ(littleval2[5], 0x00);
EXPECT_EQ(littleval2[6], 0x00);
EXPECT_EQ(littleval2[7], 0x00);
// Test to make sure 64-bit int doesn't overflow.
unsigned char bigval64[16] = {0x00};
endian::writeAtBitAlignment<int64_t, big, unaligned>(
bigval64, (int64_t)0xffffffffffffffff, 1);
EXPECT_EQ(bigval64[0], 0xff);
EXPECT_EQ(bigval64[1], 0xff);
EXPECT_EQ(bigval64[2], 0xff);
EXPECT_EQ(bigval64[3], 0xff);
EXPECT_EQ(bigval64[4], 0xff);
EXPECT_EQ(bigval64[5], 0xff);
EXPECT_EQ(bigval64[6], 0xff);
EXPECT_EQ(bigval64[7], 0xfe);
EXPECT_EQ(bigval64[8], 0x00);
EXPECT_EQ(bigval64[9], 0x00);
EXPECT_EQ(bigval64[10], 0x00);
EXPECT_EQ(bigval64[11], 0x00);
EXPECT_EQ(bigval64[12], 0x00);
EXPECT_EQ(bigval64[13], 0x00);
EXPECT_EQ(bigval64[14], 0x00);
EXPECT_EQ(bigval64[15], 0x01);
unsigned char littleval64[16] = {0x00};
endian::writeAtBitAlignment<int64_t, little, unaligned>(
littleval64, (int64_t)0xffffffffffffffff, 1);
EXPECT_EQ(littleval64[0], 0xfe);
EXPECT_EQ(littleval64[1], 0xff);
EXPECT_EQ(littleval64[2], 0xff);
EXPECT_EQ(littleval64[3], 0xff);
EXPECT_EQ(littleval64[4], 0xff);
EXPECT_EQ(littleval64[5], 0xff);
EXPECT_EQ(littleval64[6], 0xff);
EXPECT_EQ(littleval64[7], 0xff);
EXPECT_EQ(littleval64[8], 0x01);
EXPECT_EQ(littleval64[9], 0x00);
EXPECT_EQ(littleval64[10], 0x00);
EXPECT_EQ(littleval64[11], 0x00);
EXPECT_EQ(littleval64[12], 0x00);
EXPECT_EQ(littleval64[13], 0x00);
EXPECT_EQ(littleval64[14], 0x00);
EXPECT_EQ(littleval64[15], 0x00);
}
TEST(Endian, Write) {
unsigned char data[5];
endian::write<int32_t, big, unaligned>(data, -1362446643);
EXPECT_EQ(data[0], 0xAE);
EXPECT_EQ(data[1], 0xCA);
EXPECT_EQ(data[2], 0xB6);
EXPECT_EQ(data[3], 0xCD);
endian::write<int32_t, big, unaligned>(data + 1, -1362446643);
EXPECT_EQ(data[1], 0xAE);
EXPECT_EQ(data[2], 0xCA);
EXPECT_EQ(data[3], 0xB6);
EXPECT_EQ(data[4], 0xCD);
endian::write<int32_t, little, unaligned>(data, -1362446643);
EXPECT_EQ(data[0], 0xCD);
EXPECT_EQ(data[1], 0xB6);
EXPECT_EQ(data[2], 0xCA);
EXPECT_EQ(data[3], 0xAE);
endian::write<int32_t, little, unaligned>(data + 1, -1362446643);
EXPECT_EQ(data[1], 0xCD);
EXPECT_EQ(data[2], 0xB6);
EXPECT_EQ(data[3], 0xCA);
EXPECT_EQ(data[4], 0xAE);
}
TEST(Endian, PackedEndianSpecificIntegral) {
// These are 5 bytes so we can be sure at least one of the reads is unaligned.
unsigned char big[] = {0x00, 0x01, 0x02, 0x03, 0x04};
unsigned char little[] = {0x00, 0x04, 0x03, 0x02, 0x01};
big32_t *big_val =
reinterpret_cast<big32_t *>(big + 1);
little32_t *little_val =
reinterpret_cast<little32_t *>(little + 1);
EXPECT_EQ(*big_val, *little_val);
}
TEST(Endian, PacketEndianSpecificIntegralAsEnum) {
enum class Test : uint16_t { ONETWO = 0x0102, TWOONE = 0x0201 };
unsigned char bytes[] = {0x01, 0x02};
using LittleTest = little_t<Test>;
using BigTest = big_t<Test>;
EXPECT_EQ(Test::TWOONE, *reinterpret_cast<LittleTest *>(bytes));
EXPECT_EQ(Test::ONETWO, *reinterpret_cast<BigTest *>(bytes));
}
} // end anon namespace

View File

@@ -0,0 +1,38 @@
//===- ErrnoTest.cpp - Error handling unit tests --------------------------===//
//
// 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/Errno.h"
#include "gtest/gtest.h"
using namespace wpi::sys;
TEST(ErrnoTest, RetryAfterSignal) {
EXPECT_EQ(1, RetryAfterSignal(-1, [] { return 1; }));
EXPECT_EQ(-1, RetryAfterSignal(-1, [] {
errno = EAGAIN;
return -1;
}));
EXPECT_EQ(EAGAIN, errno);
unsigned calls = 0;
EXPECT_EQ(1, RetryAfterSignal(-1, [&calls] {
errno = EINTR;
++calls;
return calls == 1 ? -1 : 1;
}));
EXPECT_EQ(2u, calls);
EXPECT_EQ(1, RetryAfterSignal(-1, [](int x) { return x; }, 1));
std::unique_ptr<int> P(RetryAfterSignal(nullptr, [] { return new int(47); }));
EXPECT_EQ(47, *P);
errno = EINTR;
EXPECT_EQ(-1, RetryAfterSignal(-1, [] { return -1; }));
}

View File

@@ -1,9 +1,8 @@
//===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 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
//
//===----------------------------------------------------------------------===//
@@ -11,6 +10,7 @@
#include "gtest/gtest.h"
#include <memory>
#include <type_traits>
using namespace wpi;
@@ -225,4 +225,70 @@ TEST(UniqueFunctionTest, CountForwardingMoves) {
UnmovableF(X);
}
TEST(UniqueFunctionTest, Const) {
// Can assign from const lambda.
unique_function<int(int) const> Plus2 = [X(std::make_unique<int>(2))](int Y) {
return *X + Y;
};
EXPECT_EQ(5, Plus2(3));
// Can call through a const ref.
const auto &Plus2Ref = Plus2;
EXPECT_EQ(5, Plus2Ref(3));
// Can move-construct and assign.
unique_function<int(int) const> Plus2A = std::move(Plus2);
EXPECT_EQ(5, Plus2A(3));
unique_function<int(int) const> Plus2B;
Plus2B = std::move(Plus2A);
EXPECT_EQ(5, Plus2B(3));
// Can convert to non-const function type, but not back.
unique_function<int(int)> Plus2C = std::move(Plus2B);
EXPECT_EQ(5, Plus2C(3));
// Overloaded call operator correctly resolved.
struct ChooseCorrectOverload {
std::string_view operator()() { return "non-const"; }
std::string_view operator()() const { return "const"; }
};
unique_function<std::string_view()> ChooseMutable = ChooseCorrectOverload();
ChooseCorrectOverload A;
EXPECT_EQ("non-const", ChooseMutable());
EXPECT_EQ("non-const", A());
unique_function<std::string_view() const> ChooseConst = ChooseCorrectOverload();
const ChooseCorrectOverload &X = A;
EXPECT_EQ("const", ChooseConst());
EXPECT_EQ("const", X());
}
// Test that overloads on unique_functions are resolved as expected.
std::string returns(std::string_view) { return "not a function"; }
std::string returns(unique_function<double()> F) { return "number"; }
std::string returns(unique_function<std::string_view()> F) { return "string"; }
TEST(UniqueFunctionTest, SFINAE) {
EXPECT_EQ("not a function", returns("boo!"));
EXPECT_EQ("number", returns([] { return 42; }));
EXPECT_EQ("string", returns([] { return "hello"; }));
}
// A forward declared type, and a templated type.
class Incomplete;
template <typename T> class Templated { T A; };
// Check that we can define unique_function that have references to
// incomplete types, even if those types are templated over an
// incomplete type.
TEST(UniqueFunctionTest, IncompleteTypes) {
unique_function<void(Templated<Incomplete> &&)>
IncompleteArgumentRValueReference;
unique_function<void(Templated<Incomplete> &)>
IncompleteArgumentLValueReference;
unique_function<void(Templated<Incomplete> *)> IncompleteArgumentPointer;
unique_function<Templated<Incomplete> &()> IncompleteResultLValueReference;
unique_function<Templated<Incomplete> && ()> IncompleteResultRValueReference2;
unique_function<Templated<Incomplete> *()> IncompleteResultPointer;
}
} // anonymous namespace

View File

@@ -0,0 +1,430 @@
//===- unittest/ADT/MapVectorTest.cpp - MapVector unit tests ----*- 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
//
//===----------------------------------------------------------------------===//
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wpedantic"
#if !defined(__clang__)
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#endif
#include "wpi/MapVector.h"
#include "wpi/iterator_range.h"
#include "gtest/gtest.h"
#include <utility>
using namespace wpi;
TEST(MapVectorTest, swap) {
MapVector<int, int> MV1, MV2;
std::pair<MapVector<int, int>::iterator, bool> R;
R = MV1.insert(std::make_pair(1, 2));
ASSERT_EQ(R.first, MV1.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_TRUE(R.second);
EXPECT_FALSE(MV1.empty());
EXPECT_TRUE(MV2.empty());
MV2.swap(MV1);
EXPECT_TRUE(MV1.empty());
EXPECT_FALSE(MV2.empty());
auto I = MV1.find(1);
ASSERT_EQ(MV1.end(), I);
I = MV2.find(1);
ASSERT_EQ(I, MV2.begin());
EXPECT_EQ(I->first, 1);
EXPECT_EQ(I->second, 2);
}
TEST(MapVectorTest, insert_pop) {
MapVector<int, int> MV;
std::pair<MapVector<int, int>::iterator, bool> R;
R = MV.insert(std::make_pair(1, 2));
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_TRUE(R.second);
R = MV.insert(std::make_pair(1, 3));
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_FALSE(R.second);
R = MV.insert(std::make_pair(4, 5));
ASSERT_NE(R.first, MV.end());
EXPECT_EQ(R.first->first, 4);
EXPECT_EQ(R.first->second, 5);
EXPECT_TRUE(R.second);
EXPECT_EQ(MV.size(), 2u);
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 5);
MV.pop_back();
EXPECT_EQ(MV.size(), 1u);
EXPECT_EQ(MV[1], 2);
R = MV.insert(std::make_pair(4, 7));
ASSERT_NE(R.first, MV.end());
EXPECT_EQ(R.first->first, 4);
EXPECT_EQ(R.first->second, 7);
EXPECT_TRUE(R.second);
EXPECT_EQ(MV.size(), 2u);
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 7);
}
TEST(MapVectorTest, erase) {
MapVector<int, int> MV;
MV.insert(std::make_pair(1, 2));
MV.insert(std::make_pair(3, 4));
MV.insert(std::make_pair(5, 6));
ASSERT_EQ(MV.size(), 3u);
MV.erase(MV.find(1));
ASSERT_EQ(MV.size(), 2u);
ASSERT_EQ(MV.find(1), MV.end());
ASSERT_EQ(MV[3], 4);
ASSERT_EQ(MV[5], 6);
ASSERT_EQ(MV.erase(3), 1u);
ASSERT_EQ(MV.size(), 1u);
ASSERT_EQ(MV.find(3), MV.end());
ASSERT_EQ(MV[5], 6);
ASSERT_EQ(MV.erase(79), 0u);
ASSERT_EQ(MV.size(), 1u);
}
TEST(MapVectorTest, remove_if) {
MapVector<int, int> MV;
MV.insert(std::make_pair(1, 11));
MV.insert(std::make_pair(2, 12));
MV.insert(std::make_pair(3, 13));
MV.insert(std::make_pair(4, 14));
MV.insert(std::make_pair(5, 15));
MV.insert(std::make_pair(6, 16));
ASSERT_EQ(MV.size(), 6u);
MV.remove_if([](const std::pair<int, int> &Val) { return Val.second % 2; });
ASSERT_EQ(MV.size(), 3u);
ASSERT_EQ(MV.find(1), MV.end());
ASSERT_EQ(MV.find(3), MV.end());
ASSERT_EQ(MV.find(5), MV.end());
ASSERT_EQ(MV[2], 12);
ASSERT_EQ(MV[4], 14);
ASSERT_EQ(MV[6], 16);
}
TEST(MapVectorTest, iteration_test) {
MapVector<int, int> MV;
MV.insert(std::make_pair(1, 11));
MV.insert(std::make_pair(2, 12));
MV.insert(std::make_pair(3, 13));
MV.insert(std::make_pair(4, 14));
MV.insert(std::make_pair(5, 15));
MV.insert(std::make_pair(6, 16));
ASSERT_EQ(MV.size(), 6u);
int count = 1;
for (auto P : make_range(MV.begin(), MV.end())) {
ASSERT_EQ(P.first, count);
count++;
}
count = 6;
for (auto P : make_range(MV.rbegin(), MV.rend())) {
ASSERT_EQ(P.first, count);
count--;
}
}
TEST(MapVectorTest, NonCopyable) {
MapVector<int, std::unique_ptr<int>> MV;
MV.insert(std::make_pair(1, std::make_unique<int>(1)));
MV.insert(std::make_pair(2, std::make_unique<int>(2)));
ASSERT_EQ(MV.count(1), 1u);
ASSERT_EQ(*MV.find(2)->second, 2);
}
template <class IntType> struct MapVectorMappedTypeTest : ::testing::Test {
using int_type = IntType;
};
using MapIntTypes = ::testing::Types<int, long, long long, unsigned,
unsigned long, unsigned long long>;
TYPED_TEST_SUITE(MapVectorMappedTypeTest, MapIntTypes, );
TYPED_TEST(MapVectorMappedTypeTest, DifferentDenseMap) {
// Test that using a map with a mapped type other than 'unsigned' compiles
// and works.
using IntType = typename TestFixture::int_type;
using MapVectorType = MapVector<int, int, DenseMap<int, IntType>>;
MapVectorType MV;
std::pair<typename MapVectorType::iterator, bool> R;
R = MV.insert(std::make_pair(1, 2));
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_TRUE(R.second);
const std::pair<int, int> Elem(1, 3);
R = MV.insert(Elem);
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_FALSE(R.second);
int& value = MV[4];
EXPECT_EQ(value, 0);
value = 5;
EXPECT_EQ(MV.size(), 2u);
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 5);
}
TEST(SmallMapVectorSmallTest, insert_pop) {
SmallMapVector<int, int, 32> MV;
std::pair<SmallMapVector<int, int, 32>::iterator, bool> R;
R = MV.insert(std::make_pair(1, 2));
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_TRUE(R.second);
R = MV.insert(std::make_pair(1, 3));
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_FALSE(R.second);
R = MV.insert(std::make_pair(4, 5));
ASSERT_NE(R.first, MV.end());
EXPECT_EQ(R.first->first, 4);
EXPECT_EQ(R.first->second, 5);
EXPECT_TRUE(R.second);
EXPECT_EQ(MV.size(), 2u);
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 5);
MV.pop_back();
EXPECT_EQ(MV.size(), 1u);
EXPECT_EQ(MV[1], 2);
R = MV.insert(std::make_pair(4, 7));
ASSERT_NE(R.first, MV.end());
EXPECT_EQ(R.first->first, 4);
EXPECT_EQ(R.first->second, 7);
EXPECT_TRUE(R.second);
EXPECT_EQ(MV.size(), 2u);
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 7);
}
TEST(SmallMapVectorSmallTest, erase) {
SmallMapVector<int, int, 32> MV;
MV.insert(std::make_pair(1, 2));
MV.insert(std::make_pair(3, 4));
MV.insert(std::make_pair(5, 6));
ASSERT_EQ(MV.size(), 3u);
MV.erase(MV.find(1));
ASSERT_EQ(MV.size(), 2u);
ASSERT_EQ(MV.find(1), MV.end());
ASSERT_EQ(MV[3], 4);
ASSERT_EQ(MV[5], 6);
ASSERT_EQ(MV.erase(3), 1u);
ASSERT_EQ(MV.size(), 1u);
ASSERT_EQ(MV.find(3), MV.end());
ASSERT_EQ(MV[5], 6);
ASSERT_EQ(MV.erase(79), 0u);
ASSERT_EQ(MV.size(), 1u);
}
TEST(SmallMapVectorSmallTest, remove_if) {
SmallMapVector<int, int, 32> MV;
MV.insert(std::make_pair(1, 11));
MV.insert(std::make_pair(2, 12));
MV.insert(std::make_pair(3, 13));
MV.insert(std::make_pair(4, 14));
MV.insert(std::make_pair(5, 15));
MV.insert(std::make_pair(6, 16));
ASSERT_EQ(MV.size(), 6u);
MV.remove_if([](const std::pair<int, int> &Val) { return Val.second % 2; });
ASSERT_EQ(MV.size(), 3u);
ASSERT_EQ(MV.find(1), MV.end());
ASSERT_EQ(MV.find(3), MV.end());
ASSERT_EQ(MV.find(5), MV.end());
ASSERT_EQ(MV[2], 12);
ASSERT_EQ(MV[4], 14);
ASSERT_EQ(MV[6], 16);
}
TEST(SmallMapVectorSmallTest, iteration_test) {
SmallMapVector<int, int, 32> MV;
MV.insert(std::make_pair(1, 11));
MV.insert(std::make_pair(2, 12));
MV.insert(std::make_pair(3, 13));
MV.insert(std::make_pair(4, 14));
MV.insert(std::make_pair(5, 15));
MV.insert(std::make_pair(6, 16));
ASSERT_EQ(MV.size(), 6u);
int count = 1;
for (auto P : make_range(MV.begin(), MV.end())) {
ASSERT_EQ(P.first, count);
count++;
}
count = 6;
for (auto P : make_range(MV.rbegin(), MV.rend())) {
ASSERT_EQ(P.first, count);
count--;
}
}
TEST(SmallMapVectorSmallTest, NonCopyable) {
SmallMapVector<int, std::unique_ptr<int>, 8> MV;
MV.insert(std::make_pair(1, std::make_unique<int>(1)));
MV.insert(std::make_pair(2, std::make_unique<int>(2)));
ASSERT_EQ(MV.count(1), 1u);
ASSERT_EQ(*MV.find(2)->second, 2);
}
TEST(SmallMapVectorLargeTest, insert_pop) {
SmallMapVector<int, int, 1> MV;
std::pair<SmallMapVector<int, int, 1>::iterator, bool> R;
R = MV.insert(std::make_pair(1, 2));
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_TRUE(R.second);
R = MV.insert(std::make_pair(1, 3));
ASSERT_EQ(R.first, MV.begin());
EXPECT_EQ(R.first->first, 1);
EXPECT_EQ(R.first->second, 2);
EXPECT_FALSE(R.second);
R = MV.insert(std::make_pair(4, 5));
ASSERT_NE(R.first, MV.end());
EXPECT_EQ(R.first->first, 4);
EXPECT_EQ(R.first->second, 5);
EXPECT_TRUE(R.second);
EXPECT_EQ(MV.size(), 2u);
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 5);
MV.pop_back();
EXPECT_EQ(MV.size(), 1u);
EXPECT_EQ(MV[1], 2);
R = MV.insert(std::make_pair(4, 7));
ASSERT_NE(R.first, MV.end());
EXPECT_EQ(R.first->first, 4);
EXPECT_EQ(R.first->second, 7);
EXPECT_TRUE(R.second);
EXPECT_EQ(MV.size(), 2u);
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 7);
}
TEST(SmallMapVectorLargeTest, erase) {
SmallMapVector<int, int, 1> MV;
MV.insert(std::make_pair(1, 2));
MV.insert(std::make_pair(3, 4));
MV.insert(std::make_pair(5, 6));
ASSERT_EQ(MV.size(), 3u);
MV.erase(MV.find(1));
ASSERT_EQ(MV.size(), 2u);
ASSERT_EQ(MV.find(1), MV.end());
ASSERT_EQ(MV[3], 4);
ASSERT_EQ(MV[5], 6);
ASSERT_EQ(MV.erase(3), 1u);
ASSERT_EQ(MV.size(), 1u);
ASSERT_EQ(MV.find(3), MV.end());
ASSERT_EQ(MV[5], 6);
ASSERT_EQ(MV.erase(79), 0u);
ASSERT_EQ(MV.size(), 1u);
}
TEST(SmallMapVectorLargeTest, remove_if) {
SmallMapVector<int, int, 1> MV;
MV.insert(std::make_pair(1, 11));
MV.insert(std::make_pair(2, 12));
MV.insert(std::make_pair(3, 13));
MV.insert(std::make_pair(4, 14));
MV.insert(std::make_pair(5, 15));
MV.insert(std::make_pair(6, 16));
ASSERT_EQ(MV.size(), 6u);
MV.remove_if([](const std::pair<int, int> &Val) { return Val.second % 2; });
ASSERT_EQ(MV.size(), 3u);
ASSERT_EQ(MV.find(1), MV.end());
ASSERT_EQ(MV.find(3), MV.end());
ASSERT_EQ(MV.find(5), MV.end());
ASSERT_EQ(MV[2], 12);
ASSERT_EQ(MV[4], 14);
ASSERT_EQ(MV[6], 16);
}
TEST(SmallMapVectorLargeTest, iteration_test) {
SmallMapVector<int, int, 1> MV;
MV.insert(std::make_pair(1, 11));
MV.insert(std::make_pair(2, 12));
MV.insert(std::make_pair(3, 13));
MV.insert(std::make_pair(4, 14));
MV.insert(std::make_pair(5, 15));
MV.insert(std::make_pair(6, 16));
ASSERT_EQ(MV.size(), 6u);
int count = 1;
for (auto P : make_range(MV.begin(), MV.end())) {
ASSERT_EQ(P.first, count);
count++;
}
count = 6;
for (auto P : make_range(MV.rbegin(), MV.rend())) {
ASSERT_EQ(P.first, count);
count--;
}
}

View File

@@ -0,0 +1,607 @@
//===- unittests/Support/MathExtrasTest.cpp - math utils tests ------------===//
//
// 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/MathExtras.h"
#include "gtest/gtest.h"
using namespace wpi;
namespace {
TEST(MathExtras, countTrailingZeros) {
uint8_t Z8 = 0;
uint16_t Z16 = 0;
uint32_t Z32 = 0;
uint64_t Z64 = 0;
EXPECT_EQ(8u, countTrailingZeros(Z8));
EXPECT_EQ(16u, countTrailingZeros(Z16));
EXPECT_EQ(32u, countTrailingZeros(Z32));
EXPECT_EQ(64u, countTrailingZeros(Z64));
uint8_t NZ8 = 42;
uint16_t NZ16 = 42;
uint32_t NZ32 = 42;
uint64_t NZ64 = 42;
EXPECT_EQ(1u, countTrailingZeros(NZ8));
EXPECT_EQ(1u, countTrailingZeros(NZ16));
EXPECT_EQ(1u, countTrailingZeros(NZ32));
EXPECT_EQ(1u, countTrailingZeros(NZ64));
}
TEST(MathExtras, countLeadingZeros) {
uint8_t Z8 = 0;
uint16_t Z16 = 0;
uint32_t Z32 = 0;
uint64_t Z64 = 0;
EXPECT_EQ(8u, countLeadingZeros(Z8));
EXPECT_EQ(16u, countLeadingZeros(Z16));
EXPECT_EQ(32u, countLeadingZeros(Z32));
EXPECT_EQ(64u, countLeadingZeros(Z64));
uint8_t NZ8 = 42;
uint16_t NZ16 = 42;
uint32_t NZ32 = 42;
uint64_t NZ64 = 42;
EXPECT_EQ(2u, countLeadingZeros(NZ8));
EXPECT_EQ(10u, countLeadingZeros(NZ16));
EXPECT_EQ(26u, countLeadingZeros(NZ32));
EXPECT_EQ(58u, countLeadingZeros(NZ64));
EXPECT_EQ(8u, countLeadingZeros(0x00F000FFu));
EXPECT_EQ(8u, countLeadingZeros(0x00F12345u));
for (unsigned i = 0; i <= 30; ++i) {
EXPECT_EQ(31 - i, countLeadingZeros(1u << i));
}
EXPECT_EQ(8u, countLeadingZeros(0x00F1234500F12345ULL));
EXPECT_EQ(1u, countLeadingZeros(1ULL << 62));
for (unsigned i = 0; i <= 62; ++i) {
EXPECT_EQ(63 - i, countLeadingZeros(1ULL << i));
}
}
TEST(MathExtras, onesMask) {
EXPECT_EQ(0U, maskLeadingOnes<uint8_t>(0));
EXPECT_EQ(0U, maskTrailingOnes<uint8_t>(0));
EXPECT_EQ(0U, maskLeadingOnes<uint16_t>(0));
EXPECT_EQ(0U, maskTrailingOnes<uint16_t>(0));
EXPECT_EQ(0U, maskLeadingOnes<uint32_t>(0));
EXPECT_EQ(0U, maskTrailingOnes<uint32_t>(0));
EXPECT_EQ(0U, maskLeadingOnes<uint64_t>(0));
EXPECT_EQ(0U, maskTrailingOnes<uint64_t>(0));
EXPECT_EQ(0x00000003U, maskTrailingOnes<uint32_t>(2U));
EXPECT_EQ(0xC0000000U, maskLeadingOnes<uint32_t>(2U));
EXPECT_EQ(0x000007FFU, maskTrailingOnes<uint32_t>(11U));
EXPECT_EQ(0xFFE00000U, maskLeadingOnes<uint32_t>(11U));
EXPECT_EQ(0xFFFFFFFFU, maskTrailingOnes<uint32_t>(32U));
EXPECT_EQ(0xFFFFFFFFU, maskLeadingOnes<uint32_t>(32U));
EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, maskTrailingOnes<uint64_t>(64U));
EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, maskLeadingOnes<uint64_t>(64U));
EXPECT_EQ(0x0000FFFFFFFFFFFFULL, maskTrailingOnes<uint64_t>(48U));
EXPECT_EQ(0xFFFFFFFFFFFF0000ULL, maskLeadingOnes<uint64_t>(48U));
}
TEST(MathExtras, findFirstSet) {
uint8_t Z8 = 0;
uint16_t Z16 = 0;
uint32_t Z32 = 0;
uint64_t Z64 = 0;
EXPECT_EQ(0xFFULL, findFirstSet(Z8));
EXPECT_EQ(0xFFFFULL, findFirstSet(Z16));
EXPECT_EQ(0xFFFFFFFFULL, findFirstSet(Z32));
EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findFirstSet(Z64));
uint8_t NZ8 = 42;
uint16_t NZ16 = 42;
uint32_t NZ32 = 42;
uint64_t NZ64 = 42;
EXPECT_EQ(1u, findFirstSet(NZ8));
EXPECT_EQ(1u, findFirstSet(NZ16));
EXPECT_EQ(1u, findFirstSet(NZ32));
EXPECT_EQ(1u, findFirstSet(NZ64));
}
TEST(MathExtras, findLastSet) {
uint8_t Z8 = 0;
uint16_t Z16 = 0;
uint32_t Z32 = 0;
uint64_t Z64 = 0;
EXPECT_EQ(0xFFULL, findLastSet(Z8));
EXPECT_EQ(0xFFFFULL, findLastSet(Z16));
EXPECT_EQ(0xFFFFFFFFULL, findLastSet(Z32));
EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findLastSet(Z64));
uint8_t NZ8 = 42;
uint16_t NZ16 = 42;
uint32_t NZ32 = 42;
uint64_t NZ64 = 42;
EXPECT_EQ(5u, findLastSet(NZ8));
EXPECT_EQ(5u, findLastSet(NZ16));
EXPECT_EQ(5u, findLastSet(NZ32));
EXPECT_EQ(5u, findLastSet(NZ64));
}
TEST(MathExtras, isIntN) {
EXPECT_TRUE(isIntN(16, 32767));
EXPECT_FALSE(isIntN(16, 32768));
}
TEST(MathExtras, isUIntN) {
EXPECT_TRUE(isUIntN(16, 65535));
EXPECT_FALSE(isUIntN(16, 65536));
EXPECT_TRUE(isUIntN(1, 0));
EXPECT_TRUE(isUIntN(6, 63));
}
TEST(MathExtras, maxIntN) {
EXPECT_EQ(32767, maxIntN(16));
EXPECT_EQ(2147483647, maxIntN(32));
EXPECT_EQ(std::numeric_limits<int32_t>::max(), maxIntN(32));
EXPECT_EQ(std::numeric_limits<int64_t>::max(), maxIntN(64));
}
TEST(MathExtras, minIntN) {
EXPECT_EQ(-32768LL, minIntN(16));
EXPECT_EQ(-64LL, minIntN(7));
EXPECT_EQ(std::numeric_limits<int32_t>::min(), minIntN(32));
EXPECT_EQ(std::numeric_limits<int64_t>::min(), minIntN(64));
}
TEST(MathExtras, maxUIntN) {
EXPECT_EQ(0xffffULL, maxUIntN(16));
EXPECT_EQ(0xffffffffULL, maxUIntN(32));
EXPECT_EQ(0xffffffffffffffffULL, maxUIntN(64));
EXPECT_EQ(1ULL, maxUIntN(1));
EXPECT_EQ(0x0fULL, maxUIntN(4));
}
TEST(MathExtras, reverseBits) {
uint8_t NZ8 = 42;
uint16_t NZ16 = 42;
uint32_t NZ32 = 42;
uint64_t NZ64 = 42;
EXPECT_EQ(0x54ULL, reverseBits(NZ8));
EXPECT_EQ(0x5400ULL, reverseBits(NZ16));
EXPECT_EQ(0x54000000ULL, reverseBits(NZ32));
EXPECT_EQ(0x5400000000000000ULL, reverseBits(NZ64));
}
TEST(MathExtras, isPowerOf2_32) {
EXPECT_FALSE(isPowerOf2_32(0));
EXPECT_TRUE(isPowerOf2_32(1 << 6));
EXPECT_TRUE(isPowerOf2_32(1 << 12));
EXPECT_FALSE(isPowerOf2_32((1 << 19) + 3));
EXPECT_FALSE(isPowerOf2_32(0xABCDEF0));
}
TEST(MathExtras, isPowerOf2_64) {
EXPECT_FALSE(isPowerOf2_64(0));
EXPECT_TRUE(isPowerOf2_64(1LL << 46));
EXPECT_TRUE(isPowerOf2_64(1LL << 12));
EXPECT_FALSE(isPowerOf2_64((1LL << 53) + 3));
EXPECT_FALSE(isPowerOf2_64(0xABCDEF0ABCDEF0LL));
}
TEST(MathExtras, PowerOf2Ceil) {
EXPECT_EQ(0U, PowerOf2Ceil(0U));
EXPECT_EQ(8U, PowerOf2Ceil(8U));
EXPECT_EQ(8U, PowerOf2Ceil(7U));
}
TEST(MathExtras, PowerOf2Floor) {
EXPECT_EQ(0U, PowerOf2Floor(0U));
EXPECT_EQ(8U, PowerOf2Floor(8U));
EXPECT_EQ(4U, PowerOf2Floor(7U));
}
TEST(MathExtras, CTLog2) {
EXPECT_EQ(CTLog2<1ULL << 0>(), 0U);
EXPECT_EQ(CTLog2<1ULL << 1>(), 1U);
EXPECT_EQ(CTLog2<1ULL << 2>(), 2U);
EXPECT_EQ(CTLog2<1ULL << 3>(), 3U);
EXPECT_EQ(CTLog2<1ULL << 4>(), 4U);
EXPECT_EQ(CTLog2<1ULL << 5>(), 5U);
EXPECT_EQ(CTLog2<1ULL << 6>(), 6U);
EXPECT_EQ(CTLog2<1ULL << 7>(), 7U);
EXPECT_EQ(CTLog2<1ULL << 8>(), 8U);
EXPECT_EQ(CTLog2<1ULL << 9>(), 9U);
EXPECT_EQ(CTLog2<1ULL << 10>(), 10U);
EXPECT_EQ(CTLog2<1ULL << 11>(), 11U);
EXPECT_EQ(CTLog2<1ULL << 12>(), 12U);
EXPECT_EQ(CTLog2<1ULL << 13>(), 13U);
EXPECT_EQ(CTLog2<1ULL << 14>(), 14U);
EXPECT_EQ(CTLog2<1ULL << 15>(), 15U);
}
TEST(MathExtras, countLeadingOnes) {
for (int i = 30; i >= 0; --i) {
// Start with all ones and unset some bit.
EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i)));
}
for (int i = 62; i >= 0; --i) {
// Start with all ones and unset some bit.
EXPECT_EQ(63u - i, countLeadingOnes(0xFFFFFFFFFFFFFFFFULL ^ (1LL << i)));
}
for (int i = 30; i >= 0; --i) {
// Start with all ones and unset some bit.
EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i)));
}
}
TEST(MathExtras, FloatBits) {
static const float kValue = 5632.34f;
EXPECT_FLOAT_EQ(kValue, BitsToFloat(FloatToBits(kValue)));
}
TEST(MathExtras, DoubleBits) {
static const double kValue = 87987234.983498;
EXPECT_DOUBLE_EQ(kValue, BitsToDouble(DoubleToBits(kValue)));
}
TEST(MathExtras, MinAlign) {
EXPECT_EQ(1u, MinAlign(2, 3));
EXPECT_EQ(2u, MinAlign(2, 4));
EXPECT_EQ(1u, MinAlign(17, 64));
EXPECT_EQ(256u, MinAlign(256, 512));
}
TEST(MathExtras, NextPowerOf2) {
EXPECT_EQ(4u, NextPowerOf2(3));
EXPECT_EQ(16u, NextPowerOf2(15));
EXPECT_EQ(256u, NextPowerOf2(128));
}
TEST(MathExtras, alignTo) {
EXPECT_EQ(8u, alignTo(5, 8));
EXPECT_EQ(24u, alignTo(17, 8));
EXPECT_EQ(0u, alignTo(~0LL, 8));
EXPECT_EQ(7u, alignTo(5, 8, 7));
EXPECT_EQ(17u, alignTo(17, 8, 1));
EXPECT_EQ(3u, alignTo(~0LL, 8, 3));
EXPECT_EQ(552u, alignTo(321, 255, 42));
}
template<typename T>
void SaturatingAddTestHelper()
{
const T Max = std::numeric_limits<T>::max();
bool ResultOverflowed;
EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2)));
EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingAdd(Max, T(1)));
EXPECT_EQ(Max, SaturatingAdd(Max, T(1), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 1)));
EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 1), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingAdd(T(1), Max));
EXPECT_EQ(Max, SaturatingAdd(T(1), Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingAdd(Max, Max));
EXPECT_EQ(Max, SaturatingAdd(Max, Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
}
TEST(MathExtras, SaturatingAdd) {
SaturatingAddTestHelper<uint8_t>();
SaturatingAddTestHelper<uint16_t>();
SaturatingAddTestHelper<uint32_t>();
SaturatingAddTestHelper<uint64_t>();
}
template<typename T>
void SaturatingMultiplyTestHelper()
{
const T Max = std::numeric_limits<T>::max();
bool ResultOverflowed;
// Test basic multiplication.
EXPECT_EQ(T(6), SaturatingMultiply(T(2), T(3)));
EXPECT_EQ(T(6), SaturatingMultiply(T(2), T(3), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(6), SaturatingMultiply(T(3), T(2)));
EXPECT_EQ(T(6), SaturatingMultiply(T(3), T(2), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
// Test multiplication by zero.
EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(0)));
EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(0), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(0), SaturatingMultiply(T(1), T(0)));
EXPECT_EQ(T(0), SaturatingMultiply(T(1), T(0), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(1)));
EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(1), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(0), SaturatingMultiply(Max, T(0)));
EXPECT_EQ(T(0), SaturatingMultiply(Max, T(0), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(0), SaturatingMultiply(T(0), Max));
EXPECT_EQ(T(0), SaturatingMultiply(T(0), Max, &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
// Test multiplication by maximum value.
EXPECT_EQ(Max, SaturatingMultiply(Max, T(2)));
EXPECT_EQ(Max, SaturatingMultiply(Max, T(2), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingMultiply(T(2), Max));
EXPECT_EQ(Max, SaturatingMultiply(T(2), Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingMultiply(Max, Max));
EXPECT_EQ(Max, SaturatingMultiply(Max, Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
// Test interesting boundary conditions for algorithm -
// ((1 << A) - 1) * ((1 << B) + K) for K in [-1, 0, 1]
// and A + B == std::numeric_limits<T>::digits.
// We expect overflow iff A > B and K = 1.
const int Digits = std::numeric_limits<T>::digits;
for (int A = 1, B = Digits - 1; B >= 1; ++A, --B) {
for (int K = -1; K <= 1; ++K) {
T X = (T(1) << A) - T(1);
T Y = (T(1) << B) + K;
bool OverflowExpected = A > B && K == 1;
if(OverflowExpected) {
EXPECT_EQ(Max, SaturatingMultiply(X, Y));
EXPECT_EQ(Max, SaturatingMultiply(X, Y, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
} else {
EXPECT_EQ(X * Y, SaturatingMultiply(X, Y));
EXPECT_EQ(X * Y, SaturatingMultiply(X, Y, &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
}
}
}
}
TEST(MathExtras, SaturatingMultiply) {
SaturatingMultiplyTestHelper<uint8_t>();
SaturatingMultiplyTestHelper<uint16_t>();
SaturatingMultiplyTestHelper<uint32_t>();
SaturatingMultiplyTestHelper<uint64_t>();
}
template<typename T>
void SaturatingMultiplyAddTestHelper()
{
const T Max = std::numeric_limits<T>::max();
bool ResultOverflowed;
// Test basic multiply-add.
EXPECT_EQ(T(16), SaturatingMultiplyAdd(T(2), T(3), T(10)));
EXPECT_EQ(T(16), SaturatingMultiplyAdd(T(2), T(3), T(10), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
// Test multiply overflows, add doesn't overflow
EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, T(0), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
// Test multiply doesn't overflow, add overflows
EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), T(1), Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
// Test multiply-add with Max as operand
EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), T(1), Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), Max, T(1), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, T(1), &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, Max, &ResultOverflowed));
EXPECT_TRUE(ResultOverflowed);
// Test multiply-add with 0 as operand
EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(1), T(1), T(0), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(1), T(0), T(1), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(0), T(0), T(1), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
EXPECT_EQ(T(0), SaturatingMultiplyAdd(T(0), T(0), T(0), &ResultOverflowed));
EXPECT_FALSE(ResultOverflowed);
}
TEST(MathExtras, SaturatingMultiplyAdd) {
SaturatingMultiplyAddTestHelper<uint8_t>();
SaturatingMultiplyAddTestHelper<uint16_t>();
SaturatingMultiplyAddTestHelper<uint32_t>();
SaturatingMultiplyAddTestHelper<uint64_t>();
}
TEST(MathExtras, IsShiftedUInt) {
EXPECT_TRUE((isShiftedUInt<1, 0>(0)));
EXPECT_TRUE((isShiftedUInt<1, 0>(1)));
EXPECT_FALSE((isShiftedUInt<1, 0>(2)));
EXPECT_FALSE((isShiftedUInt<1, 0>(3)));
EXPECT_FALSE((isShiftedUInt<1, 0>(0x8000000000000000)));
EXPECT_TRUE((isShiftedUInt<1, 63>(0x8000000000000000)));
EXPECT_TRUE((isShiftedUInt<2, 62>(0xC000000000000000)));
EXPECT_FALSE((isShiftedUInt<2, 62>(0xE000000000000000)));
// 0x201 is ten bits long and has a 1 in the MSB and LSB.
EXPECT_TRUE((isShiftedUInt<10, 5>(uint64_t(0x201) << 5)));
EXPECT_FALSE((isShiftedUInt<10, 5>(uint64_t(0x201) << 4)));
EXPECT_FALSE((isShiftedUInt<10, 5>(uint64_t(0x201) << 6)));
}
TEST(MathExtras, IsShiftedInt) {
EXPECT_TRUE((isShiftedInt<1, 0>(0)));
EXPECT_TRUE((isShiftedInt<1, 0>(-1)));
EXPECT_FALSE((isShiftedInt<1, 0>(2)));
EXPECT_FALSE((isShiftedInt<1, 0>(3)));
EXPECT_FALSE((isShiftedInt<1, 0>(0x8000000000000000)));
EXPECT_TRUE((isShiftedInt<1, 63>(0x8000000000000000)));
EXPECT_TRUE((isShiftedInt<2, 62>(0xC000000000000000)));
EXPECT_FALSE((isShiftedInt<2, 62>(0xE000000000000000)));
// 0x201 is ten bits long and has a 1 in the MSB and LSB.
EXPECT_TRUE((isShiftedInt<11, 5>(int64_t(0x201) << 5)));
EXPECT_FALSE((isShiftedInt<11, 5>(int64_t(0x201) << 3)));
EXPECT_FALSE((isShiftedInt<11, 5>(int64_t(0x201) << 6)));
EXPECT_TRUE((isShiftedInt<11, 5>(-(int64_t(0x201) << 5))));
EXPECT_FALSE((isShiftedInt<11, 5>(-(int64_t(0x201) << 3))));
EXPECT_FALSE((isShiftedInt<11, 5>(-(int64_t(0x201) << 6))));
EXPECT_TRUE((isShiftedInt<6, 10>(-(int64_t(1) << 15))));
EXPECT_FALSE((isShiftedInt<6, 10>(int64_t(1) << 15)));
}
template <typename T>
class OverflowTest : public ::testing::Test { };
using OverflowTestTypes = ::testing::Types<signed char, short, int, long,
long long>;
TYPED_TEST_SUITE(OverflowTest, OverflowTestTypes, );
TYPED_TEST(OverflowTest, AddNoOverflow) {
TypeParam Result;
EXPECT_FALSE(AddOverflow<TypeParam>(1, 2, Result));
EXPECT_EQ(Result, TypeParam(3));
}
TYPED_TEST(OverflowTest, AddOverflowToNegative) {
TypeParam Result;
auto MaxValue = std::numeric_limits<TypeParam>::max();
EXPECT_TRUE(AddOverflow<TypeParam>(MaxValue, MaxValue, Result));
EXPECT_EQ(Result, TypeParam(-2));
}
TYPED_TEST(OverflowTest, AddOverflowToMin) {
TypeParam Result;
auto MaxValue = std::numeric_limits<TypeParam>::max();
EXPECT_TRUE(AddOverflow<TypeParam>(MaxValue, TypeParam(1), Result));
EXPECT_EQ(Result, std::numeric_limits<TypeParam>::min());
}
TYPED_TEST(OverflowTest, AddOverflowToZero) {
TypeParam Result;
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_TRUE(AddOverflow<TypeParam>(MinValue, MinValue, Result));
EXPECT_EQ(Result, TypeParam(0));
}
TYPED_TEST(OverflowTest, AddOverflowToMax) {
TypeParam Result;
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_TRUE(AddOverflow<TypeParam>(MinValue, TypeParam(-1), Result));
EXPECT_EQ(Result, std::numeric_limits<TypeParam>::max());
}
TYPED_TEST(OverflowTest, SubNoOverflow) {
TypeParam Result;
EXPECT_FALSE(SubOverflow<TypeParam>(1, 2, Result));
EXPECT_EQ(Result, TypeParam(-1));
}
TYPED_TEST(OverflowTest, SubOverflowToMax) {
TypeParam Result;
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_TRUE(SubOverflow<TypeParam>(0, MinValue, Result));
EXPECT_EQ(Result, MinValue);
}
TYPED_TEST(OverflowTest, SubOverflowToMin) {
TypeParam Result;
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_TRUE(SubOverflow<TypeParam>(0, MinValue, Result));
EXPECT_EQ(Result, MinValue);
}
TYPED_TEST(OverflowTest, SubOverflowToNegative) {
TypeParam Result;
auto MaxValue = std::numeric_limits<TypeParam>::max();
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_TRUE(SubOverflow<TypeParam>(MaxValue, MinValue, Result));
EXPECT_EQ(Result, TypeParam(-1));
}
TYPED_TEST(OverflowTest, SubOverflowToPositive) {
TypeParam Result;
auto MaxValue = std::numeric_limits<TypeParam>::max();
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_TRUE(SubOverflow<TypeParam>(MinValue, MaxValue, Result));
EXPECT_EQ(Result, TypeParam(1));
}
TYPED_TEST(OverflowTest, MulNoOverflow) {
TypeParam Result;
EXPECT_FALSE(MulOverflow<TypeParam>(1, 2, Result));
EXPECT_EQ(Result, 2);
EXPECT_FALSE(MulOverflow<TypeParam>(-1, 3, Result));
EXPECT_EQ(Result, -3);
EXPECT_FALSE(MulOverflow<TypeParam>(4, -2, Result));
EXPECT_EQ(Result, -8);
EXPECT_FALSE(MulOverflow<TypeParam>(-6, -5, Result));
EXPECT_EQ(Result, 30);
}
TYPED_TEST(OverflowTest, MulNoOverflowToMax) {
TypeParam Result;
auto MaxValue = std::numeric_limits<TypeParam>::max();
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_FALSE(MulOverflow<TypeParam>(MinValue + 1, -1, Result));
EXPECT_EQ(Result, MaxValue);
}
TYPED_TEST(OverflowTest, MulOverflowToMin) {
TypeParam Result;
auto MinValue = std::numeric_limits<TypeParam>::min();
EXPECT_TRUE(MulOverflow<TypeParam>(MinValue, -1, Result));
EXPECT_EQ(Result, MinValue);
}
TYPED_TEST(OverflowTest, MulOverflowMax) {
TypeParam Result;
auto MinValue = std::numeric_limits<TypeParam>::min();
auto MaxValue = std::numeric_limits<TypeParam>::max();
EXPECT_TRUE(MulOverflow<TypeParam>(MinValue, MinValue, Result));
EXPECT_EQ(Result, 0);
EXPECT_TRUE(MulOverflow<TypeParam>(MaxValue, MaxValue, Result));
EXPECT_EQ(Result, 1);
}
TYPED_TEST(OverflowTest, MulResultZero) {
TypeParam Result;
EXPECT_FALSE(MulOverflow<TypeParam>(4, 0, Result));
EXPECT_EQ(Result, TypeParam(0));
EXPECT_FALSE(MulOverflow<TypeParam>(-5, 0, Result));
EXPECT_EQ(Result, TypeParam(0));
EXPECT_FALSE(MulOverflow<TypeParam>(0, 5, Result));
EXPECT_EQ(Result, TypeParam(0));
EXPECT_FALSE(MulOverflow<TypeParam>(0, -5, Result));
EXPECT_EQ(Result, TypeParam(0));
}
} // namespace

View File

@@ -0,0 +1,109 @@
//===- llvm/unittest/ADT/PointerIntPairTest.cpp - Unit tests --------------===//
//
// 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/PointerIntPair.h"
#include "gtest/gtest.h"
#include <limits>
using namespace wpi;
namespace {
TEST(PointerIntPairTest, GetSet) {
struct S {
int i;
};
S s;
PointerIntPair<S *, 2> Pair(&s, 1U);
EXPECT_EQ(&s, Pair.getPointer());
EXPECT_EQ(1U, Pair.getInt());
Pair.setInt(2);
EXPECT_EQ(&s, Pair.getPointer());
EXPECT_EQ(2U, Pair.getInt());
Pair.setPointer(nullptr);
EXPECT_EQ(nullptr, Pair.getPointer());
EXPECT_EQ(2U, Pair.getInt());
Pair.setPointerAndInt(&s, 3U);
EXPECT_EQ(&s, Pair.getPointer());
EXPECT_EQ(3U, Pair.getInt());
// Make sure that we can perform all of our operations on enum classes.
//
// The concern is that enum classes are only explicitly convertible to
// integers. This means that if we assume in PointerIntPair this, a
// compilation error will result. This group of tests exercises the enum class
// code to make sure that we do not run into such issues in the future.
enum class E : unsigned {
Case1,
Case2,
Case3,
};
PointerIntPair<S *, 2, E> Pair2(&s, E::Case1);
EXPECT_EQ(&s, Pair2.getPointer());
EXPECT_EQ(E::Case1, Pair2.getInt());
Pair2.setInt(E::Case2);
EXPECT_EQ(&s, Pair2.getPointer());
EXPECT_EQ(E::Case2, Pair2.getInt());
Pair2.setPointer(nullptr);
EXPECT_EQ(nullptr, Pair2.getPointer());
EXPECT_EQ(E::Case2, Pair2.getInt());
Pair2.setPointerAndInt(&s, E::Case3);
EXPECT_EQ(&s, Pair2.getPointer());
EXPECT_EQ(E::Case3, Pair2.getInt());
static_assert(std::is_trivially_copyable<PointerIntPair<S *, 2, E>>::value,
"trivially copyable");
}
TEST(PointerIntPairTest, DefaultInitialize) {
PointerIntPair<float *, 2> Pair;
EXPECT_EQ(nullptr, Pair.getPointer());
EXPECT_EQ(0U, Pair.getInt());
}
// In real code this would be a word-sized integer limited to 31 bits.
struct Fixnum31 {
uintptr_t Value;
};
struct FixnumPointerTraits {
static inline void *getAsVoidPointer(Fixnum31 Num) {
return reinterpret_cast<void *>(Num.Value << NumLowBitsAvailable);
}
static inline Fixnum31 getFromVoidPointer(void *P) {
// In real code this would assert that the value is in range.
return {reinterpret_cast<uintptr_t>(P) >> NumLowBitsAvailable};
}
static constexpr int NumLowBitsAvailable =
std::numeric_limits<uintptr_t>::digits - 31;
};
TEST(PointerIntPairTest, ManyUnusedBits) {
PointerIntPair<Fixnum31, 1, bool, FixnumPointerTraits> pair;
EXPECT_EQ((uintptr_t)0, pair.getPointer().Value);
EXPECT_FALSE(pair.getInt());
pair.setPointerAndInt({ 0x7FFFFFFF }, true );
EXPECT_EQ((uintptr_t)0x7FFFFFFF, pair.getPointer().Value);
EXPECT_TRUE(pair.getInt());
EXPECT_EQ(FixnumPointerTraits::NumLowBitsAvailable - 1,
(int)PointerLikeTypeTraits<decltype(pair)>::NumLowBitsAvailable);
static_assert(
std::is_trivially_copyable<
PointerIntPair<Fixnum31, 1, bool, FixnumPointerTraits>>::value,
"trivially copyable");
}
} // end anonymous namespace

View File

@@ -0,0 +1,159 @@
//===- llvm/unittest/ADT/PointerUnionTest.cpp - Optional unit tests -------===//
//
// 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/PointerUnion.h"
#include "gtest/gtest.h"
using namespace wpi;
namespace {
typedef PointerUnion<int *, float *> PU;
typedef PointerUnion<int *, float *, long long *> PU3;
typedef PointerUnion<int *, float *, long long *, double *> PU4;
struct PointerUnionTest : public testing::Test {
float f;
int i;
double d;
long long l;
PU a, b, c, n;
PU3 i3, f3, l3;
PU4 i4, f4, l4, d4;
PU4 i4null, f4null, l4null, d4null;
PointerUnionTest()
: f(3.14f), i(42), d(3.14), l(42), a(&f), b(&i), c(&i), n(), i3(&i),
f3(&f), l3(&l), i4(&i), f4(&f), l4(&l), d4(&d), i4null((int *)nullptr),
f4null((float *)nullptr), l4null((long long *)nullptr),
d4null((double *)nullptr) {}
};
TEST_F(PointerUnionTest, Comparison) {
EXPECT_TRUE(a == a);
EXPECT_FALSE(a != a);
EXPECT_TRUE(a != b);
EXPECT_FALSE(a == b);
EXPECT_TRUE(b == c);
EXPECT_FALSE(b != c);
EXPECT_TRUE(b != n);
EXPECT_FALSE(b == n);
EXPECT_TRUE(i3 == i3);
EXPECT_FALSE(i3 != i3);
EXPECT_TRUE(i3 != f3);
EXPECT_TRUE(f3 != l3);
EXPECT_TRUE(i4 == i4);
EXPECT_FALSE(i4 != i4);
EXPECT_TRUE(i4 != f4);
EXPECT_TRUE(i4 != l4);
EXPECT_TRUE(f4 != l4);
EXPECT_TRUE(l4 != d4);
EXPECT_TRUE(i4null != f4null);
EXPECT_TRUE(i4null != l4null);
EXPECT_TRUE(i4null != d4null);
}
TEST_F(PointerUnionTest, Null) {
EXPECT_FALSE(a.isNull());
EXPECT_FALSE(b.isNull());
EXPECT_TRUE(n.isNull());
EXPECT_FALSE(!a);
EXPECT_FALSE(!b);
EXPECT_TRUE(!n);
// workaround an issue with EXPECT macros and explicit bool
EXPECT_TRUE((bool)a);
EXPECT_TRUE((bool)b);
EXPECT_FALSE(n);
EXPECT_NE(n, b);
EXPECT_EQ(b, c);
b = nullptr;
EXPECT_EQ(n, b);
EXPECT_NE(b, c);
EXPECT_FALSE(i3.isNull());
EXPECT_FALSE(f3.isNull());
EXPECT_FALSE(l3.isNull());
EXPECT_FALSE(i4.isNull());
EXPECT_FALSE(f4.isNull());
EXPECT_FALSE(l4.isNull());
EXPECT_FALSE(d4.isNull());
EXPECT_TRUE(i4null.isNull());
EXPECT_TRUE(f4null.isNull());
EXPECT_TRUE(l4null.isNull());
EXPECT_TRUE(d4null.isNull());
}
TEST_F(PointerUnionTest, Is) {
EXPECT_FALSE(a.is<int *>());
EXPECT_TRUE(a.is<float *>());
EXPECT_TRUE(b.is<int *>());
EXPECT_FALSE(b.is<float *>());
EXPECT_TRUE(n.is<int *>());
EXPECT_FALSE(n.is<float *>());
EXPECT_TRUE(i3.is<int *>());
EXPECT_TRUE(f3.is<float *>());
EXPECT_TRUE(l3.is<long long *>());
EXPECT_TRUE(i4.is<int *>());
EXPECT_TRUE(f4.is<float *>());
EXPECT_TRUE(l4.is<long long *>());
EXPECT_TRUE(d4.is<double *>());
EXPECT_TRUE(i4null.is<int *>());
EXPECT_TRUE(f4null.is<float *>());
EXPECT_TRUE(l4null.is<long long *>());
EXPECT_TRUE(d4null.is<double *>());
}
TEST_F(PointerUnionTest, Get) {
EXPECT_EQ(a.get<float *>(), &f);
EXPECT_EQ(b.get<int *>(), &i);
EXPECT_EQ(n.get<int *>(), (int *)nullptr);
}
template<int I> struct alignas(8) Aligned {};
typedef PointerUnion<Aligned<0> *, Aligned<1> *, Aligned<2> *, Aligned<3> *,
Aligned<4> *, Aligned<5> *, Aligned<6> *, Aligned<7> *>
PU8;
TEST_F(PointerUnionTest, ManyElements) {
Aligned<0> a0;
Aligned<7> a7;
PU8 a = &a0;
EXPECT_TRUE(a.is<Aligned<0>*>());
EXPECT_FALSE(a.is<Aligned<1>*>());
EXPECT_FALSE(a.is<Aligned<2>*>());
EXPECT_FALSE(a.is<Aligned<3>*>());
EXPECT_FALSE(a.is<Aligned<4>*>());
EXPECT_FALSE(a.is<Aligned<5>*>());
EXPECT_FALSE(a.is<Aligned<6>*>());
EXPECT_FALSE(a.is<Aligned<7>*>());
EXPECT_EQ(a.dyn_cast<Aligned<0>*>(), &a0);
EXPECT_EQ(*a.getAddrOfPtr1(), &a0);
a = &a7;
EXPECT_FALSE(a.is<Aligned<0>*>());
EXPECT_FALSE(a.is<Aligned<1>*>());
EXPECT_FALSE(a.is<Aligned<2>*>());
EXPECT_FALSE(a.is<Aligned<3>*>());
EXPECT_FALSE(a.is<Aligned<4>*>());
EXPECT_FALSE(a.is<Aligned<5>*>());
EXPECT_FALSE(a.is<Aligned<6>*>());
EXPECT_TRUE(a.is<Aligned<7>*>());
EXPECT_EQ(a.dyn_cast<Aligned<7>*>(), &a7);
EXPECT_TRUE(a == PU8(&a7));
EXPECT_TRUE(a != PU8(&a0));
}
TEST_F(PointerUnionTest, GetAddrOfPtr1) {
EXPECT_TRUE((void *)b.getAddrOfPtr1() == (void *)&b);
EXPECT_TRUE((void *)n.getAddrOfPtr1() == (void *)&n);
}
} // end anonymous namespace

View File

@@ -0,0 +1,78 @@
//===- STLForwardCompatTest.cpp - Unit tests for STLForwardCompat ---------===//
//
// 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/STLForwardCompat.h"
#include "gtest/gtest.h"
namespace {
TEST(STLForwardCompatTest, NegationTest) {
EXPECT_TRUE((wpi::negation<std::false_type>::value));
EXPECT_FALSE((wpi::negation<std::true_type>::value));
}
struct incomplete_type;
TEST(STLForwardCompatTest, ConjunctionTest) {
EXPECT_TRUE((wpi::conjunction<>::value));
EXPECT_FALSE((wpi::conjunction<std::false_type>::value));
EXPECT_TRUE((wpi::conjunction<std::true_type>::value));
EXPECT_FALSE((wpi::conjunction<std::false_type, incomplete_type>::value));
EXPECT_FALSE((wpi::conjunction<std::false_type, std::true_type>::value));
EXPECT_FALSE((wpi::conjunction<std::true_type, std::false_type>::value));
EXPECT_TRUE((wpi::conjunction<std::true_type, std::true_type>::value));
EXPECT_TRUE((wpi::conjunction<std::true_type, std::true_type,
std::true_type>::value));
}
TEST(STLForwardCompatTest, DisjunctionTest) {
EXPECT_FALSE((wpi::disjunction<>::value));
EXPECT_FALSE((wpi::disjunction<std::false_type>::value));
EXPECT_TRUE((wpi::disjunction<std::true_type>::value));
EXPECT_TRUE((wpi::disjunction<std::true_type, incomplete_type>::value));
EXPECT_TRUE((wpi::disjunction<std::false_type, std::true_type>::value));
EXPECT_TRUE((wpi::disjunction<std::true_type, std::false_type>::value));
EXPECT_TRUE((wpi::disjunction<std::true_type, std::true_type>::value));
EXPECT_TRUE((wpi::disjunction<std::true_type, std::true_type,
std::true_type>::value));
}
template <typename T>
class STLForwardCompatRemoveCVRefTest : public ::testing::Test {};
using STLForwardCompatRemoveCVRefTestTypes = ::testing::Types<
// clang-format off
std::pair<int, int>,
std::pair<int &, int>,
std::pair<const int, int>,
std::pair<volatile int, int>,
std::pair<const volatile int &, int>,
std::pair<int *, int *>,
std::pair<int *const, int *>,
std::pair<const int *, const int *>,
std::pair<int *&, int *>
// clang-format on
>;
TYPED_TEST_SUITE(STLForwardCompatRemoveCVRefTest,
STLForwardCompatRemoveCVRefTestTypes, );
TYPED_TEST(STLForwardCompatRemoveCVRefTest, RemoveCVRef) {
using From = typename TypeParam::first_type;
using To = typename TypeParam::second_type;
EXPECT_TRUE(
(std::is_same<typename wpi::remove_cvref<From>::type, To>::value));
}
TYPED_TEST(STLForwardCompatRemoveCVRefTest, RemoveCVRefT) {
using From = typename TypeParam::first_type;
EXPECT_TRUE((std::is_same<typename wpi::remove_cvref<From>::type,
wpi::remove_cvref_t<From>>::value));
}
} // namespace

Some files were not shown because too many files have changed in this diff Show More