[wpiutil] Upgrade to LLVM 17.0.1 (#5482)

This commit is contained in:
Tyler Veness
2023-09-21 19:54:33 -07:00
committed by GitHub
parent 07a0d22fe6
commit 1b6ec5a95d
82 changed files with 1697 additions and 901 deletions

View File

@@ -103,7 +103,7 @@ bool convertUTF16ToUTF8String(std::span<const char> SrcBytes, SmallVectorImpl<ch
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
for (UTF16 &I : ByteSwapped)
I = wpi::ByteSwap_16(I);
I = wpi::byteswap<uint16_t>(I);
Src = &ByteSwapped[0];
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
}
@@ -161,7 +161,7 @@ bool convertUTF32ToUTF8String(std::span<const char> SrcBytes, std::string &Out)
if (Src[0] == UNI_UTF32_BYTE_ORDER_MARK_SWAPPED) {
ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
for (UTF32 &I : ByteSwapped)
I = wpi::ByteSwap_32(I);
I = wpi::byteswap<uint32_t>(I);
Src = &ByteSwapped[0];
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
}

View File

@@ -11,8 +11,9 @@
//===----------------------------------------------------------------------===//
#include "wpi/StringMap.h"
#include "wpi/DJB.h"
#include "wpi/MathExtras.h"
#include "wpi/ReverseIteration.h"
#include "wpi/xxhash.h"
using namespace wpi;
@@ -84,7 +85,9 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
// Hash table unallocated so far?
if (NumBuckets == 0)
init(16);
unsigned FullHashValue = djbHash(Name, 0);
unsigned FullHashValue = xxh3_64bits(Name);
if (shouldReverseIterate())
FullHashValue = ~FullHashValue;
unsigned BucketNo = FullHashValue & (NumBuckets - 1);
unsigned *HashTable = getHashTable(TheTable, NumBuckets);
@@ -139,7 +142,9 @@ unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
int StringMapImpl::FindKey(std::string_view Key) const {
if (NumBuckets == 0)
return -1; // Really empty table?
unsigned FullHashValue = djbHash(Key, 0);
unsigned FullHashValue = xxh3_64bits(Key);
if (shouldReverseIterate())
FullHashValue = ~FullHashValue;
unsigned BucketNo = FullHashValue & (NumBuckets - 1);
unsigned *HashTable = getHashTable(TheTable, NumBuckets);

View File

@@ -0,0 +1,407 @@
/*
* xxHash - Fast Hash algorithm
* Copyright (C) 2012-2021, Yann Collet
*
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at :
* - xxHash homepage: http://www.xxhash.com
* - xxHash source repository : https://github.com/Cyan4973/xxHash
*/
// xxhash64 is based on commit d2df04efcbef7d7f6886d345861e5dfda4edacc1. Removed
// everything but a simple interface for computing xxh64.
// xxh3_64bits is based on commit d5891596637d21366b9b1dcf2c0007a3edb26a9e (July
// 2023).
#include "wpi/xxhash.h"
#include "wpi/Compiler.h"
#include "wpi/Endian.h"
#include <stdlib.h>
using namespace wpi;
using namespace support;
static uint64_t rotl64(uint64_t X, size_t R) {
return (X << R) | (X >> (64 - R));
}
constexpr uint32_t PRIME32_1 = 0x9E3779B1;
constexpr uint32_t PRIME32_2 = 0x85EBCA77;
constexpr uint32_t PRIME32_3 = 0xC2B2AE3D;
static const uint64_t PRIME64_1 = 11400714785074694791ULL;
static const uint64_t PRIME64_2 = 14029467366897019727ULL;
static const uint64_t PRIME64_3 = 1609587929392839161ULL;
static const uint64_t PRIME64_4 = 9650029242287828579ULL;
static const uint64_t PRIME64_5 = 2870177450012600261ULL;
static uint64_t round(uint64_t Acc, uint64_t Input) {
Acc += Input * PRIME64_2;
Acc = rotl64(Acc, 31);
Acc *= PRIME64_1;
return Acc;
}
static uint64_t mergeRound(uint64_t Acc, uint64_t Val) {
Val = round(0, Val);
Acc ^= Val;
Acc = Acc * PRIME64_1 + PRIME64_4;
return Acc;
}
static uint64_t XXH64_avalanche(uint64_t hash) {
hash ^= hash >> 33;
hash *= PRIME64_2;
hash ^= hash >> 29;
hash *= PRIME64_3;
hash ^= hash >> 32;
return hash;
}
uint64_t wpi::xxHash64(std::string_view Data) {
size_t Len = Data.size();
uint64_t Seed = 0;
const unsigned char *P = reinterpret_cast<const unsigned char*>(Data.data());
const unsigned char *const BEnd = P + Data.size();
uint64_t H64;
if (Len >= 32) {
const unsigned char *const Limit = BEnd - 32;
uint64_t V1 = Seed + PRIME64_1 + PRIME64_2;
uint64_t V2 = Seed + PRIME64_2;
uint64_t V3 = Seed + 0;
uint64_t V4 = Seed - PRIME64_1;
do {
V1 = round(V1, endian::read64le(P));
P += 8;
V2 = round(V2, endian::read64le(P));
P += 8;
V3 = round(V3, endian::read64le(P));
P += 8;
V4 = round(V4, endian::read64le(P));
P += 8;
} while (P <= Limit);
H64 = rotl64(V1, 1) + rotl64(V2, 7) + rotl64(V3, 12) + rotl64(V4, 18);
H64 = mergeRound(H64, V1);
H64 = mergeRound(H64, V2);
H64 = mergeRound(H64, V3);
H64 = mergeRound(H64, V4);
} else {
H64 = Seed + PRIME64_5;
}
H64 += (uint64_t)Len;
while (reinterpret_cast<uintptr_t>(P) + 8 <=
reinterpret_cast<uintptr_t>(BEnd)) {
uint64_t const K1 = round(0, endian::read64le(P));
H64 ^= K1;
H64 = rotl64(H64, 27) * PRIME64_1 + PRIME64_4;
P += 8;
}
if (reinterpret_cast<uintptr_t>(P) + 4 <= reinterpret_cast<uintptr_t>(BEnd)) {
H64 ^= (uint64_t)(endian::read32le(P)) * PRIME64_1;
H64 = rotl64(H64, 23) * PRIME64_2 + PRIME64_3;
P += 4;
}
while (P < BEnd) {
H64 ^= (*P) * PRIME64_5;
H64 = rotl64(H64, 11) * PRIME64_1;
P++;
}
return XXH64_avalanche(H64);
}
uint64_t wpi::xxHash64(std::span<const uint8_t> Data) {
return xxHash64({(const char *)Data.data(), Data.size()});
}
constexpr size_t XXH3_SECRETSIZE_MIN = 136;
constexpr size_t XXH_SECRET_DEFAULT_SIZE = 192;
/* Pseudorandom data taken directly from FARSH */
// clang-format off
constexpr uint8_t kSecret[XXH_SECRET_DEFAULT_SIZE] = {
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
};
// clang-format on
constexpr uint64_t PRIME_MX1 = 0x165667919E3779F9;
constexpr uint64_t PRIME_MX2 = 0x9FB21C651E98DF25;
// Calculates a 64-bit to 128-bit multiply, then XOR folds it.
static uint64_t XXH3_mul128_fold64(uint64_t lhs, uint64_t rhs) {
#if defined(__SIZEOF_INT128__) || \
(defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)
__uint128_t product = (__uint128_t)lhs * (__uint128_t)rhs;
return uint64_t(product) ^ uint64_t(product >> 64);
#else
/* First calculate all of the cross products. */
const uint64_t lo_lo = (lhs & 0xFFFFFFFF) * (rhs & 0xFFFFFFFF);
const uint64_t hi_lo = (lhs >> 32) * (rhs & 0xFFFFFFFF);
const uint64_t lo_hi = (lhs & 0xFFFFFFFF) * (rhs >> 32);
const uint64_t hi_hi = (lhs >> 32) * (rhs >> 32);
/* Now add the products together. These will never overflow. */
const uint64_t cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
const uint64_t upper = (hi_lo >> 32) + (cross >> 32) + hi_hi;
const uint64_t lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);
return upper ^ lower;
#endif
}
constexpr size_t XXH_STRIPE_LEN = 64;
constexpr size_t XXH_SECRET_CONSUME_RATE = 8;
constexpr size_t XXH_ACC_NB = XXH_STRIPE_LEN / sizeof(uint64_t);
static uint64_t XXH3_avalanche(uint64_t hash) {
hash ^= hash >> 37;
hash *= PRIME_MX1;
hash ^= hash >> 32;
return hash;
}
static uint64_t XXH3_len_1to3_64b(const uint8_t *input, size_t len,
const uint8_t *secret, uint64_t seed) {
const uint8_t c1 = input[0];
const uint8_t c2 = input[len >> 1];
const uint8_t c3 = input[len - 1];
uint32_t combined = ((uint32_t)c1 << 16) | ((uint32_t)c2 << 24) |
((uint32_t)c3 << 0) | ((uint32_t)len << 8);
uint64_t bitflip =
(uint64_t)(endian::read32le(secret) ^ endian::read32le(secret + 4)) +
seed;
return XXH64_avalanche(uint64_t(combined) ^ bitflip);
}
static uint64_t XXH3_len_4to8_64b(const uint8_t *input, size_t len,
const uint8_t *secret, uint64_t seed) {
seed ^= (uint64_t)byteswap(uint32_t(seed)) << 32;
const uint32_t input1 = endian::read32le(input);
const uint32_t input2 = endian::read32le(input + len - 4);
uint64_t acc =
(endian::read64le(secret + 8) ^ endian::read64le(secret + 16)) - seed;
const uint64_t input64 = (uint64_t)input2 | ((uint64_t)input1 << 32);
acc ^= input64;
// XXH3_rrmxmx(acc, len)
acc ^= rotl64(acc, 49) ^ rotl64(acc, 24);
acc *= PRIME_MX2;
acc ^= (acc >> 35) + (uint64_t)len;
acc *= PRIME_MX2;
return acc ^ (acc >> 28);
}
static uint64_t XXH3_len_9to16_64b(const uint8_t *input, size_t len,
const uint8_t *secret, uint64_t const seed) {
uint64_t input_lo =
(endian::read64le(secret + 24) ^ endian::read64le(secret + 32)) + seed;
uint64_t input_hi =
(endian::read64le(secret + 40) ^ endian::read64le(secret + 48)) - seed;
input_lo ^= endian::read64le(input);
input_hi ^= endian::read64le(input + len - 8);
uint64_t acc = uint64_t(len) + byteswap(input_lo) + input_hi +
XXH3_mul128_fold64(input_lo, input_hi);
return XXH3_avalanche(acc);
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
static uint64_t XXH3_len_0to16_64b(const uint8_t *input, size_t len,
const uint8_t *secret, uint64_t const seed) {
if (LLVM_LIKELY(len > 8))
return XXH3_len_9to16_64b(input, len, secret, seed);
if (LLVM_LIKELY(len >= 4))
return XXH3_len_4to8_64b(input, len, secret, seed);
if (len != 0)
return XXH3_len_1to3_64b(input, len, secret, seed);
return XXH64_avalanche(seed ^ endian::read64le(secret + 56) ^
endian::read64le(secret + 64));
}
static uint64_t XXH3_mix16B(const uint8_t *input, uint8_t const *secret,
uint64_t seed) {
uint64_t lhs = seed;
uint64_t rhs = 0U - seed;
lhs += endian::read64le(secret);
rhs += endian::read64le(secret + 8);
lhs ^= endian::read64le(input);
rhs ^= endian::read64le(input + 8);
return XXH3_mul128_fold64(lhs, rhs);
}
/* For mid range keys, XXH3 uses a Mum-hash variant. */
LLVM_ATTRIBUTE_ALWAYS_INLINE
static uint64_t XXH3_len_17to128_64b(const uint8_t *input, size_t len,
const uint8_t *secret,
uint64_t const seed) {
uint64_t acc = len * PRIME64_1, acc_end;
acc += XXH3_mix16B(input + 0, secret + 0, seed);
acc_end = XXH3_mix16B(input + len - 16, secret + 16, seed);
if (len > 32) {
acc += XXH3_mix16B(input + 16, secret + 32, seed);
acc_end += XXH3_mix16B(input + len - 32, secret + 48, seed);
if (len > 64) {
acc += XXH3_mix16B(input + 32, secret + 64, seed);
acc_end += XXH3_mix16B(input + len - 48, secret + 80, seed);
if (len > 96) {
acc += XXH3_mix16B(input + 48, secret + 96, seed);
acc_end += XXH3_mix16B(input + len - 64, secret + 112, seed);
}
}
}
return XXH3_avalanche(acc + acc_end);
}
constexpr size_t XXH3_MIDSIZE_MAX = 240;
LLVM_ATTRIBUTE_NOINLINE
static uint64_t XXH3_len_129to240_64b(const uint8_t *input, size_t len,
const uint8_t *secret, uint64_t seed) {
constexpr size_t XXH3_MIDSIZE_STARTOFFSET = 3;
constexpr size_t XXH3_MIDSIZE_LASTOFFSET = 17;
uint64_t acc = (uint64_t)len * PRIME64_1;
const unsigned nbRounds = len / 16;
for (unsigned i = 0; i < 8; ++i)
acc += XXH3_mix16B(input + 16 * i, secret + 16 * i, seed);
acc = XXH3_avalanche(acc);
for (unsigned i = 8; i < nbRounds; ++i) {
acc += XXH3_mix16B(input + 16 * i,
secret + 16 * (i - 8) + XXH3_MIDSIZE_STARTOFFSET, seed);
}
/* last bytes */
acc +=
XXH3_mix16B(input + len - 16,
secret + XXH3_SECRETSIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
return XXH3_avalanche(acc);
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
static void XXH3_accumulate_512_scalar(uint64_t *acc, const uint8_t *input,
const uint8_t *secret) {
for (size_t i = 0; i < XXH_ACC_NB; ++i) {
uint64_t data_val = endian::read64le(input + 8 * i);
uint64_t data_key = data_val ^ endian::read64le(secret + 8 * i);
acc[i ^ 1] += data_val;
acc[i] += uint32_t(data_key) * (data_key >> 32);
}
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
static void XXH3_accumulate_scalar(uint64_t *acc, const uint8_t *input,
const uint8_t *secret, size_t nbStripes) {
for (size_t n = 0; n < nbStripes; ++n)
XXH3_accumulate_512_scalar(acc, input + n * XXH_STRIPE_LEN,
secret + n * XXH_SECRET_CONSUME_RATE);
}
static void XXH3_scrambleAcc(uint64_t *acc, const uint8_t *secret) {
for (size_t i = 0; i < XXH_ACC_NB; ++i) {
acc[i] ^= acc[i] >> 47;
acc[i] ^= endian::read64le(secret + 8 * i);
acc[i] *= PRIME32_1;
}
}
static uint64_t XXH3_mix2Accs(const uint64_t *acc, const uint8_t *secret) {
return XXH3_mul128_fold64(acc[0] ^ endian::read64le(secret),
acc[1] ^ endian::read64le(secret + 8));
}
static uint64_t XXH3_mergeAccs(const uint64_t *acc, const uint8_t *key,
uint64_t start) {
uint64_t result64 = start;
for (size_t i = 0; i < 4; ++i)
result64 += XXH3_mix2Accs(acc + 2 * i, key + 16 * i);
return XXH3_avalanche(result64);
}
LLVM_ATTRIBUTE_NOINLINE
static uint64_t XXH3_hashLong_64b(const uint8_t *input, size_t len,
const uint8_t *secret, size_t secretSize) {
const size_t nbStripesPerBlock =
(secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE;
const size_t block_len = XXH_STRIPE_LEN * nbStripesPerBlock;
const size_t nb_blocks = (len - 1) / block_len;
alignas(16) uint64_t acc[XXH_ACC_NB] = {
PRIME32_3, PRIME64_1, PRIME64_2, PRIME64_3,
PRIME64_4, PRIME32_2, PRIME64_5, PRIME32_1,
};
for (size_t n = 0; n < nb_blocks; ++n) {
XXH3_accumulate_scalar(acc, input + n * block_len, secret,
nbStripesPerBlock);
XXH3_scrambleAcc(acc, secret + secretSize - XXH_STRIPE_LEN);
}
/* last partial block */
const size_t nbStripes = (len - 1 - (block_len * nb_blocks)) / XXH_STRIPE_LEN;
assert(nbStripes <= secretSize / XXH_SECRET_CONSUME_RATE);
XXH3_accumulate_scalar(acc, input + nb_blocks * block_len, secret, nbStripes);
/* last stripe */
constexpr size_t XXH_SECRET_LASTACC_START = 7;
XXH3_accumulate_512_scalar(acc, input + len - XXH_STRIPE_LEN,
secret + secretSize - XXH_STRIPE_LEN -
XXH_SECRET_LASTACC_START);
/* converge into final hash */
constexpr size_t XXH_SECRET_MERGEACCS_START = 11;
return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START,
(uint64_t)len * PRIME64_1);
}
uint64_t wpi::xxh3_64bits(std::span<const uint8_t> data) {
auto *in = data.data();
size_t len = data.size();
if (len <= 16)
return XXH3_len_0to16_64b(in, len, kSecret, 0);
if (len <= 128)
return XXH3_len_17to128_64b(in, len, kSecret, 0);
if (len <= XXH3_MIDSIZE_MAX)
return XXH3_len_129to240_64b(in, len, kSecret, 0);
return XXH3_hashLong_64b(in, len, kSecret, sizeof(kSecret));
}

View File

@@ -0,0 +1,103 @@
//===- llvm/ADT/ADL.h - Argument dependent lookup utilities -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_ADL_H
#define WPIUTIL_WPI_ADL_H
#include <type_traits>
#include <iterator>
#include <utility>
namespace wpi {
// Only used by compiler if both template types are the same. Useful when
// using SFINAE to test for the existence of member functions.
template <typename T, T> struct SameType;
namespace adl_detail {
using std::begin;
template <typename RangeT>
constexpr auto begin_impl(RangeT &&range)
-> decltype(begin(std::forward<RangeT>(range))) {
return begin(std::forward<RangeT>(range));
}
using std::end;
template <typename RangeT>
constexpr auto end_impl(RangeT &&range)
-> decltype(end(std::forward<RangeT>(range))) {
return end(std::forward<RangeT>(range));
}
using std::swap;
template <typename T>
constexpr void swap_impl(T &&lhs,
T &&rhs) noexcept(noexcept(swap(std::declval<T>(),
std::declval<T>()))) {
swap(std::forward<T>(lhs), std::forward<T>(rhs));
}
using std::size;
template <typename RangeT>
constexpr auto size_impl(RangeT &&range)
-> decltype(size(std::forward<RangeT>(range))) {
return size(std::forward<RangeT>(range));
}
} // end namespace adl_detail
/// Returns the begin iterator to \p range using `std::begin` and
/// function found through Argument-Dependent Lookup (ADL).
template <typename RangeT>
constexpr auto adl_begin(RangeT &&range)
-> decltype(adl_detail::begin_impl(std::forward<RangeT>(range))) {
return adl_detail::begin_impl(std::forward<RangeT>(range));
}
/// Returns the end iterator to \p range using `std::end` and
/// functions found through Argument-Dependent Lookup (ADL).
template <typename RangeT>
constexpr auto adl_end(RangeT &&range)
-> decltype(adl_detail::end_impl(std::forward<RangeT>(range))) {
return adl_detail::end_impl(std::forward<RangeT>(range));
}
/// Swaps \p lhs with \p rhs using `std::swap` and functions found through
/// Argument-Dependent Lookup (ADL).
template <typename T>
constexpr void adl_swap(T &&lhs, T &&rhs) noexcept(
noexcept(adl_detail::swap_impl(std::declval<T>(), std::declval<T>()))) {
adl_detail::swap_impl(std::forward<T>(lhs), std::forward<T>(rhs));
}
/// Returns the size of \p range using `std::size` and functions found through
/// Argument-Dependent Lookup (ADL).
template <typename RangeT>
constexpr auto adl_size(RangeT &&range)
-> decltype(adl_detail::size_impl(std::forward<RangeT>(range))) {
return adl_detail::size_impl(std::forward<RangeT>(range));
}
namespace detail {
template <typename RangeT>
using IterOfRange = decltype(adl_begin(std::declval<RangeT &>()));
template <typename RangeT>
using ValueOfRange =
std::remove_reference_t<decltype(*adl_begin(std::declval<RangeT &>()))>;
} // namespace detail
} // namespace wpi
#endif // WPIUTIL_WPI_ADL_H

View File

@@ -19,6 +19,12 @@
#ifndef WPIUTIL_WPI_ALLOCATORBASE_H
#define WPIUTIL_WPI_ALLOCATORBASE_H
#ifdef _MSC_VER
#define LLVM_ALLOCATORHOLDER_EMPTYBASE __declspec(empty_bases)
#else
#define LLVM_ALLOCATORHOLDER_EMPTYBASE
#endif // _MSC_VER
#include "wpi/Compiler.h"
#include "wpi/MemAlloc.h"
#include <type_traits>
@@ -72,7 +78,7 @@ public:
/// Deallocate space for a sequence of objects without constructing them.
template <typename T>
std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void>
std::enable_if_t<!std::is_same_v<std::remove_cv_t<T>, void>, void>
Deallocate(T *Ptr, size_t Num = 1) {
Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T));
}

View File

@@ -66,7 +66,7 @@ template <typename To, typename From, typename Enabler = void> struct isa_impl {
// Always allow upcasts, and perform no dynamic check for them.
template <typename To, typename From>
struct isa_impl<To, From, std::enable_if_t<std::is_base_of<To, From>::value>> {
struct isa_impl<To, From, std::enable_if_t<std::is_base_of_v<To, From>>> {
static inline bool doit(const From &) { return true; }
};
@@ -231,7 +231,7 @@ struct cast_convert_val<To, FromTy *, FromTy *> {
template <class X> struct is_simple_type {
static const bool value =
std::is_same<X, typename simplify_type<X>::SimpleType>::value;
std::is_same_v<X, typename simplify_type<X>::SimpleType>;
};
// } // namespace detail
@@ -275,8 +275,7 @@ struct CastIsPossible<To, std::optional<From>> {
/// Upcasting (from derived to base) and casting from a type to itself should
/// always be possible.
template <typename To, typename From>
struct CastIsPossible<To, From,
std::enable_if_t<std::is_base_of<To, From>::value>> {
struct CastIsPossible<To, From, std::enable_if_t<std::is_base_of_v<To, From>>> {
static inline bool isPossible(const From &f) { return true; }
};
@@ -319,7 +318,7 @@ namespace detail {
/// A helper to derive the type to use with `Self` for cast traits, when the
/// provided CRTP derived type is allowed to be void.
template <typename OptionalDerived, typename Default>
using SelfType = std::conditional_t<std::is_same<OptionalDerived, void>::value,
using SelfType = std::conditional_t<std::is_same_v<OptionalDerived, void>,
Default, OptionalDerived>;
} // namespace detail
@@ -390,8 +389,8 @@ struct ConstStrippingForwardingCast {
// Remove the pointer if it exists, then we can get rid of consts/volatiles.
using DecayedFrom = std::remove_cv_t<std::remove_pointer_t<From>>;
// Now if it's a pointer, add it back. Otherwise, we want a ref.
using NonConstFrom = std::conditional_t<std::is_pointer<From>::value,
DecayedFrom *, DecayedFrom &>;
using NonConstFrom =
std::conditional_t<std::is_pointer_v<From>, DecayedFrom *, DecayedFrom &>;
static inline bool isPossible(const From &f) {
return ForwardTo::isPossible(const_cast<NonConstFrom>(f));

View File

@@ -114,12 +114,24 @@
/// 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) && \
(!(defined(_WIN32) || defined(__CYGWIN__)) || \
#if LLVM_HAS_CPP_ATTRIBUTE(gnu::visibility)
#define LLVM_ATTRIBUTE_VISIBILITY_HIDDEN [[gnu::visibility("hidden")]]
#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT [[gnu::visibility("default")]]
#elif __has_attribute(visibility)
#define LLVM_ATTRIBUTE_VISIBILITY_HIDDEN __attribute__((visibility("hidden")))
#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT __attribute__((visibility("default")))
#else
#define LLVM_ATTRIBUTE_VISIBILITY_HIDDEN
#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
#endif
#if (!(defined(_WIN32) || defined(__CYGWIN__)) || \
(defined(__MINGW32__) && defined(__clang__)))
#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
#define LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_VISIBILITY_HIDDEN
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
#define LLVM_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
#define LLVM_EXTERNAL_VISIBILITY LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
#else
#define LLVM_EXTERNAL_VISIBILITY
#endif

View File

@@ -1,29 +0,0 @@
//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains support for the DJ Bernstein hash function.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_DJB_H
#define WPIUTIL_WPI_DJB_H
#include <string_view>
namespace wpi {
/// The Bernstein hash function used by the DWARF accelerator tables.
inline uint32_t djbHash(std::string_view Buffer, uint32_t H = 5381) {
for (unsigned char C : Buffer)
H = (H << 5) + H + C;
return H;
}
} // namespace wpi
#endif // WPIUTIL_WPI_DJB_H

View File

@@ -23,6 +23,7 @@
#include "wpi/ReverseIteration.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <bit>
#include <cassert>
#include <cstddef>
#include <cstring>
@@ -141,10 +142,15 @@ public:
setNumTombstones(0);
}
/// Return true if the specified key is in the map, false otherwise.
bool contains(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
return LookupBucketFor(Val, TheBucket);
}
/// Return 1 if the specified key is in the map, 0 otherwise.
size_type count(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
return LookupBucketFor(Val, TheBucket) ? 1 : 0;
return contains(Val) ? 1 : 0;
}
iterator find(const_arg_type_t<KeyT> Val) {
@@ -201,6 +207,14 @@ public:
return ValueT();
}
/// at - Return the entry for the specified key, or abort if no such
/// entry exists.
const ValueT &at(const_arg_type_t<KeyT> Val) const {
auto Iter = this->find(std::move(Val));
assert(Iter != this->end() && "DenseMap::at failed due to a missing key");
return Iter->second;
}
// Inserts key,value pair into the map if the key isn't already in the map.
// If the key is already in the map, it returns false and doesn't update the
// value.
@@ -299,6 +313,20 @@ public:
insert(*I);
}
/// Returns the value associated to the key in the map if it exists. If it
/// does not exist, emplace a default value for the key and returns a
/// reference to the newly created value.
ValueT &getOrInsertDefault(KeyT &&Key) {
return try_emplace(Key).first->second;
}
/// Returns the value associated to the key in the map if it exists. If it
/// does not exist, emplace a default value for the key and returns a
/// reference to the newly created value.
ValueT &getOrInsertDefault(const KeyT &Key) {
return try_emplace(Key).first->second;
}
bool erase(const KeyT &Val) {
BucketT *TheBucket;
if (!LookupBucketFor(Val, TheBucket))
@@ -906,7 +934,7 @@ class SmallDenseMap
public:
explicit SmallDenseMap(unsigned NumInitBuckets = 0) {
if (NumInitBuckets > InlineBuckets)
NumInitBuckets = NextPowerOf2(NumInitBuckets - 1);
NumInitBuckets = std::bit_ceil(NumInitBuckets);
init(NumInitBuckets);
}

View File

@@ -20,7 +20,6 @@
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
namespace wpi {
@@ -234,6 +233,14 @@ struct DenseMapInfo<std::pair<T, U>> {
SecondInfo::getHashValue(PairVal.second));
}
// Expose an additional function intended to be used by other
// specializations of DenseMapInfo without needing to know how
// to combine hash values manually
static unsigned getHashValuePiecewise(const T &First, const U &Second) {
return detail::combineHashValue(FirstInfo::getHashValue(First),
SecondInfo::getHashValue(Second));
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
return FirstInfo::isEqual(LHS.first, RHS.first) &&
SecondInfo::isEqual(LHS.second, RHS.second);
@@ -290,37 +297,6 @@ template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
}
};
// Provide DenseMapInfo for variants whose all alternatives have DenseMapInfo.
template <typename... Ts> struct DenseMapInfo<std::variant<Ts...>> {
using Variant = std::variant<Ts...>;
using FirstT = std::variant_alternative_t<0, Variant>;
static inline Variant getEmptyKey() {
return Variant(std::in_place_index<0>, DenseMapInfo<FirstT>::getEmptyKey());
}
static inline Variant getTombstoneKey() {
return Variant(std::in_place_index<0>,
DenseMapInfo<FirstT>::getTombstoneKey());
}
static unsigned getHashValue(const Variant &Val) {
return std::visit(
[&Val](auto &&Alternative) {
using T = std::decay_t<decltype(Alternative)>;
// Include index in hash to make sure same value as different
// alternatives don't collide.
return detail::combineHashValue(
DenseMapInfo<size_t>::getHashValue(Val.index()),
DenseMapInfo<T>::getHashValue(Alternative));
},
Val);
}
static bool isEqual(const Variant &LHS, const Variant &RHS) {
return LHS == RHS;
}
};
} // end namespace wpi
#endif // WPIUTIL_WPI_DENSEMAPINFO_H

View File

@@ -0,0 +1,71 @@
//===- DenseMapInfoVariant.h - Type traits for DenseMap<variant> *- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines DenseMapInfo traits for DenseMap<std::variant<Ts...>>.
///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_DENSEMAPINFOVARIANT_H
#define WPIUTIL_WPI_DENSEMAPINFOVARIANT_H
#include "wpi/DenseMapInfo.h"
#include <utility>
#include <variant>
namespace wpi {
// Provide DenseMapInfo for variants whose all alternatives have DenseMapInfo.
template <typename... Ts> struct DenseMapInfo<std::variant<Ts...>> {
using Variant = std::variant<Ts...>;
using FirstT = std::variant_alternative_t<0, Variant>;
static inline Variant getEmptyKey() {
return Variant(std::in_place_index<0>, DenseMapInfo<FirstT>::getEmptyKey());
}
static inline Variant getTombstoneKey() {
return Variant(std::in_place_index<0>,
DenseMapInfo<FirstT>::getTombstoneKey());
}
static unsigned getHashValue(const Variant &Val) {
return std::visit(
[&Val](auto &&Alternative) {
using T = std::decay_t<decltype(Alternative)>;
// Include index in hash to make sure same value as different
// alternatives don't collide.
return DenseMapInfo<std::pair<size_t, T>>::getHashValuePiecewise(
Val.index(), Alternative);
},
Val);
}
static bool isEqual(const Variant &LHS, const Variant &RHS) {
if (LHS.index() != RHS.index())
return false;
if (LHS.valueless_by_exception())
return true;
// We want to dispatch to DenseMapInfo<T>::isEqual(LHS.get(I), RHS.get(I))
// We know the types are the same, but std::visit(V, LHS, RHS) doesn't.
// We erase the type held in LHS to void*, and dispatch over RHS.
const void *ErasedLHS =
std::visit([](const auto &LHS) -> const void * { return &LHS; }, LHS);
return std::visit(
[&](const auto &RHS) -> bool {
using T = std::remove_cv_t<std::remove_reference_t<decltype(RHS)>>;
return DenseMapInfo<T>::isEqual(*static_cast<const T *>(ErasedLHS),
RHS);
},
RHS);
}
};
} // end namespace wpi
#endif // WPIUTIL_WPI_DENSEMAPINFOVARIANT_H

View File

@@ -22,6 +22,7 @@
namespace wpi {
#ifndef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
#define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE
/// A base class for data structure classes wishing to make iterators
/// ("handles") pointing into themselves fail-fast. When building without
@@ -77,6 +78,11 @@ public:
};
#else
#ifdef _MSC_VER
#define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE __declspec(empty_bases)
#else
#define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE
#endif // _MSC_VER
class DebugEpochBase {
public:

View File

@@ -44,7 +44,7 @@ namespace wpi {
void install_fatal_error_handler(fatal_error_handler_t handler,
void *user_data = nullptr);
/// Restores default error handling behavior.
/// Restores default error handling behaviour.
void remove_fatal_error_handler();
/// ScopedFatalErrorHandler - This is a simple helper class which just

View File

@@ -67,7 +67,7 @@ namespace detail {
template <typename T>
using EnableIfTrivial =
std::enable_if_t<wpi::is_trivially_move_constructible<T>::value &&
std::enable_if_t<std::is_trivially_move_constructible<T>::value &&
std::is_trivially_destructible<T>::value>;
template <typename CallableT, typename ThisT>
using EnableUnlessSameType =
@@ -107,11 +107,11 @@ protected:
template <typename T> struct AdjustedParamTBase {
static_assert(!std::is_reference<T>::value,
"references should be handled by template specialization");
using type = std::conditional_t<
wpi::is_trivially_copy_constructible<T>::value &&
wpi::is_trivially_move_constructible<T>::value &&
IsSizeLessThanThresholdT<T>::value,
T, T &>;
using type =
std::conditional_t<std::is_trivially_copy_constructible<T>::value &&
std::is_trivially_move_constructible<T>::value &&
IsSizeLessThanThresholdT<T>::value,
T, T &>;
};
// This specialization ensures that 'AdjustedParam<V<T>&>' or
@@ -179,16 +179,15 @@ protected:
bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
bool isTrivialCallback() const {
return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
return isa<TrivialCallback *>(CallbackAndInlineFlag.getPointer());
}
CallPtrT getTrivialCallback() const {
return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
return cast<TrivialCallback *>(CallbackAndInlineFlag.getPointer())->CallPtr;
}
NonTrivialCallbacks *getNonTrivialCallbacks() const {
return CallbackAndInlineFlag.getPointer()
.template get<NonTrivialCallbacks *>();
return cast<NonTrivialCallbacks *>(CallbackAndInlineFlag.getPointer());
}
CallPtrT getCallPtr() const {

View File

@@ -48,6 +48,7 @@
#include "wpi/SwapByteOrder.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <bit>
#include <cassert>
#include <cstring>
#include <optional>
@@ -223,29 +224,30 @@ inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) {
uint64_t b = fetch64(s + 8);
uint64_t c = fetch64(s + len - 8) * k2;
uint64_t d = fetch64(s + len - 16) * k0;
return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d,
a + rotate(b ^ k3, 20) - c + len + seed);
return hash_16_bytes(std::rotr<uint64_t>(a - b, 43) +
std::rotr<uint64_t>(c ^ seed, 30) + d,
a + std::rotr<uint64_t>(b ^ k3, 20) - c + len + seed);
}
inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) {
uint64_t z = fetch64(s + 24);
uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0;
uint64_t b = rotate(a + z, 52);
uint64_t c = rotate(a, 37);
uint64_t b = std::rotr<uint64_t>(a + z, 52);
uint64_t c = std::rotr<uint64_t>(a, 37);
a += fetch64(s + 8);
c += rotate(a, 7);
c += std::rotr<uint64_t>(a, 7);
a += fetch64(s + 16);
uint64_t vf = a + z;
uint64_t vs = b + rotate(a, 31) + c;
uint64_t vs = b + std::rotr<uint64_t>(a, 31) + c;
a = fetch64(s + 16) + fetch64(s + len - 32);
z = fetch64(s + len - 8);
b = rotate(a + z, 52);
c = rotate(a, 37);
b = std::rotr<uint64_t>(a + z, 52);
c = std::rotr<uint64_t>(a, 37);
a += fetch64(s + len - 24);
c += rotate(a, 7);
c += std::rotr<uint64_t>(a, 7);
a += fetch64(s + len - 16);
uint64_t wf = a + z;
uint64_t ws = b + rotate(a, 31) + c;
uint64_t ws = b + std::rotr<uint64_t>(a, 31) + c;
uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
return shift_mix((seed ^ (r * k0)) + vs) * k2;
}
@@ -275,9 +277,13 @@ struct hash_state {
/// seed and the first 64-byte chunk.
/// This effectively performs the initial mix.
static hash_state create(const char *s, uint64_t seed) {
hash_state state = {
0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
seed * k1, shift_mix(seed), 0 };
hash_state state = {0,
seed,
hash_16_bytes(seed, k1),
std::rotr<uint64_t>(seed ^ k1, 49),
seed * k1,
shift_mix(seed),
0};
state.h6 = hash_16_bytes(state.h4, state.h5);
state.mix(s);
return state;
@@ -288,10 +294,10 @@ struct hash_state {
static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
a += fetch64(s);
uint64_t c = fetch64(s + 24);
b = rotate(b + a + c, 21);
b = std::rotr<uint64_t>(b + a + c, 21);
uint64_t d = a;
a += fetch64(s + 8) + fetch64(s + 16);
b += rotate(a, 44) + d;
b += std::rotr<uint64_t>(a, 44) + d;
a += c;
}
@@ -299,11 +305,11 @@ struct hash_state {
/// We mix all 64 bytes even when the chunk length is smaller, but we
/// record the actual length.
void mix(const char *s) {
h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1;
h0 = std::rotr<uint64_t>(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
h1 = std::rotr<uint64_t>(h1 + h4 + fetch64(s + 48), 42) * k1;
h0 ^= h6;
h1 += h3 + fetch64(s + 40);
h2 = rotate(h2 + h5, 33) * k1;
h2 = std::rotr<uint64_t>(h2 + h5, 33) * k1;
h3 = h4 * k1;
h4 = h0 + h5;
mix_32_bytes(s, h3, h4);

View File

@@ -10,7 +10,7 @@
/// This file implements a map that provides insertion order iteration. The
/// interface is purposefully minimal. The key is assumed to be cheap to copy
/// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in
/// a std::vector.
/// a SmallVector.
///
//===----------------------------------------------------------------------===//
@@ -24,16 +24,15 @@
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
namespace wpi {
/// This class implements a map that also provides access to all stored values
/// in a deterministic order. The values are kept in a std::vector and the
/// in a deterministic order. The values are kept in a SmallVector<*, 0> and the
/// mapping is done with DenseMap from Keys to indexes in that vector.
template<typename KeyT, typename ValueT,
typename MapType = DenseMap<KeyT, unsigned>,
typename VectorType = std::vector<std::pair<KeyT, ValueT>>>
template <typename KeyT, typename ValueT,
typename MapType = DenseMap<KeyT, unsigned>,
typename VectorType = SmallVector<std::pair<KeyT, ValueT>, 0>>
class MapVector {
MapType Map;
VectorType Vector;
@@ -140,10 +139,9 @@ public:
return std::make_pair(begin() + I, false);
}
size_type count(const KeyT &Key) const {
typename MapType::const_iterator Pos = Map.find(Key);
return Pos == Map.end()? 0 : 1;
}
bool contains(const KeyT &Key) const { return Map.find(Key) != Map.end(); }
size_type count(const KeyT &Key) const { return contains(Key) ? 1 : 0; }
iterator find(const KeyT &Key) {
typename MapType::const_iterator Pos = Map.find(Key);

View File

@@ -25,55 +25,10 @@
namespace wpi {
/// The behavior an operation has on an input of 0.
enum ZeroBehavior {
/// The returned value is undefined.
ZB_Undefined,
/// The returned value is numeric_limits<T>::max()
ZB_Max
};
/// Count number of 0's from the least significant bit to the most
/// stopping at the first 1.
///
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of 0.
template <typename T> unsigned countTrailingZeros(T Val) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return std::countr_zero(Val);
}
/// Count number of 0's from the most significant bit to the least
/// stopping at the first 1.
///
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of 0.
template <typename T> unsigned countLeadingZeros(T Val) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return std::countl_zero(Val);
}
/// Get the index of the first set bit starting from the least
/// significant bit.
///
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of 0.
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::countr_zero(Val);
}
/// Create a bitmask with the N right-most bits set to 1, and all other
/// bits set to 0. Only unsigned types are allowed.
template <typename T> T maskTrailingOnes(unsigned N) {
static_assert(std::is_unsigned<T>::value, "Invalid type!");
static_assert(std::is_unsigned_v<T>, "Invalid type!");
const unsigned Bits = CHAR_BIT * sizeof(T);
assert(N <= Bits && "Invalid bit index");
return N == 0 ? 0 : (T(-1) >> (Bits - N));
@@ -97,21 +52,6 @@ template <typename T> T maskLeadingZeros(unsigned N) {
return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
}
/// Get the index of the last set bit starting from the least
/// significant bit.
///
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of 0.
template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
if (ZB == ZB_Max && Val == 0)
return (std::numeric_limits<T>::max)();
// Use ^ instead of - because both gcc and llvm can remove the associated ^
// in the __builtin_clz intrinsic on x86.
return std::countl_zero(Val) ^ (std::numeric_limits<T>::digits - 1);
}
/// Macro compressed bit reversal table for 256 bits.
///
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
@@ -304,42 +244,6 @@ constexpr inline bool isPowerOf2_64(uint64_t Value) {
return std::has_single_bit(Value);
}
/// Count the number of ones from the most significant bit to the first
/// zero bit.
///
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of all ones.
template <typename T> unsigned countLeadingOnes(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return std::countl_one<T>(Value);
}
/// Count the number of ones from the least significant bit to the first
/// zero bit.
///
/// Ex. countTrailingOnes(0x00FF00FF) == 8.
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of all ones.
template <typename T> unsigned countTrailingOnes(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return std::countr_one<T>(Value);
}
/// Count the number of set bits in a value.
/// Ex. countPopulation(0xF000F000) = 8
/// Returns 0 if the word is zero.
template <typename T>
inline unsigned countPopulation(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return (unsigned)std::popcount(Value);
}
/// Return true if the argument contains a non-empty sequence of ones with the
/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
/// If true, \p MaskIdx will specify the index of the lowest set bit and \p
@@ -403,34 +307,6 @@ inline unsigned Log2_64_Ceil(uint64_t Value) {
return static_cast<unsigned>(64 - std::countl_zero(Value - 1));
}
/// This function takes a 64-bit integer and returns the bit equivalent double.
inline double BitsToDouble(uint64_t Bits) {
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
return wpi::bit_cast<double>(Bits);
}
/// This function takes a 32-bit integer and returns the bit equivalent float.
inline float BitsToFloat(uint32_t Bits) {
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
return wpi::bit_cast<float>(Bits);
}
/// This function takes a double and returns the bit equivalent 64-bit integer.
/// Note that copying doubles around changes the bits of NaNs on some hosts,
/// notably x86, so this routine cannot be used if these bits are needed.
inline uint64_t DoubleToBits(double Double) {
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
return wpi::bit_cast<uint64_t>(Double);
}
/// This function takes a float and returns the bit equivalent 32-bit integer.
/// Note that copying floats around changes the bits of NaNs on some hosts,
/// notably x86, so this routine cannot be used if these bits are needed.
inline uint32_t FloatToBits(float Float) {
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
return wpi::bit_cast<uint32_t>(Float);
}
/// A and B are either alignments or offsets. Return the minimum alignment that
/// may be assumed after adding the two together.
constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
@@ -454,12 +330,6 @@ constexpr inline uint64_t NextPowerOf2(uint64_t A) {
return A + 1;
}
/// Returns the power of two which is less than or equal to the given value.
/// Essentially, it is a floor operation across the domain of powers of two.
inline uint64_t PowerOf2Floor(uint64_t A) {
return std::bit_floor(A);
}
/// Returns the power of two which is greater than or equal to the given value.
/// Essentially, it is a ceil operation across the domain of powers of two.
inline uint64_t PowerOf2Ceil(uint64_t A) {
@@ -567,7 +437,7 @@ 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>
std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
std::enable_if_t<std::is_unsigned_v<T>, T> AbsoluteDifference(T X, T Y) {
return X > Y ? (X - Y) : (Y - X);
}
@@ -575,7 +445,7 @@ std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
/// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T.
template <typename T>
std::enable_if_t<std::is_unsigned<T>::value, T>
std::enable_if_t<std::is_unsigned_v<T>, T>
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -604,7 +474,7 @@ std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y, T Z,
/// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T.
template <typename T>
std::enable_if_t<std::is_unsigned<T>::value, T>
std::enable_if_t<std::is_unsigned_v<T>, T>
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -650,7 +520,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>
std::enable_if_t<std::is_unsigned<T>::value, T>
std::enable_if_t<std::is_unsigned_v<T>, T>
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -669,7 +539,7 @@ extern const float huge_valf;
/// Add two signed integers, computing the two's complement truncated result,
/// returning true if overflow occurred.
template <typename T>
std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
std::enable_if_t<std::is_signed_v<T>, T> AddOverflow(T X, T Y, T &Result) {
#if __has_builtin(__builtin_add_overflow)
return __builtin_add_overflow(X, Y, &Result);
#else
@@ -695,7 +565,7 @@ std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
/// 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) {
std::enable_if_t<std::is_signed_v<T>, T> SubOverflow(T X, T Y, T &Result) {
#if __has_builtin(__builtin_sub_overflow)
return __builtin_sub_overflow(X, Y, &Result);
#else
@@ -721,7 +591,7 @@ std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) {
/// 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) {
std::enable_if_t<std::is_signed_v<T>, 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);

View File

@@ -19,10 +19,44 @@
#include "wpi/type_traits.h"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <limits>
namespace wpi {
namespace detail {
template <typename Ptr> struct PunnedPointer {
static_assert(sizeof(Ptr) == sizeof(intptr_t), "");
// Asserts that allow us to let the compiler implement the destructor and
// copy/move constructors
static_assert(std::is_trivially_destructible<Ptr>::value, "");
static_assert(std::is_trivially_copy_constructible<Ptr>::value, "");
static_assert(std::is_trivially_move_constructible<Ptr>::value, "");
explicit constexpr PunnedPointer(intptr_t i = 0) { *this = i; }
constexpr intptr_t asInt() const {
intptr_t R = 0;
std::memcpy(&R, Data, sizeof(R));
return R;
}
constexpr operator intptr_t() const { return asInt(); }
constexpr PunnedPointer &operator=(intptr_t V) {
std::memcpy(Data, &V, sizeof(Data));
return *this;
}
Ptr *getPointerAddress() { return reinterpret_cast<Ptr *>(Data); }
const Ptr *getPointerAddress() const { return reinterpret_cast<Ptr *>(Data); }
private:
alignas(Ptr) unsigned char Data[sizeof(Ptr)];
};
} // namespace detail
template <typename T, typename Enable> struct DenseMapInfo;
template <typename PointerT, unsigned IntBits, typename PtrTraits>
struct PointerIntPairInfo;
@@ -46,7 +80,7 @@ template <typename PointerTy, unsigned IntBits, typename IntType = unsigned,
class PointerIntPair {
// Used by MSVC visualizer and generally helpful for debugging/visualizing.
using InfoTy = Info;
intptr_t Value = 0;
detail::PunnedPointer<PointerTy> Value;
public:
constexpr PointerIntPair() = default;
@@ -86,10 +120,12 @@ public:
assert(Value == reinterpret_cast<intptr_t>(getPointer()) &&
"Can only return the address if IntBits is cleared and "
"PtrTraits doesn't change the pointer");
return reinterpret_cast<PointerTy *>(&Value);
return Value.getPointerAddress();
}
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
void *getOpaqueValue() const {
return reinterpret_cast<void *>(Value.asInt());
}
void setFromOpaqueValue(void *Val) & {
Value = reinterpret_cast<intptr_t>(Val);

View File

@@ -217,9 +217,9 @@ public:
/// If the union is set to the first pointer type get an address pointing to
/// it.
First *getAddrOfPtr1() {
assert(is<First>() && "Val is not the first pointer");
assert(isa<First>(*this) && "Val is not the first pointer");
assert(
PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
PointerLikeTypeTraits<First>::getAsVoidPointer(cast<First>(*this)) ==
this->Val.getPointer() &&
"Can't get the address because PointerLikeTypeTraits changes the ptr");
return const_cast<First *>(
@@ -276,7 +276,7 @@ template <typename... PTs> struct CastInfoPointerUnionImpl {
}
template <typename To> static To doCast(From &F) {
assert(isPossible<To>(F) && "cast to an incompatible type !");
assert(isPossible<To>(F) && "cast to an incompatible type!");
return PointerLikeTypeTraits<To>::getFromVoidPointer(F.Val.getPointer());
}
};

View File

@@ -14,5 +14,5 @@ bool shouldReverseIterate() {
#endif
}
}
} // namespace wpi
#endif

View File

@@ -264,8 +264,9 @@ protected:
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
template <typename PtrTy>
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
DebugEpochBase::HandleBase {
class LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE SmallPtrSetIterator
: public SmallPtrSetIteratorImpl,
DebugEpochBase::HandleBase {
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
public:

View File

@@ -149,7 +149,9 @@ class SmallSet {
static_assert(N <= 32, "N should be small");
public:
using key_type = T;
using size_type = size_t;
using value_type = T;
using const_iterator = SmallSetIterator<T, N, C>;
SmallSet() = default;

View File

@@ -328,8 +328,8 @@ public:
/// copy these types with memcpy, there is no way for the type to observe this.
/// This catches the important case of std::pair<POD, POD>, which is not
/// trivially assignable.
template <typename T, bool = (is_trivially_copy_constructible<T>::value) &&
(is_trivially_move_constructible<T>::value) &&
template <typename T, bool = (std::is_trivially_copy_constructible<T>::value) &&
(std::is_trivially_move_constructible<T>::value) &&
std::is_trivially_destructible<T>::value>
class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
friend class SmallVectorTemplateCommon<T>;
@@ -1208,7 +1208,12 @@ public:
this->destroy_range(this->begin(), this->end());
}
explicit SmallVector(size_t Size, const T &Value = T())
explicit SmallVector(size_t Size)
: SmallVectorImpl<T>(N) {
this->resize(Size);
}
SmallVector(size_t Size, const T &Value)
: SmallVectorImpl<T>(N) {
this->assign(Size, Value);
}

View File

@@ -111,8 +111,9 @@ public:
/// funky memory allocation and hashing things to make it extremely efficient,
/// storing the string data *after* the value in the map.
template <typename ValueTy, typename AllocatorTy = MallocAllocator>
class StringMap : public StringMapImpl,
private detail::AllocatorHolder<AllocatorTy> {
class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
: public StringMapImpl,
private detail::AllocatorHolder<AllocatorTy> {
using AllocTy = detail::AllocatorHolder<AllocatorTy>;
public:
@@ -235,18 +236,29 @@ public:
/// lookup - Return the entry for the specified key, or a default
/// constructed value if no such entry exists.
ValueTy lookup(std::string_view Key) const {
const_iterator it = find(Key);
if (it != end())
return it->second;
const_iterator Iter = find(Key);
if (Iter != end())
return Iter->second;
return ValueTy();
}
/// at - Return the entry for the specified key, or abort if no such
/// entry exists.
const ValueTy &at(std::string_view Val) const {
auto Iter = this->find(std::move(Val));
assert(Iter != this->end() && "StringMap::at failed due to a missing key");
return Iter->second;
}
/// Lookup the ValueTy for the \p Key, or create a default constructed value
/// if the key is not in the map.
ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
/// contains - Return true if the element is in the map, false otherwise.
bool contains(std::string_view Key) const { return find(Key) != end(); }
/// 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 contains(Key) ? 1 : 0; }
template <typename InputTy>
size_type count(const StringMapEntry<InputTy> &MapEntry) const {

View File

@@ -46,16 +46,6 @@
namespace wpi {
/// ByteSwap_16 - This function returns a byte-swapped representation of
/// the 16-bit argument.
inline uint16_t ByteSwap_16(uint16_t value) { return wpi::byteswap(value); }
/// This function returns a byte-swapped representation of the 32-bit argument.
inline uint32_t ByteSwap_32(uint32_t value) { return wpi::byteswap(value); }
/// This function returns a byte-swapped representation of the 64-bit argument.
inline uint64_t ByteSwap_64(uint64_t value) { return wpi::byteswap(value); }
namespace sys {
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
@@ -103,7 +93,7 @@ inline double getSwappedBytes(double C) {
}
template <typename T>
inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
inline std::enable_if_t<std::is_enum_v<T>, T> getSwappedBytes(T C) {
return static_cast<T>(
wpi::byteswap(static_cast<std::underlying_type_t<T>>(C)));
}

View File

@@ -18,10 +18,22 @@
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
#define WPIUTIL_WPI_ITERATOR_RANGE_H
#include "wpi/ADL.h"
#include <type_traits>
#include <utility>
namespace wpi {
template <typename From, typename To, typename = void>
struct explicitly_convertible : std::false_type {};
template <typename From, typename To>
struct explicitly_convertible<
From, To,
std::void_t<decltype(static_cast<To>(
std::declval<std::add_rvalue_reference_t<From>>()))>> : std::true_type {
};
/// A range adaptor for a pair of iterators.
///
/// This just wraps two iterators into a range-compatible interface. Nothing
@@ -31,12 +43,19 @@ class iterator_range {
IteratorT begin_iterator, end_iterator;
public:
//TODO: Add SFINAE to test that the Container's iterators match the range's
// iterators.
#if __GNUC__ == 7
// Be careful no to break gcc-7 on the mlir target.
// See https://github.com/llvm/llvm-project/issues/63843
template <typename Container>
#else
template <typename Container,
std::enable_if_t<explicitly_convertible<
detail::IterOfRange<Container>, IteratorT>::value> * = nullptr>
#endif
iterator_range(Container &&c)
//TODO: Consider ADL/non-member begin/end calls.
: begin_iterator(c.begin()), end_iterator(c.end()) {}
: begin_iterator(adl_begin(std::forward<Container>(c))),
end_iterator(adl_end(std::forward<Container>(c))) {
}
iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
: begin_iterator(std::move(begin_iterator)),
end_iterator(std::move(end_iterator)) {}
@@ -46,6 +65,9 @@ public:
bool empty() const { return begin_iterator == end_iterator; }
};
template <typename Container>
iterator_range(Container &&) -> iterator_range<detail::IterOfRange<Container>>;
/// Convenience function for iterating over sub-ranges.
///
/// This provides a bit of syntactic sugar to make using sub-ranges

View File

@@ -387,8 +387,8 @@ private:
/// 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,
std::enable_if_t<!std::is_reference_v<OStream> &&
std::is_base_of_v<raw_ostream, OStream>,
OStream &&>
operator<<(OStream &&OS, const T &Value) {
OS << Value;

View File

@@ -32,11 +32,11 @@ template <typename T> class is_integral_or_enum {
public:
static const bool value =
!std::is_class<UnderlyingT>::value && // Filter conversion operators.
!std::is_pointer<UnderlyingT>::value &&
!std::is_floating_point<UnderlyingT>::value &&
(std::is_enum<UnderlyingT>::value ||
std::is_convertible<UnderlyingT, unsigned long long>::value);
!std::is_class_v<UnderlyingT> && // Filter conversion operators.
!std::is_pointer_v<UnderlyingT> &&
!std::is_floating_point_v<UnderlyingT> &&
(std::is_enum_v<UnderlyingT> ||
std::is_convertible_v<UnderlyingT, unsigned long long>);
};
/// If T is a pointer, just return it. If it is not, return T&.
@@ -45,7 +45,7 @@ struct add_lvalue_reference_if_not_pointer { using type = T &; };
template <typename T>
struct add_lvalue_reference_if_not_pointer<
T, std::enable_if_t<std::is_pointer<T>::value>> {
T, std::enable_if_t<std::is_pointer_v<T>>> {
using type = T;
};
@@ -55,7 +55,7 @@ template<typename T, typename Enable = void>
struct add_const_past_pointer { using type = const T; };
template <typename T>
struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer_v<T>>> {
using type = const std::remove_pointer_t<T> *;
};
@@ -64,27 +64,11 @@ struct const_pointer_or_const_ref {
using type = const T &;
};
template <typename T>
struct const_pointer_or_const_ref<T,
std::enable_if_t<std::is_pointer<T>::value>> {
struct const_pointer_or_const_ref<T, std::enable_if_t<std::is_pointer_v<T>>> {
using type = typename add_const_past_pointer<T>::type;
};
namespace detail {
/// Internal utility to detect trivial copy construction.
template<typename T> union copy_construction_triviality_helper {
T t;
copy_construction_triviality_helper() = default;
copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
~copy_construction_triviality_helper() = default;
};
/// Internal utility to detect trivial move construction.
template<typename T> union move_construction_triviality_helper {
T t;
move_construction_triviality_helper() = default;
move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
~move_construction_triviality_helper() = default;
};
template<class T>
union trivial_helper {
T t;
@@ -92,12 +76,6 @@ union trivial_helper {
} // end namespace detail
template <typename T>
using is_trivially_move_constructible = std::is_trivially_move_constructible<T>;
template <typename T>
using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
} // end namespace wpi
#endif // WPIUTIL_WPI_TYPE_TRAITS_H

View File

@@ -0,0 +1,56 @@
/*
xxHash - Extremely Fast Hash algorithm
Header File
Copyright (C) 2012-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- xxHash source repository : https://github.com/Cyan4973/xxHash
*/
/* based on revision d2df04efcbef7d7f6886d345861e5dfda4edacc1 Removed
* everything but a simple interface for computing XXh64. */
#ifndef WPIUTIL_WPI_XXHASH_H
#define WPIUTIL_WPI_XXHASH_H
#include <stdint.h>
#include <span>
#include <string_view>
namespace wpi {
uint64_t xxHash64(std::string_view Data);
uint64_t xxHash64(std::span<const uint8_t> Data);
uint64_t xxh3_64bits(std::span<const uint8_t> data);
inline uint64_t xxh3_64bits(std::string_view data) {
return xxh3_64bits(std::span(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
}
}
#endif