spy_hash_state.h
Go to the documentation of this file.
1 // Copyright 2018 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
16 #define ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
17 
18 #include <ostream>
19 #include <string>
20 #include <vector>
21 
22 #include "absl/hash/hash.h"
23 #include "absl/strings/match.h"
25 #include "absl/strings/str_join.h"
26 
27 namespace absl {
28 namespace hash_internal {
29 
30 // SpyHashState is an implementation of the HashState API that simply
31 // accumulates all input bytes in an internal buffer. This makes it useful
32 // for testing AbslHashValue overloads (so long as they are templated on the
33 // HashState parameter), since it can report the exact hash representation
34 // that the AbslHashValue overload produces.
35 //
36 // Sample usage:
37 // EXPECT_EQ(SpyHashState::combine(SpyHashState(), foo),
38 // SpyHashState::combine(SpyHashState(), bar));
39 template <typename T>
40 class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
41  public:
42  SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) {
43  static_assert(std::is_void<T>::value, "");
44  }
45 
46  // Move-only
47  SpyHashStateImpl(const SpyHashStateImpl&) = delete;
49 
50  SpyHashStateImpl(SpyHashStateImpl&& other) noexcept {
51  *this = std::move(other);
52  }
53 
55  hash_representation_ = std::move(other.hash_representation_);
56  error_ = other.error_;
57  moved_from_ = other.moved_from_;
58  other.moved_from_ = true;
59  return *this;
60  }
61 
62  template <typename U>
64  hash_representation_ = std::move(other.hash_representation_);
65  error_ = other.error_;
66  moved_from_ = other.moved_from_;
67  other.moved_from_ = true;
68  }
69 
70  template <typename A, typename... Args>
72  const Args&... args) {
73  // Pass an instance of SpyHashStateImpl<A> when trying to combine `A`. This
74  // allows us to test that the user only uses this instance for combine calls
75  // and does not call AbslHashValue directly.
76  // See AbslHashValue implementation at the bottom.
78  return SpyHashStateImpl::combine(std::move(s), args...);
79  }
82  *s.error_ = "AbslHashValue should not be invoked directly.";
83  } else if (s.moved_from_) {
84  *s.error_ = "Used moved-from instance of the hash state object.";
85  }
86  return s;
87  }
88 
91  }
92 
93  // Two SpyHashStateImpl objects are equal if they hold equal hash
94  // representations.
95  friend bool operator==(const SpyHashStateImpl& lhs,
96  const SpyHashStateImpl& rhs) {
98  }
99 
100  friend bool operator!=(const SpyHashStateImpl& lhs,
101  const SpyHashStateImpl& rhs) {
102  return !(lhs == rhs);
103  }
104 
105  enum class CompareResult {
106  kEqual,
107  kASuffixB,
108  kBSuffixA,
109  kUnequal,
110  };
111 
113  const SpyHashStateImpl& b) {
114  const std::string a_flat = absl::StrJoin(a.hash_representation_, "");
115  const std::string b_flat = absl::StrJoin(b.hash_representation_, "");
116  if (a_flat == b_flat) return CompareResult::kEqual;
117  if (absl::EndsWith(a_flat, b_flat)) return CompareResult::kBSuffixA;
118  if (absl::EndsWith(b_flat, a_flat)) return CompareResult::kASuffixB;
120  }
121 
122  // operator<< prints the hash representation as a hex and ASCII dump, to
123  // facilitate debugging.
124  friend std::ostream& operator<<(std::ostream& out,
125  const SpyHashStateImpl& hash_state) {
126  out << "[\n";
127  for (auto& s : hash_state.hash_representation_) {
128  size_t offset = 0;
129  for (char c : s) {
130  if (offset % 16 == 0) {
131  out << absl::StreamFormat("\n0x%04x: ", offset);
132  }
133  if (offset % 2 == 0) {
134  out << " ";
135  }
136  out << absl::StreamFormat("%02x", c);
137  ++offset;
138  }
139  out << "\n";
140  }
141  return out << "]";
142  }
143 
144  // The base case of the combine recursion, which writes raw bytes into the
145  // internal buffer.
147  const unsigned char* begin,
148  size_t size) {
149  hash_state.hash_representation_.emplace_back(
150  reinterpret_cast<const char*>(begin), size);
151  return hash_state;
152  }
153 
154  using SpyHashStateImpl::HashStateBase::combine_contiguous;
155 
157  if (moved_from_) {
158  return "Returned a moved-from instance of the hash state object.";
159  }
160  return *error_;
161  }
162 
163  private:
164  template <typename U>
165  friend class SpyHashStateImpl;
166 
167  // This is true if SpyHashStateImpl<T> has been passed to a call of
168  // AbslHashValue with the wrong type. This detects that the user called
169  // AbslHashValue directly (because the hash state type does not match).
171 
172  std::vector<std::string> hash_representation_;
173  // This is a shared_ptr because we want all instances of the particular
174  // SpyHashState run to share the field. This way we can set the error for
175  // use-after-move and all the copies will see it.
176  std::shared_ptr<absl::optional<std::string>> error_;
177  bool moved_from_ = false;
178 };
179 
180 template <typename T>
182 
183 template <bool& B>
184 struct OdrUse {
185  constexpr OdrUse() {}
186  bool& b = B;
187 };
188 
189 template <void (*)()>
190 struct RunOnStartup {
191  static bool run;
192  static constexpr OdrUse<run> kOdrUse{};
193 };
194 
195 template <void (*f)()>
196 bool RunOnStartup<f>::run = (f(), true);
197 
198 template <
199  typename T, typename U,
200  // Only trigger for when (T != U),
202  // This statement works in two ways:
203  // - First, it instantiates RunOnStartup and forces the initialization of
204  // `run`, which set the global variable.
205  // - Second, it triggers a SFINAE error disabling the overload to prevent
206  // compile time errors. If we didn't disable the overload we would get
207  // ambiguous overload errors, which we don't want.
209 void AbslHashValue(SpyHashStateImpl<T>, const U&);
210 
212 
213 } // namespace hash_internal
214 } // namespace absl
215 
216 #endif // ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
SpyHashStateImpl(SpyHashStateImpl &&other) noexcept
friend bool operator==(const SpyHashStateImpl &lhs, const SpyHashStateImpl &rhs)
absl::optional< std::string > error() const
std::vector< std::string > hash_representation_
std::enable_if< std::is_same< B, bool >::value, H >::type AbslHashValue(H hash_state, B value)
static SpyHashStateImpl combine(SpyHashStateImpl s)
SpyHashStateImpl(SpyHashStateImpl< U > &&other)
char * begin
std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, Formatter &&fmt)
Definition: str_join.h:244
ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat(const FormatSpec< Args... > &format, const Args &... args)
Definition: str_format.h:342
friend std::ostream & operator<<(std::ostream &out, const SpyHashStateImpl &hash_state)
Definition: algorithm.h:29
typename std::enable_if< B, T >::type enable_if_t
Definition: type_traits.h:547
bool EndsWith(absl::string_view text, absl::string_view suffix)
Definition: match.h:61
friend bool operator!=(const SpyHashStateImpl &lhs, const SpyHashStateImpl &rhs)
size_t value
uintptr_t size
SpyHashStateImpl & operator=(SpyHashStateImpl &&other) noexcept
std::shared_ptr< absl::optional< std::string > > error_
static SpyHashStateImpl combine(SpyHashStateImpl s, const A &a, const Args &... args)
SpyHashStateImpl & operator=(const SpyHashStateImpl &)=delete
static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state, const unsigned char *begin, size_t size)
uint64_t b
Definition: layout_test.cc:50
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: utility.h:219
char * out
Definition: mutex.h:1013
static CompareResult Compare(const SpyHashStateImpl &a, const SpyHashStateImpl &b)


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:20