123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- 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 empty and
- /// tombstone values).
- ///
- //===----------------------------------------------------------------------===//
- #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 CachedHashStringRef getEmptyKey() {
- return CachedHashStringRef(DenseMapInfo<StringRef>::getEmptyKey(), 0);
- }
- static CachedHashStringRef getTombstoneKey() {
- return CachedHashStringRef(DenseMapInfo<StringRef>::getTombstoneKey(), 1);
- }
- static unsigned getHashValue(const CachedHashStringRef &S) {
- assert(!isEqual(S, getEmptyKey()) && "Cannot hash the empty key!");
- assert(!isEqual(S, getTombstoneKey()) && "Cannot hash the tombstone key!");
- 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() { return DenseMapInfo<char *>::getEmptyKey(); }
- static char *getTombstoneKeyPtr() {
- return DenseMapInfo<char *>::getTombstoneKey();
- }
- bool isEmptyOrTombstone() const {
- return P == getEmptyKeyPtr() || P == getTombstoneKeyPtr();
- }
- struct ConstructEmptyOrTombstoneTy {};
- CachedHashString(ConstructEmptyOrTombstoneTy, char *EmptyOrTombstonePtr)
- : P(EmptyOrTombstonePtr), Size(0), Hash(0) {
- assert(isEmptyOrTombstone());
- }
- // 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.isEmptyOrTombstone()) {
- 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 (!isEmptyOrTombstone())
- 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 CachedHashString getEmptyKey() {
- return CachedHashString(CachedHashString::ConstructEmptyOrTombstoneTy(),
- CachedHashString::getEmptyKeyPtr());
- }
- static CachedHashString getTombstoneKey() {
- return CachedHashString(CachedHashString::ConstructEmptyOrTombstoneTy(),
- CachedHashString::getTombstoneKeyPtr());
- }
- static unsigned getHashValue(const CachedHashString &S) {
- assert(!isEqual(S, getEmptyKey()) && "Cannot hash the empty key!");
- assert(!isEqual(S, getTombstoneKey()) && "Cannot hash the tombstone key!");
- 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();
- if (LHS.P == CachedHashString::getTombstoneKeyPtr())
- return RHS.P == CachedHashString::getTombstoneKeyPtr();
- // This is safe because if RHS.P is the empty or tombstone key, it will have
- // length 0, so we'll never dereference its pointer.
- return LHS.val() == RHS.val();
- }
- };
- } // namespace llvm
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|