CachedHashString.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/ADT/CachedHashString.h - Prehashed string/StringRef -*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. ///
  14. /// \file
  15. /// This file defines CachedHashString and CachedHashStringRef. These are
  16. /// owning and not-owning string types that store their hash in addition to
  17. /// their string data.
  18. ///
  19. /// Unlike std::string, CachedHashString can be used in DenseSet/DenseMap
  20. /// (because, unlike std::string, CachedHashString lets us have empty and
  21. /// tombstone values).
  22. ///
  23. //===----------------------------------------------------------------------===//
  24. #ifndef LLVM_ADT_CACHEDHASHSTRING_H
  25. #define LLVM_ADT_CACHEDHASHSTRING_H
  26. #include "llvm/ADT/DenseMapInfo.h"
  27. #include "llvm/ADT/StringRef.h"
  28. namespace llvm {
  29. /// A container which contains a StringRef plus a precomputed hash.
  30. class CachedHashStringRef {
  31. const char *P;
  32. uint32_t Size;
  33. uint32_t Hash;
  34. public:
  35. // Explicit because hashing a string isn't free.
  36. explicit CachedHashStringRef(StringRef S)
  37. : CachedHashStringRef(S, DenseMapInfo<StringRef>::getHashValue(S)) {}
  38. CachedHashStringRef(StringRef S, uint32_t Hash)
  39. : P(S.data()), Size(S.size()), Hash(Hash) {
  40. assert(S.size() <= std::numeric_limits<uint32_t>::max());
  41. }
  42. StringRef val() const { return StringRef(P, Size); }
  43. const char *data() const { return P; }
  44. uint32_t size() const { return Size; }
  45. uint32_t hash() const { return Hash; }
  46. };
  47. template <> struct DenseMapInfo<CachedHashStringRef> {
  48. static CachedHashStringRef getEmptyKey() {
  49. return CachedHashStringRef(DenseMapInfo<StringRef>::getEmptyKey(), 0);
  50. }
  51. static CachedHashStringRef getTombstoneKey() {
  52. return CachedHashStringRef(DenseMapInfo<StringRef>::getTombstoneKey(), 1);
  53. }
  54. static unsigned getHashValue(const CachedHashStringRef &S) {
  55. assert(!isEqual(S, getEmptyKey()) && "Cannot hash the empty key!");
  56. assert(!isEqual(S, getTombstoneKey()) && "Cannot hash the tombstone key!");
  57. return S.hash();
  58. }
  59. static bool isEqual(const CachedHashStringRef &LHS,
  60. const CachedHashStringRef &RHS) {
  61. return LHS.hash() == RHS.hash() &&
  62. DenseMapInfo<StringRef>::isEqual(LHS.val(), RHS.val());
  63. }
  64. };
  65. /// A container which contains a string, which it owns, plus a precomputed hash.
  66. ///
  67. /// We do not null-terminate the string.
  68. class CachedHashString {
  69. friend struct DenseMapInfo<CachedHashString>;
  70. char *P;
  71. uint32_t Size;
  72. uint32_t Hash;
  73. static char *getEmptyKeyPtr() { return DenseMapInfo<char *>::getEmptyKey(); }
  74. static char *getTombstoneKeyPtr() {
  75. return DenseMapInfo<char *>::getTombstoneKey();
  76. }
  77. bool isEmptyOrTombstone() const {
  78. return P == getEmptyKeyPtr() || P == getTombstoneKeyPtr();
  79. }
  80. struct ConstructEmptyOrTombstoneTy {};
  81. CachedHashString(ConstructEmptyOrTombstoneTy, char *EmptyOrTombstonePtr)
  82. : P(EmptyOrTombstonePtr), Size(0), Hash(0) {
  83. assert(isEmptyOrTombstone());
  84. }
  85. // TODO: Use small-string optimization to avoid allocating.
  86. public:
  87. explicit CachedHashString(const char *S) : CachedHashString(StringRef(S)) {}
  88. // Explicit because copying and hashing a string isn't free.
  89. explicit CachedHashString(StringRef S)
  90. : CachedHashString(S, DenseMapInfo<StringRef>::getHashValue(S)) {}
  91. CachedHashString(StringRef S, uint32_t Hash)
  92. : P(new char[S.size()]), Size(S.size()), Hash(Hash) {
  93. memcpy(P, S.data(), S.size());
  94. }
  95. // Ideally this class would not be copyable. But SetVector requires copyable
  96. // keys, and we want this to be usable there.
  97. CachedHashString(const CachedHashString &Other)
  98. : Size(Other.Size), Hash(Other.Hash) {
  99. if (Other.isEmptyOrTombstone()) {
  100. P = Other.P;
  101. } else {
  102. P = new char[Size];
  103. memcpy(P, Other.P, Size);
  104. }
  105. }
  106. CachedHashString &operator=(CachedHashString Other) {
  107. swap(*this, Other);
  108. return *this;
  109. }
  110. CachedHashString(CachedHashString &&Other) noexcept
  111. : P(Other.P), Size(Other.Size), Hash(Other.Hash) {
  112. Other.P = getEmptyKeyPtr();
  113. }
  114. ~CachedHashString() {
  115. if (!isEmptyOrTombstone())
  116. delete[] P;
  117. }
  118. StringRef val() const { return StringRef(P, Size); }
  119. uint32_t size() const { return Size; }
  120. uint32_t hash() const { return Hash; }
  121. operator StringRef() const { return val(); }
  122. operator CachedHashStringRef() const {
  123. return CachedHashStringRef(val(), Hash);
  124. }
  125. friend void swap(CachedHashString &LHS, CachedHashString &RHS) {
  126. using std::swap;
  127. swap(LHS.P, RHS.P);
  128. swap(LHS.Size, RHS.Size);
  129. swap(LHS.Hash, RHS.Hash);
  130. }
  131. };
  132. template <> struct DenseMapInfo<CachedHashString> {
  133. static CachedHashString getEmptyKey() {
  134. return CachedHashString(CachedHashString::ConstructEmptyOrTombstoneTy(),
  135. CachedHashString::getEmptyKeyPtr());
  136. }
  137. static CachedHashString getTombstoneKey() {
  138. return CachedHashString(CachedHashString::ConstructEmptyOrTombstoneTy(),
  139. CachedHashString::getTombstoneKeyPtr());
  140. }
  141. static unsigned getHashValue(const CachedHashString &S) {
  142. assert(!isEqual(S, getEmptyKey()) && "Cannot hash the empty key!");
  143. assert(!isEqual(S, getTombstoneKey()) && "Cannot hash the tombstone key!");
  144. return S.hash();
  145. }
  146. static bool isEqual(const CachedHashString &LHS,
  147. const CachedHashString &RHS) {
  148. if (LHS.hash() != RHS.hash())
  149. return false;
  150. if (LHS.P == CachedHashString::getEmptyKeyPtr())
  151. return RHS.P == CachedHashString::getEmptyKeyPtr();
  152. if (LHS.P == CachedHashString::getTombstoneKeyPtr())
  153. return RHS.P == CachedHashString::getTombstoneKeyPtr();
  154. // This is safe because if RHS.P is the empty or tombstone key, it will have
  155. // length 0, so we'll never dereference its pointer.
  156. return LHS.val() == RHS.val();
  157. }
  158. };
  159. } // namespace llvm
  160. #endif
  161. #ifdef __GNUC__
  162. #pragma GCC diagnostic pop
  163. #endif