Files
gps/tools/local/circt/include/llvm/ADT/CachedHashString.h
T
2026-07-12 11:01:51 +03:00

154 lines
4.6 KiB
C++

//===- llvm/ADT/CachedHashString.h - Prehashed string/StringRef -*- 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 CachedHashString and CachedHashStringRef. These are
/// owning and not-owning string types that store their hash in addition to
/// their string data.
///
/// Unlike std::string, CachedHashString can be used in DenseSet/DenseMap
/// (because, unlike std::string, CachedHashString lets us have an empty
/// value).
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_CACHEDHASHSTRING_H
#define LLVM_ADT_CACHEDHASHSTRING_H
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
/// A container which contains a StringRef plus a precomputed hash.
class CachedHashStringRef {
const char *P;
uint32_t Size;
uint32_t Hash;
public:
// Explicit because hashing a string isn't free.
explicit CachedHashStringRef(StringRef S)
: CachedHashStringRef(S, DenseMapInfo<StringRef>::getHashValue(S)) {}
CachedHashStringRef(StringRef S, uint32_t Hash)
: P(S.data()), Size(S.size()), Hash(Hash) {
assert(S.size() <= std::numeric_limits<uint32_t>::max());
}
StringRef val() const { return StringRef(P, Size); }
const char *data() const { return P; }
uint32_t size() const { return Size; }
uint32_t hash() const { return Hash; }
};
template <> struct DenseMapInfo<CachedHashStringRef> {
static unsigned getHashValue(const CachedHashStringRef &S) {
return S.hash();
}
static bool isEqual(const CachedHashStringRef &LHS,
const CachedHashStringRef &RHS) {
return LHS.hash() == RHS.hash() &&
DenseMapInfo<StringRef>::isEqual(LHS.val(), RHS.val());
}
};
/// A container which contains a string, which it owns, plus a precomputed hash.
///
/// We do not null-terminate the string.
class CachedHashString {
friend struct DenseMapInfo<CachedHashString>;
char *P;
uint32_t Size;
uint32_t Hash;
static char *getEmptyKeyPtr() {
// Assume no pointer requires more than 4096 (1 << 12) bytes of alignment.
return reinterpret_cast<char *>(static_cast<uintptr_t>(-1) << 12);
}
bool isEmpty() const { return P == getEmptyKeyPtr(); }
// TODO: Use small-string optimization to avoid allocating.
public:
explicit CachedHashString(const char *S) : CachedHashString(StringRef(S)) {}
// Explicit because copying and hashing a string isn't free.
explicit CachedHashString(StringRef S)
: CachedHashString(S, DenseMapInfo<StringRef>::getHashValue(S)) {}
CachedHashString(StringRef S, uint32_t Hash)
: P(new char[S.size()]), Size(S.size()), Hash(Hash) {
memcpy(P, S.data(), S.size());
}
// Ideally this class would not be copyable. But SetVector requires copyable
// keys, and we want this to be usable there.
CachedHashString(const CachedHashString &Other)
: Size(Other.Size), Hash(Other.Hash) {
if (Other.isEmpty()) {
P = Other.P;
} else {
P = new char[Size];
memcpy(P, Other.P, Size);
}
}
CachedHashString &operator=(CachedHashString Other) {
swap(*this, Other);
return *this;
}
CachedHashString(CachedHashString &&Other) noexcept
: P(Other.P), Size(Other.Size), Hash(Other.Hash) {
Other.P = getEmptyKeyPtr();
}
~CachedHashString() {
if (!isEmpty())
delete[] P;
}
StringRef val() const { return StringRef(P, Size); }
uint32_t size() const { return Size; }
uint32_t hash() const { return Hash; }
operator StringRef() const { return val(); }
operator CachedHashStringRef() const {
return CachedHashStringRef(val(), Hash);
}
friend void swap(CachedHashString &LHS, CachedHashString &RHS) {
using std::swap;
swap(LHS.P, RHS.P);
swap(LHS.Size, RHS.Size);
swap(LHS.Hash, RHS.Hash);
}
};
template <> struct DenseMapInfo<CachedHashString> {
static unsigned getHashValue(const CachedHashString &S) { return S.hash(); }
static bool isEqual(const CachedHashString &LHS,
const CachedHashString &RHS) {
if (LHS.hash() != RHS.hash())
return false;
if (LHS.P == CachedHashString::getEmptyKeyPtr())
return RHS.P == CachedHashString::getEmptyKeyPtr();
// This is safe because if RHS.P is the empty key, it will have length 0, so
// we'll never dereference its pointer.
return LHS.val() == RHS.val();
}
};
} // namespace llvm
#endif