raw_hashtable_test_helpers.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_COMMON_RAW_HASHTABLE_TEST_HELPERS_H_
  5. #define CARBON_COMMON_RAW_HASHTABLE_TEST_HELPERS_H_
  6. #include <compare>
  7. #include "common/check.h"
  8. #include "common/hashing.h"
  9. #include "common/hashtable_key_context.h"
  10. #include "common/ostream.h"
  11. namespace Carbon::RawHashtable {
  12. // Non-trivial type for testing.
  13. struct TestData : Printable<TestData> {
  14. int value;
  15. // NOLINTNEXTLINE: google-explicit-constructor
  16. TestData(int v) : value(v) { CARBON_CHECK(value >= 0); }
  17. ~TestData() {
  18. CARBON_CHECK(value >= 0);
  19. value = -1;
  20. }
  21. TestData(const TestData& other) : TestData(other.value) {}
  22. TestData(TestData&& other) noexcept : TestData(other.value) {
  23. other.value = 0;
  24. }
  25. auto Print(llvm::raw_ostream& out) const -> void { out << value; }
  26. friend auto operator==(TestData lhs, TestData rhs) -> bool {
  27. return lhs.value == rhs.value;
  28. }
  29. friend auto operator<=>(TestData lhs, TestData rhs) -> std::strong_ordering {
  30. return lhs.value <=> rhs.value;
  31. }
  32. friend auto CarbonHashValue(TestData data, uint64_t seed) -> HashCode {
  33. return Carbon::HashValue(data.value, seed);
  34. }
  35. };
  36. // Test stateless key context that produces different hashes from normal.
  37. // Changing the hash values should result in test failures if the context ever
  38. // fails to be used.
  39. struct TestKeyContext : DefaultKeyContext {
  40. template <typename KeyT>
  41. auto HashKey(const KeyT& key, uint64_t seed) const -> HashCode {
  42. Hasher hash(seed);
  43. // Inject some other data to the hash.
  44. hash.HashRaw(42);
  45. hash.HashRaw(HashValue(key));
  46. return static_cast<HashCode>(hash);
  47. }
  48. };
  49. // Hostile fixed hashing key context used for stress testing. Allows control
  50. // over which parts of the hash will be forced to collide, and the values they
  51. // are coerced to. Note that this relies on implementation details and internals
  52. // of `HashCode`.
  53. template <int TagBits, bool FixIndexBits, bool FixTagBits, uint64_t FixedVal>
  54. struct FixedHashKeyContext : DefaultKeyContext {
  55. template <typename KeyT>
  56. auto HashKey(const KeyT& key, uint64_t seed) const -> HashCode {
  57. HashCode original_hash = HashValue(key, seed);
  58. auto raw_hash = static_cast<uint64_t>(original_hash);
  59. constexpr uint64_t TagMask = (1U << TagBits) - 1;
  60. if (FixIndexBits) {
  61. raw_hash &= TagMask;
  62. raw_hash |= FixedVal << TagBits;
  63. CARBON_DCHECK(HashCode(raw_hash).ExtractIndexAndTag<TagBits>().first ==
  64. (FixedVal & (~static_cast<uint64_t>(0) >> TagBits)));
  65. }
  66. if (FixTagBits) {
  67. raw_hash &= ~TagMask;
  68. raw_hash |= FixedVal & TagMask;
  69. CARBON_DCHECK(HashCode(raw_hash).ExtractIndexAndTag<TagBits>().second ==
  70. (FixedVal & TagMask));
  71. }
  72. return HashCode(raw_hash);
  73. }
  74. };
  75. template <typename T>
  76. class IndexKeyContext : public TranslatingKeyContext<IndexKeyContext<T>> {
  77. using Base = TranslatingKeyContext<IndexKeyContext>;
  78. public:
  79. explicit IndexKeyContext(llvm::ArrayRef<T> array) : array_(array) {}
  80. auto TranslateKey(ssize_t index) const -> const T& { return array_[index]; }
  81. // Override the CRTP approach when we have two indices as we can optimize that
  82. // approach.
  83. using Base::KeyEq;
  84. auto KeyEq(ssize_t lhs_index, ssize_t rhs_index) const -> bool {
  85. // No need to compare the elements, if the indices are equal, the values
  86. // must be.
  87. return lhs_index == rhs_index;
  88. }
  89. private:
  90. llvm::ArrayRef<T> array_;
  91. };
  92. } // namespace Carbon::RawHashtable
  93. #endif // CARBON_COMMON_RAW_HASHTABLE_TEST_HELPERS_H_