mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpiutil] Vendor llvm and update to 13.0.0 (#4224)
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
188
upstream_utils/llvm_patches/0005-Threading-updates.patch
Normal file
188
upstream_utils/llvm_patches/0005-Threading-updates.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
354
upstream_utils/llvm_patches/0007-ifdef-guard-safety.patch
Normal file
354
upstream_utils/llvm_patches/0007-ifdef-guard-safety.patch
Normal 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
|
||||
|
||||
81
upstream_utils/llvm_patches/0008-Explicitly-use-std.patch
Normal file
81
upstream_utils/llvm_patches/0008-Explicitly-use-std.patch
Normal 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
|
||||
|
||||
234
upstream_utils/llvm_patches/0009-Remove-format_provider.patch
Normal file
234
upstream_utils/llvm_patches/0009-Remove-format_provider.patch
Normal 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
|
||||
|
||||
266
upstream_utils/llvm_patches/0010-Remove-reverse-iterator.patch
Normal file
266
upstream_utils/llvm_patches/0010-Remove-reverse-iterator.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
91
upstream_utils/llvm_patches/0012-Remove-EpochTracker.patch
Normal file
91
upstream_utils/llvm_patches/0012-Remove-EpochTracker.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
743
upstream_utils/llvm_patches/0014-Remove-unused-functions.patch
Normal file
743
upstream_utils/llvm_patches/0014-Remove-unused-functions.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
43
upstream_utils/llvm_patches/0020-Add-lerp-and-sgn.patch
Normal file
43
upstream_utils/llvm_patches/0020-Add-lerp-and-sgn.patch
Normal 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
|
||||
|
||||
172
upstream_utils/llvm_patches/0021-Fixup-includes.patch
Normal file
172
upstream_utils/llvm_patches/0021-Fixup-includes.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
223
upstream_utils/llvm_patches/0023-Windows-Support.patch
Normal file
223
upstream_utils/llvm_patches/0023-Windows-Support.patch
Normal 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
|
||||
|
||||
58
upstream_utils/llvm_patches/0024-Prefer-fmtlib.patch
Normal file
58
upstream_utils/llvm_patches/0024-Prefer-fmtlib.patch
Normal 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
|
||||
|
||||
37
upstream_utils/llvm_patches/0025-prefer-wpi-s-fs.h.patch
Normal file
37
upstream_utils/llvm_patches/0025-prefer-wpi-s-fs.h.patch
Normal 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
|
||||
|
||||
266
upstream_utils/llvm_patches/0026-Remove-unused-functions.patch
Normal file
266
upstream_utils/llvm_patches/0026-Remove-unused-functions.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
46
upstream_utils/llvm_patches/0028-OS-specific-changes.patch
Normal file
46
upstream_utils/llvm_patches/0028-OS-specific-changes.patch
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
202
upstream_utils/update_llvm.py
Normal file
202
upstream_utils/update_llvm.py
Normal 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()
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
34
wpiutil/src/main/native/cpp/llvm/MemAlloc.cpp
Normal file
34
wpiutil/src/main/native/cpp/llvm/MemAlloc.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//===- MemAlloc.cpp - Memory allocation functions -------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/MemAlloc.h"
|
||||
|
||||
// These are out of line to have __cpp_aligned_new not affect ABI.
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
|
||||
wpi::allocate_buffer(size_t Size, size_t Alignment) {
|
||||
return ::operator new(Size
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
void wpi::deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
|
||||
::operator delete(Ptr
|
||||
#ifdef __cpp_sized_deallocation
|
||||
,
|
||||
Size
|
||||
#endif
|
||||
#ifdef __cpp_aligned_new
|
||||
,
|
||||
std::align_val_t(Alignment)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
82
wpiutil/src/main/native/include/wpi/STLForwardCompat.h
Normal file
82
wpiutil/src/main/native/include/wpi/STLForwardCompat.h
Normal file
@@ -0,0 +1,82 @@
|
||||
//===- STLForwardCompat.h - Library features from future STLs ------C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains library features backported from future STL versions.
|
||||
//
|
||||
// These should be replaced with their STL counterparts as the C++ version LLVM
|
||||
// is compiled with is updated.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
#define WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Features from C++17
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
struct negation // NOLINT(readability-identifier-naming)
|
||||
: std::integral_constant<bool, !bool(T::value)> {};
|
||||
|
||||
template <typename...>
|
||||
struct conjunction // NOLINT(readability-identifier-naming)
|
||||
: std::true_type {};
|
||||
template <typename B1> struct conjunction<B1> : B1 {};
|
||||
template <typename B1, typename... Bn>
|
||||
struct conjunction<B1, Bn...>
|
||||
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
|
||||
|
||||
template <typename...>
|
||||
struct disjunction // NOLINT(readability-identifier-naming)
|
||||
: std::false_type {};
|
||||
template <typename B1> struct disjunction<B1> : B1 {};
|
||||
template <typename B1, typename... Bn>
|
||||
struct disjunction<B1, Bn...>
|
||||
: std::conditional<bool(B1::value), B1, disjunction<Bn...>>::type {};
|
||||
|
||||
struct in_place_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_t() = default;
|
||||
};
|
||||
/// \warning This must not be odr-used, as it cannot be made \c inline in C++14.
|
||||
constexpr in_place_t in_place; // NOLINT(readability-identifier-naming)
|
||||
|
||||
template <typename T>
|
||||
struct in_place_type_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_type_t() = default;
|
||||
};
|
||||
|
||||
template <std::size_t I>
|
||||
struct in_place_index_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
explicit in_place_index_t() = default;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Features from C++20
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
struct remove_cvref // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
using type = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t // NOLINT(readability-identifier-naming)
|
||||
= typename wpi::remove_cvref<T>::type;
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_WPI_STLFORWARDCOMPAT_H
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
143
wpiutil/src/main/native/include/wpi/StringMapEntry.h
Normal file
143
wpiutil/src/main/native/include/wpi/StringMapEntry.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,6 +35,9 @@ SOFTWARE.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "unit-json.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using wpi::json;
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@@ -35,6 +35,7 @@ SOFTWARE.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
|
||||
@@ -38,6 +38,7 @@ SOFTWARE.
|
||||
using wpi::json;
|
||||
using wpi::JsonTest;
|
||||
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
//#include <forward_list>
|
||||
#include <list>
|
||||
|
||||
@@ -35,6 +35,9 @@ SOFTWARE.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "unit-json.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using wpi::json;
|
||||
|
||||
class JsonElementObjectAccessTestBase {
|
||||
|
||||
@@ -37,6 +37,7 @@ SOFTWARE.
|
||||
#include "unit-json.h"
|
||||
using wpi::json;
|
||||
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
|
||||
TEST(MessagePackDiscardedTest, Case)
|
||||
|
||||
@@ -35,6 +35,9 @@ SOFTWARE.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "unit-json.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using wpi::json;
|
||||
|
||||
TEST(JsonPointerTest, TypesCreate)
|
||||
|
||||
49
wpiutil/src/test/native/cpp/llvm/Chrono.cpp
Normal file
49
wpiutil/src/test/native/cpp/llvm/Chrono.cpp
Normal 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
|
||||
1712
wpiutil/src/test/native/cpp/llvm/ConvertUTFTest.cpp
Normal file
1712
wpiutil/src/test/native/cpp/llvm/ConvertUTFTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
637
wpiutil/src/test/native/cpp/llvm/DenseMapTest.cpp
Normal file
637
wpiutil/src/test/native/cpp/llvm/DenseMapTest.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
211
wpiutil/src/test/native/cpp/llvm/EndianTest.cpp
Normal file
211
wpiutil/src/test/native/cpp/llvm/EndianTest.cpp
Normal 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
|
||||
38
wpiutil/src/test/native/cpp/llvm/ErrnoTest.cpp
Normal file
38
wpiutil/src/test/native/cpp/llvm/ErrnoTest.cpp
Normal 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; }));
|
||||
}
|
||||
@@ -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
|
||||
|
||||
430
wpiutil/src/test/native/cpp/llvm/MapVectorTest.cpp
Normal file
430
wpiutil/src/test/native/cpp/llvm/MapVectorTest.cpp
Normal 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--;
|
||||
}
|
||||
}
|
||||
607
wpiutil/src/test/native/cpp/llvm/MathExtrasTest.cpp
Normal file
607
wpiutil/src/test/native/cpp/llvm/MathExtrasTest.cpp
Normal 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
|
||||
109
wpiutil/src/test/native/cpp/llvm/PointerIntPairTest.cpp
Normal file
109
wpiutil/src/test/native/cpp/llvm/PointerIntPairTest.cpp
Normal 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
|
||||
159
wpiutil/src/test/native/cpp/llvm/PointerUnionTest.cpp
Normal file
159
wpiutil/src/test/native/cpp/llvm/PointerUnionTest.cpp
Normal 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
|
||||
78
wpiutil/src/test/native/cpp/llvm/STLForwardCompatTest.cpp
Normal file
78
wpiutil/src/test/native/cpp/llvm/STLForwardCompatTest.cpp
Normal 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
Reference in New Issue
Block a user