/* * Copyright (C) 2015 ScyllaDB */ /* * This file is part of Scylla. * * Scylla is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Scylla is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Scylla. If not, see . */ #pragma once #include #include #include #include #include // // This hashing differs from std::hash<> in that it decouples knowledge about // type structure from the way the hash value is calculated: // * appending_hash instantiation knows about what data should be included in the hash for type T. // * Hasher object knows how to combine the data into the final hash. // // The appending_hash should always feed some data into the hasher, regardless of the state the object is in, // in order for the hash to be highly sensitive for value changes. For example, vector> should // ideally feed different values for empty vector and a vector with a single empty optional. // // appending_hash is machine-independent. // // The Hasher concept struct Hasher { void update(const char* ptr, size_t size); }; template struct appending_hash; template inline void feed_hash(Hasher& h, const T& value, Args&&... args) { appending_hash()(h, value, std::forward(args)...); }; template struct appending_hash::value>> { template void operator()(Hasher& h, T value) const { auto value_le = cpu_to_le(value); h.update(reinterpret_cast(&value_le), sizeof(T)); } }; template<> struct appending_hash { template void operator()(Hasher& h, bool value) const { feed_hash(h, static_cast(value)); } }; template struct appending_hash::value>> { template void operator()(Hasher& h, const T& value) const { feed_hash(h, static_cast>(value)); } }; template struct appending_hash> { template void operator()(Hasher& h, const std::experimental::optional& value) const { if (value) { feed_hash(h, true); feed_hash(h, *value); } else { feed_hash(h, false); } } }; template struct appending_hash { template void operator()(Hasher& h, const char (&value) [N]) const { feed_hash(h, N); h.update(value, N); } }; template struct appending_hash> { template void operator()(Hasher& h, const std::vector& value) const { feed_hash(h, value.size()); for (auto&& v : value) { appending_hash()(h, v); } } }; template struct appending_hash> { template void operator()(Hasher& h, const std::map& value) const { feed_hash(h, value.size()); for (auto&& e : value) { appending_hash()(h, e.first); appending_hash()(h, e.second); } } }; template<> struct appending_hash { template void operator()(Hasher& h, const sstring& v) const { feed_hash(h, v.size()); h.update(reinterpret_cast(v.cbegin()), v.size() * sizeof(sstring::value_type)); } }; template<> struct appending_hash { template void operator()(Hasher& h, const std::string& v) const { feed_hash(h, v.size()); h.update(reinterpret_cast(v.data()), v.size() * sizeof(std::string::value_type)); } }; template struct appending_hash> { template void operator()(Hasher& h, std::chrono::duration v) const { feed_hash(h, v.count()); } }; template struct appending_hash> { template void operator()(Hasher& h, std::chrono::time_point v) const { feed_hash(h, v.time_since_epoch().count()); } };