abseil-cpp/absl/hash/internal/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 <algorithm>
19 #include <ostream>
20 #include <string>
21 #include <vector>
22 
23 #include "absl/hash/hash.h"
24 #include "absl/strings/match.h"
25 #include "absl/strings/str_format.h"
26 #include "absl/strings/str_join.h"
27 
28 namespace absl {
30 namespace hash_internal {
31 
32 // SpyHashState is an implementation of the HashState API that simply
33 // accumulates all input bytes in an internal buffer. This makes it useful
34 // for testing AbslHashValue overloads (so long as they are templated on the
35 // HashState parameter), since it can report the exact hash representation
36 // that the AbslHashValue overload produces.
37 //
38 // Sample usage:
39 // EXPECT_EQ(SpyHashState::combine(SpyHashState(), foo),
40 // SpyHashState::combine(SpyHashState(), bar));
41 template <typename T>
42 class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
43  public:
44  SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) {
45  static_assert(std::is_void<T>::value, "");
46  }
47 
48  // Move-only
49  SpyHashStateImpl(const SpyHashStateImpl&) = delete;
51 
52  SpyHashStateImpl(SpyHashStateImpl&& other) noexcept {
53  *this = std::move(other);
54  }
55 
57  hash_representation_ = std::move(other.hash_representation_);
58  error_ = other.error_;
59  moved_from_ = other.moved_from_;
60  other.moved_from_ = true;
61  return *this;
62  }
63 
64  template <typename U>
66  hash_representation_ = std::move(other.hash_representation_);
67  error_ = other.error_;
68  moved_from_ = other.moved_from_;
69  other.moved_from_ = true;
70  }
71 
72  template <typename A, typename... Args>
74  const Args&... args) {
75  // Pass an instance of SpyHashStateImpl<A> when trying to combine `A`. This
76  // allows us to test that the user only uses this instance for combine calls
77  // and does not call AbslHashValue directly.
78  // See AbslHashValue implementation at the bottom.
81  }
84  *s.error_ = "AbslHashValue should not be invoked directly.";
85  } else if (s.moved_from_) {
86  *s.error_ = "Used moved-from instance of the hash state object.";
87  }
88  return s;
89  }
90 
93  }
94 
95  // Two SpyHashStateImpl objects are equal if they hold equal hash
96  // representations.
97  friend bool operator==(const SpyHashStateImpl& lhs,
98  const SpyHashStateImpl& rhs) {
100  }
101 
102  friend bool operator!=(const SpyHashStateImpl& lhs,
103  const SpyHashStateImpl& rhs) {
104  return !(lhs == rhs);
105  }
106 
107  enum class CompareResult {
108  kEqual,
109  kASuffixB,
110  kBSuffixA,
111  kUnequal,
112  };
113 
115  const SpyHashStateImpl& b) {
116  const std::string a_flat = absl::StrJoin(a.hash_representation_, "");
117  const std::string b_flat = absl::StrJoin(b.hash_representation_, "");
118  if (a_flat == b_flat) return CompareResult::kEqual;
119  if (absl::EndsWith(a_flat, b_flat)) return CompareResult::kBSuffixA;
120  if (absl::EndsWith(b_flat, a_flat)) return CompareResult::kASuffixB;
122  }
123 
124  // operator<< prints the hash representation as a hex and ASCII dump, to
125  // facilitate debugging.
126  friend std::ostream& operator<<(std::ostream& out,
127  const SpyHashStateImpl& hash_state) {
128  out << "[\n";
129  for (auto& s : hash_state.hash_representation_) {
130  size_t offset = 0;
131  for (char c : s) {
132  if (offset % 16 == 0) {
133  out << absl::StreamFormat("\n0x%04x: ", offset);
134  }
135  if (offset % 2 == 0) {
136  out << " ";
137  }
138  out << absl::StreamFormat("%02x", c);
139  ++offset;
140  }
141  out << "\n";
142  }
143  return out << "]";
144  }
145 
146  // The base case of the combine recursion, which writes raw bytes into the
147  // internal buffer.
149  const unsigned char* begin,
150  size_t size) {
151  const size_t large_chunk_stride = PiecewiseChunkSize();
152  if (size > large_chunk_stride) {
153  // Combining a large contiguous buffer must have the same effect as
154  // doing it piecewise by the stride length, followed by the (possibly
155  // empty) remainder.
156  while (size >= large_chunk_stride) {
158  std::move(hash_state), begin, large_chunk_stride);
159  begin += large_chunk_stride;
160  size -= large_chunk_stride;
161  }
162  }
163 
164  hash_state.hash_representation_.emplace_back(
165  reinterpret_cast<const char*>(begin), size);
166  return hash_state;
167  }
168 
169  using SpyHashStateImpl::HashStateBase::combine_contiguous;
170 
171  template <typename CombinerT>
173  CombinerT combiner) {
175 
176  combiner(SpyHashStateImpl<void>{}, std::ref(cb));
177 
178  std::sort(cb.element_hash_representations.begin(),
179  cb.element_hash_representations.end());
180  state.hash_representation_.insert(state.hash_representation_.end(),
181  cb.element_hash_representations.begin(),
182  cb.element_hash_representations.end());
183  if (cb.error && cb.error->has_value()) {
184  state.error_ = std::move(cb.error);
185  }
186  return state;
187  }
188 
190  if (moved_from_) {
191  return "Returned a moved-from instance of the hash state object.";
192  }
193  return *error_;
194  }
195 
196  private:
197  template <typename U>
198  friend class SpyHashStateImpl;
199 
201  std::vector<std::string> element_hash_representations;
202  std::shared_ptr<absl::optional<std::string>> error;
203 
204  // The inner spy can have a different type.
205  template <typename U>
209  if (inner.error_->has_value()) {
210  error = std::move(inner.error_);
211  }
212  inner = SpyHashStateImpl<void>{};
213  }
214  };
215 
216  // This is true if SpyHashStateImpl<T> has been passed to a call of
217  // AbslHashValue with the wrong type. This detects that the user called
218  // AbslHashValue directly (because the hash state type does not match).
220 
221  std::vector<std::string> hash_representation_;
222  // This is a shared_ptr because we want all instances of the particular
223  // SpyHashState run to share the field. This way we can set the error for
224  // use-after-move and all the copies will see it.
225  std::shared_ptr<absl::optional<std::string>> error_;
226  bool moved_from_ = false;
227 };
228 
229 template <typename T>
231 
232 template <bool& B>
233 struct OdrUse {
234  constexpr OdrUse() {}
235  bool& b = B;
236 };
237 
238 template <void (*)()>
239 struct RunOnStartup {
240  static bool run;
241  static constexpr OdrUse<run> kOdrUse{};
242 };
243 
244 template <void (*f)()>
245 bool RunOnStartup<f>::run = (f(), true);
246 
247 template <
248  typename T, typename U,
249  // Only trigger for when (T != U),
251  // This statement works in two ways:
252  // - First, it instantiates RunOnStartup and forces the initialization of
253  // `run`, which set the global variable.
254  // - Second, it triggers a SFINAE error disabling the overload to prevent
255  // compile time errors. If we didn't disable the overload we would get
256  // ambiguous overload errors, which we don't want.
257  int = RunOnStartup<SpyHashStateImpl<T>::SetDirectAbslHashValueError>::run>
258 void AbslHashValue(SpyHashStateImpl<T>, const U&);
259 
261 
262 } // namespace hash_internal
264 } // namespace absl
265 
266 #endif // ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
absl::hash_internal::SpyHashStateImpl
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:42
absl::hash_internal::SpyHashStateImpl::SetDirectAbslHashValueError
static void SetDirectAbslHashValueError()
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:91
absl::hash_internal::OdrUse::OdrUse
constexpr OdrUse()
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:234
absl::hash_internal::SpyHashStateImpl::combine
static SpyHashStateImpl combine(SpyHashStateImpl s, const A &a, const Args &... args)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:73
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::hash_internal::SpyHashStateImpl::error
absl::optional< std::string > error() const
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:189
absl::hash_internal::SpyHashStateImpl::UnorderedCombinerCallback::operator()
void operator()(SpyHashStateImpl< U > &inner)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:206
absl::hash_internal::SpyHashStateImpl::RunCombineUnordered
static SpyHashStateImpl RunCombineUnordered(SpyHashStateImpl state, CombinerT combiner)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:172
absl::hash_internal::RunOnStartup::kOdrUse
static constexpr OdrUse< run > kOdrUse
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:241
absl::enable_if_t
typename std::enable_if< B, T >::type enable_if_t
Definition: abseil-cpp/absl/meta/type_traits.h:631
absl::FormatConversionChar::s
@ s
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::hash_internal::SpyHashStateImpl::UnorderedCombinerCallback
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:200
T
#define T(upbtypeconst, upbtype, ctype, default_value)
absl::hash_internal::RunOnStartup::run
static bool run
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:240
absl::hash_internal::SpyHashStateImpl::operator=
SpyHashStateImpl & operator=(const SpyHashStateImpl &)=delete
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
absl::StrJoin
std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, Formatter &&fmt)
Definition: abseil-cpp/absl/strings/str_join.h:239
hpack_encoder_fixtures::Args
Args({0, 16384})
absl::hash_internal::SpyHashStateImpl::operator==
friend bool operator==(const SpyHashStateImpl &lhs, const SpyHashStateImpl &rhs)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:97
absl::hash_internal::OdrUse::b
bool & b
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:235
absl::optional
Definition: abseil-cpp/absl/types/internal/optional.h:61
ref
unsigned ref
Definition: cxa_demangle.cpp:4909
absl::hash_internal::SpyHashStateImpl::direct_absl_hash_value_error_
static bool direct_absl_hash_value_error_
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:219
absl::hash_internal::RunOnStartup
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:239
absl::StreamFormat
ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat(const FormatSpec< Args... > &format, const Args &... args)
Definition: abseil-cpp/absl/strings/str_format.h:375
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
absl::hash_internal::SpyHashStateImpl::operator!=
friend bool operator!=(const SpyHashStateImpl &lhs, const SpyHashStateImpl &rhs)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:102
absl::hash_internal::OdrUse
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:233
absl::hash_internal::SpyHashStateImpl::UnorderedCombinerCallback::element_hash_representations
std::vector< std::string > element_hash_representations
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:201
absl::hash_internal::AbslHashValue
std::enable_if< std::is_same< B, bool >::value, H >::type AbslHashValue(H hash_state, B value)
Definition: abseil-cpp/absl/hash/internal/hash.h:344
value
const char * value
Definition: hpack_parser_table.cc:165
absl::hash_internal::SpyHashStateImpl::SpyHashStateImpl
SpyHashStateImpl(SpyHashStateImpl< U > &&other)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:65
absl::hash_internal::PiecewiseChunkSize
constexpr size_t PiecewiseChunkSize()
Definition: abseil-cpp/absl/hash/internal/hash.h:67
absl::hash_internal::SpyHashStateImpl::CompareResult::kBSuffixA
@ kBSuffixA
client.run
def run()
Definition: examples/python/async_streaming/client.py:109
absl::hash_internal::SpyHashStateImpl::moved_from_
bool moved_from_
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:226
absl::hash_internal::SpyHashStateImpl::CompareResult
CompareResult
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:107
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
absl::hash_internal::SpyHashStateImpl::combine_contiguous
static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state, const unsigned char *begin, size_t size)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:148
absl::hash_internal::SpyHashStateImpl::CompareResult::kUnequal
@ kUnequal
A
Definition: miscompile_with_no_unique_address_test.cc:23
absl::hash_internal::SpyHashStateImpl::Compare
static CompareResult Compare(const SpyHashStateImpl &a, const SpyHashStateImpl &b)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:114
absl::hash_internal::SpyHashStateImpl::CompareResult::kASuffixB
@ kASuffixB
state
Definition: bloaty/third_party/zlib/contrib/blast/blast.c:41
absl::hash_internal::SpyHashStateImpl::operator<<
friend std::ostream & operator<<(std::ostream &out, const SpyHashStateImpl &hash_state)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:126
absl::hash_internal::SpyHashStateImpl::SpyHashStateImpl
friend class SpyHashStateImpl
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:198
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::hash_internal::SpyHashStateImpl::combine
static SpyHashStateImpl combine(SpyHashStateImpl s)
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:82
absl::out
char * out
Definition: abseil-cpp/absl/synchronization/mutex.h:1048
absl::hash_internal::SpyHashStateImpl::CompareResult::kEqual
@ kEqual
absl::hash_internal::SpyHashStateImpl::operator=
SpyHashStateImpl & operator=(SpyHashStateImpl &&other) noexcept
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:56
absl::hash_internal::SpyHashStateImpl::error_
std::shared_ptr< absl::optional< std::string > > error_
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:225
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
absl::hash_internal::HashStateBase
Definition: abseil-cpp/absl/hash/internal/hash.h:198
absl::hash_internal::SpyHashStateImpl::UnorderedCombinerCallback::error
std::shared_ptr< absl::optional< std::string > > error
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:202
absl::EndsWith
bool EndsWith(absl::string_view text, absl::string_view suffix) noexcept
Definition: third_party/abseil-cpp/absl/strings/match.h:68
cb
OPENSSL_EXPORT pem_password_cb * cb
Definition: pem.h:351
absl::hash_internal::SpyHashStateImpl::hash_representation_
std::vector< std::string > hash_representation_
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:221
state
static struct rpc_state state
Definition: bad_server_response_test.cc:87
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
absl::hash_internal::SpyHashStateImpl::SpyHashStateImpl
SpyHashStateImpl()
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:44
absl::hash_internal::SpyHashStateImpl::SpyHashStateImpl
SpyHashStateImpl(SpyHashStateImpl &&other) noexcept
Definition: abseil-cpp/absl/hash/internal/spy_hash_state.h:52


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:15