Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
00016 #define ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
00017
00018 #include <ostream>
00019 #include <string>
00020 #include <vector>
00021
00022 #include "absl/hash/hash.h"
00023 #include "absl/strings/match.h"
00024 #include "absl/strings/str_format.h"
00025 #include "absl/strings/str_join.h"
00026
00027 namespace absl {
00028 namespace hash_internal {
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 template <typename T>
00040 class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
00041 public:
00042 SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) {
00043 static_assert(std::is_void<T>::value, "");
00044 }
00045
00046
00047 SpyHashStateImpl(const SpyHashStateImpl&) = delete;
00048 SpyHashStateImpl& operator=(const SpyHashStateImpl&) = delete;
00049
00050 SpyHashStateImpl(SpyHashStateImpl&& other) noexcept {
00051 *this = std::move(other);
00052 }
00053
00054 SpyHashStateImpl& operator=(SpyHashStateImpl&& other) noexcept {
00055 hash_representation_ = std::move(other.hash_representation_);
00056 error_ = other.error_;
00057 moved_from_ = other.moved_from_;
00058 other.moved_from_ = true;
00059 return *this;
00060 }
00061
00062 template <typename U>
00063 SpyHashStateImpl(SpyHashStateImpl<U>&& other) {
00064 hash_representation_ = std::move(other.hash_representation_);
00065 error_ = other.error_;
00066 moved_from_ = other.moved_from_;
00067 other.moved_from_ = true;
00068 }
00069
00070 template <typename A, typename... Args>
00071 static SpyHashStateImpl combine(SpyHashStateImpl s, const A& a,
00072 const Args&... args) {
00073
00074
00075
00076
00077 s = SpyHashStateImpl<A>::HashStateBase::combine(std::move(s), a);
00078 return SpyHashStateImpl::combine(std::move(s), args...);
00079 }
00080 static SpyHashStateImpl combine(SpyHashStateImpl s) {
00081 if (direct_absl_hash_value_error_) {
00082 *s.error_ = "AbslHashValue should not be invoked directly.";
00083 } else if (s.moved_from_) {
00084 *s.error_ = "Used moved-from instance of the hash state object.";
00085 }
00086 return s;
00087 }
00088
00089 static void SetDirectAbslHashValueError() {
00090 direct_absl_hash_value_error_ = true;
00091 }
00092
00093
00094
00095 friend bool operator==(const SpyHashStateImpl& lhs,
00096 const SpyHashStateImpl& rhs) {
00097 return lhs.hash_representation_ == rhs.hash_representation_;
00098 }
00099
00100 friend bool operator!=(const SpyHashStateImpl& lhs,
00101 const SpyHashStateImpl& rhs) {
00102 return !(lhs == rhs);
00103 }
00104
00105 enum class CompareResult {
00106 kEqual,
00107 kASuffixB,
00108 kBSuffixA,
00109 kUnequal,
00110 };
00111
00112 static CompareResult Compare(const SpyHashStateImpl& a,
00113 const SpyHashStateImpl& b) {
00114 const std::string a_flat = absl::StrJoin(a.hash_representation_, "");
00115 const std::string b_flat = absl::StrJoin(b.hash_representation_, "");
00116 if (a_flat == b_flat) return CompareResult::kEqual;
00117 if (absl::EndsWith(a_flat, b_flat)) return CompareResult::kBSuffixA;
00118 if (absl::EndsWith(b_flat, a_flat)) return CompareResult::kASuffixB;
00119 return CompareResult::kUnequal;
00120 }
00121
00122
00123
00124 friend std::ostream& operator<<(std::ostream& out,
00125 const SpyHashStateImpl& hash_state) {
00126 out << "[\n";
00127 for (auto& s : hash_state.hash_representation_) {
00128 size_t offset = 0;
00129 for (char c : s) {
00130 if (offset % 16 == 0) {
00131 out << absl::StreamFormat("\n0x%04x: ", offset);
00132 }
00133 if (offset % 2 == 0) {
00134 out << " ";
00135 }
00136 out << absl::StreamFormat("%02x", c);
00137 ++offset;
00138 }
00139 out << "\n";
00140 }
00141 return out << "]";
00142 }
00143
00144
00145
00146 static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state,
00147 const unsigned char* begin,
00148 size_t size) {
00149 hash_state.hash_representation_.emplace_back(
00150 reinterpret_cast<const char*>(begin), size);
00151 return hash_state;
00152 }
00153
00154 using SpyHashStateImpl::HashStateBase::combine_contiguous;
00155
00156 absl::optional<std::string> error() const {
00157 if (moved_from_) {
00158 return "Returned a moved-from instance of the hash state object.";
00159 }
00160 return *error_;
00161 }
00162
00163 private:
00164 template <typename U>
00165 friend class SpyHashStateImpl;
00166
00167
00168
00169
00170 static bool direct_absl_hash_value_error_;
00171
00172 std::vector<std::string> hash_representation_;
00173
00174
00175
00176 std::shared_ptr<absl::optional<std::string>> error_;
00177 bool moved_from_ = false;
00178 };
00179
00180 template <typename T>
00181 bool SpyHashStateImpl<T>::direct_absl_hash_value_error_;
00182
00183 template <bool& B>
00184 struct OdrUse {
00185 constexpr OdrUse() {}
00186 bool& b = B;
00187 };
00188
00189 template <void (*)()>
00190 struct RunOnStartup {
00191 static bool run;
00192 static constexpr OdrUse<run> kOdrUse{};
00193 };
00194
00195 template <void (*f)()>
00196 bool RunOnStartup<f>::run = (f(), true);
00197
00198 template <
00199 typename T, typename U,
00200
00201 typename = absl::enable_if_t<!std::is_same<T, U>::value>,
00202
00203
00204
00205
00206
00207
00208 int = RunOnStartup<SpyHashStateImpl<T>::SetDirectAbslHashValueError>::run>
00209 void AbslHashValue(SpyHashStateImpl<T>, const U&);
00210
00211 using SpyHashState = SpyHashStateImpl<void>;
00212
00213 }
00214 }
00215
00216 #endif // ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_