File indexing completed on 2025-01-18 09:27:18
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
0016 #define ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
0017
0018 #include <algorithm>
0019 #include <ostream>
0020 #include <string>
0021 #include <vector>
0022
0023 #include "absl/hash/hash.h"
0024 #include "absl/strings/match.h"
0025 #include "absl/strings/str_format.h"
0026 #include "absl/strings/str_join.h"
0027
0028 namespace absl {
0029 ABSL_NAMESPACE_BEGIN
0030 namespace hash_internal {
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 template <typename T>
0042 class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
0043 public:
0044 SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) {
0045 static_assert(std::is_void<T>::value, "");
0046 }
0047
0048
0049 SpyHashStateImpl(const SpyHashStateImpl&) = delete;
0050 SpyHashStateImpl& operator=(const SpyHashStateImpl&) = delete;
0051
0052 SpyHashStateImpl(SpyHashStateImpl&& other) noexcept {
0053 *this = std::move(other);
0054 }
0055
0056 SpyHashStateImpl& operator=(SpyHashStateImpl&& other) noexcept {
0057 hash_representation_ = std::move(other.hash_representation_);
0058 error_ = other.error_;
0059 moved_from_ = other.moved_from_;
0060 other.moved_from_ = true;
0061 return *this;
0062 }
0063
0064 template <typename U>
0065 SpyHashStateImpl(SpyHashStateImpl<U>&& other) {
0066 hash_representation_ = std::move(other.hash_representation_);
0067 error_ = other.error_;
0068 moved_from_ = other.moved_from_;
0069 other.moved_from_ = true;
0070 }
0071
0072 template <typename A, typename... Args>
0073 static SpyHashStateImpl combine(SpyHashStateImpl s, const A& a,
0074 const Args&... args) {
0075
0076
0077
0078
0079 s = SpyHashStateImpl<A>::HashStateBase::combine(std::move(s), a);
0080 return SpyHashStateImpl::combine(std::move(s), args...);
0081 }
0082 static SpyHashStateImpl combine(SpyHashStateImpl s) {
0083 if (direct_absl_hash_value_error_) {
0084 *s.error_ = "AbslHashValue should not be invoked directly.";
0085 } else if (s.moved_from_) {
0086 *s.error_ = "Used moved-from instance of the hash state object.";
0087 }
0088 return s;
0089 }
0090
0091 static void SetDirectAbslHashValueError() {
0092 direct_absl_hash_value_error_ = true;
0093 }
0094
0095
0096
0097 friend bool operator==(const SpyHashStateImpl& lhs,
0098 const SpyHashStateImpl& rhs) {
0099 return lhs.hash_representation_ == rhs.hash_representation_;
0100 }
0101
0102 friend bool operator!=(const SpyHashStateImpl& lhs,
0103 const SpyHashStateImpl& rhs) {
0104 return !(lhs == rhs);
0105 }
0106
0107 enum class CompareResult {
0108 kEqual,
0109 kASuffixB,
0110 kBSuffixA,
0111 kUnequal,
0112 };
0113
0114 static CompareResult Compare(const SpyHashStateImpl& a,
0115 const SpyHashStateImpl& b) {
0116 const std::string a_flat = absl::StrJoin(a.hash_representation_, "");
0117 const std::string b_flat = absl::StrJoin(b.hash_representation_, "");
0118 if (a_flat == b_flat) return CompareResult::kEqual;
0119 if (absl::EndsWith(a_flat, b_flat)) return CompareResult::kBSuffixA;
0120 if (absl::EndsWith(b_flat, a_flat)) return CompareResult::kASuffixB;
0121 return CompareResult::kUnequal;
0122 }
0123
0124
0125
0126 friend std::ostream& operator<<(std::ostream& out,
0127 const SpyHashStateImpl& hash_state) {
0128 out << "[\n";
0129 for (auto& s : hash_state.hash_representation_) {
0130 size_t offset = 0;
0131 for (char c : s) {
0132 if (offset % 16 == 0) {
0133 out << absl::StreamFormat("\n0x%04x: ", offset);
0134 }
0135 if (offset % 2 == 0) {
0136 out << " ";
0137 }
0138 out << absl::StreamFormat("%02x", c);
0139 ++offset;
0140 }
0141 out << "\n";
0142 }
0143 return out << "]";
0144 }
0145
0146
0147
0148 static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state,
0149 const unsigned char* begin,
0150 size_t size) {
0151 const size_t large_chunk_stride = PiecewiseChunkSize();
0152
0153
0154
0155 while (size > large_chunk_stride) {
0156 hash_state = SpyHashStateImpl::combine_contiguous(
0157 std::move(hash_state), begin, large_chunk_stride);
0158 begin += large_chunk_stride;
0159 size -= large_chunk_stride;
0160 }
0161
0162 if (size > 0) {
0163 hash_state.hash_representation_.emplace_back(
0164 reinterpret_cast<const char*>(begin), size);
0165 }
0166 return hash_state;
0167 }
0168
0169 using SpyHashStateImpl::HashStateBase::combine_contiguous;
0170
0171 template <typename CombinerT>
0172 static SpyHashStateImpl RunCombineUnordered(SpyHashStateImpl state,
0173 CombinerT combiner) {
0174 UnorderedCombinerCallback cb;
0175
0176 combiner(SpyHashStateImpl<void>{}, std::ref(cb));
0177
0178 std::sort(cb.element_hash_representations.begin(),
0179 cb.element_hash_representations.end());
0180 state.hash_representation_.insert(state.hash_representation_.end(),
0181 cb.element_hash_representations.begin(),
0182 cb.element_hash_representations.end());
0183 if (cb.error && cb.error->has_value()) {
0184 state.error_ = std::move(cb.error);
0185 }
0186 return state;
0187 }
0188
0189 absl::optional<std::string> error() const {
0190 if (moved_from_) {
0191 return "Returned a moved-from instance of the hash state object.";
0192 }
0193 return *error_;
0194 }
0195
0196 private:
0197 template <typename U>
0198 friend class SpyHashStateImpl;
0199
0200 struct UnorderedCombinerCallback {
0201 std::vector<std::string> element_hash_representations;
0202 std::shared_ptr<absl::optional<std::string>> error;
0203
0204
0205 template <typename U>
0206 void operator()(SpyHashStateImpl<U>& inner) {
0207 element_hash_representations.push_back(
0208 absl::StrJoin(inner.hash_representation_, ""));
0209 if (inner.error_->has_value()) {
0210 error = std::move(inner.error_);
0211 }
0212 inner = SpyHashStateImpl<void>{};
0213 }
0214 };
0215
0216
0217
0218
0219 static bool direct_absl_hash_value_error_;
0220
0221 std::vector<std::string> hash_representation_;
0222
0223
0224
0225 std::shared_ptr<absl::optional<std::string>> error_;
0226 bool moved_from_ = false;
0227 };
0228
0229 template <typename T>
0230 bool SpyHashStateImpl<T>::direct_absl_hash_value_error_;
0231
0232 template <bool& B>
0233 struct OdrUse {
0234 constexpr OdrUse() {}
0235 bool& b = B;
0236 };
0237
0238 template <void (*)()>
0239 struct RunOnStartup {
0240 static bool run;
0241 static constexpr OdrUse<run> kOdrUse{};
0242 };
0243
0244 template <void (*f)()>
0245 bool RunOnStartup<f>::run = (f(), true);
0246
0247 template <
0248 typename T, typename U,
0249
0250 typename = absl::enable_if_t<!std::is_same<T, U>::value>,
0251
0252
0253
0254
0255
0256
0257 int = RunOnStartup<SpyHashStateImpl<T>::SetDirectAbslHashValueError>::run>
0258 void AbslHashValue(SpyHashStateImpl<T>, const U&);
0259
0260 using SpyHashState = SpyHashStateImpl<void>;
0261
0262 }
0263 ABSL_NAMESPACE_END
0264 }
0265
0266 #endif