diff options
Diffstat (limited to 'modules/codec/c++/schema_hash.hpp')
-rw-r--r-- | modules/codec/c++/schema_hash.hpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/modules/codec/c++/schema_hash.hpp b/modules/codec/c++/schema_hash.hpp new file mode 100644 index 0000000..c799311 --- /dev/null +++ b/modules/codec/c++/schema_hash.hpp @@ -0,0 +1,207 @@ +#pragma once + +#include <forstio/string_literal.h> +#include "schema.hpp +#include "crc32.hpp + +namespace saw { +template<string_literal lit> +struct hash_literal { + static constexpr uint32_t apply(uint32_t seed){ + constexpr std::string_view view = lit.view(); + return hash<algs::crc32>::update(seed, view); + } +}; + +template<typename Schema> +struct schema_hash_seed { + static_assert(always_false<Schema>, "Not schema_hashable"); +}; + +template<> +struct schema_hash_seed<schema::SignedInteger> { + using Schema = schema::SignedInteger; + + static constexpr uint32_t apply(uint32_t seed){ + return hash_literal<Schema::name>::apply(seed); + } +}; + +template<> +struct schema_hash_seed<schema::UnsignedInteger> { + using Schema = schema::UnsignedInteger; + + static constexpr uint32_t apply(uint32_t seed){ + return hash_literal<Schema::name>::apply(seed); + } +}; + +template<> +struct schema_hash_seed<schema::FloatingPoint> { + using Schema = schema::FloatingPoint; + + static constexpr uint32_t apply(uint32_t seed){ + return hash_literal<Schema::name>::apply(seed); + } +}; + +template<> +struct schema_hash_seed<schema::String> { + using Schema = schema::String; + + static constexpr uint32_t apply(uint32_t seed){ + return hash_literal<Schema::name>::apply(seed); + } +}; + +template<typename P, uint64_t N> +struct schema_hash_seed<schema::Primitive<P,N>> { + using Schema = schema::Primitive<P,N>; + + static constexpr uint32_t apply(uint32_t seed){ + seed = hash_literal<Schema::name>::apply(seed); + seed = schema_hash_seed<P>::apply(seed); + uint64_t val = N; + std::array<uint8_t,sizeof(uint64_t)> dat{ + static_cast<uint8_t>(val >> 0), + static_cast<uint8_t>(val >> 8), + static_cast<uint8_t>(val >> 16), + static_cast<uint8_t>(val >> 24), + static_cast<uint8_t>(val >> 32), + static_cast<uint8_t>(val >> 40), + static_cast<uint8_t>(val >> 48), + static_cast<uint8_t>(val >> 56) + }; + seed = hash<algs::crc32>::update(seed, &dat[0], dat.size()); + return seed; + } +}; + +template<typename T, uint64_t N> +struct schema_hash_seed<schema::Array<T,N>> { + using Schema = schema::Array<T,N>; + + static constexpr uint32_t apply(uint32_t seed){ + seed = hash_literal<Schema::name>::apply(seed); + seed = schema_hash_seed<T>::apply(seed); + uint64_t val = N; + std::array<uint8_t,sizeof(uint64_t)> dat{ + static_cast<uint8_t>(val >> 0), + static_cast<uint8_t>(val >> 8), + static_cast<uint8_t>(val >> 16), + static_cast<uint8_t>(val >> 24), + static_cast<uint8_t>(val >> 32), + static_cast<uint8_t>(val >> 40), + static_cast<uint8_t>(val >> 48), + static_cast<uint8_t>(val >> 56) + }; + seed = hash<algs::crc32>::update(seed, &dat[0], dat.size()); + return seed; + } +}; + +template<typename... T> +struct schema_hash_seed<schema::Tuple<T...>> { + using Schema = schema::Tuple<T...>; + + template<uint64_t i> + static constexpr uint32_t apply_ele(uint32_t seed){ + using Type = typename parameter_pack_type<i,T...>::type; + + seed = schema_hash_seed<Type>::apply(seed); + if constexpr ( (i+1) < sizeof...(T) ){ + return apply_ele<i+1>(seed); + } + return seed; + } + + + static constexpr uint32_t apply(uint32_t seed){ + seed = hash_literal<Schema::name>::apply(seed); + if constexpr (sizeof...(T) > 0){ + seed = apply_ele<0>(seed); + } + return seed; + } +}; + +template<typename... V, string_literal... K> +struct schema_hash_seed<schema::Struct<schema::Member<V,K>...>> { + using Schema = schema::Struct<schema::Member<V,K>...>; + + template<uint64_t i> + static constexpr uint32_t apply_ele(uint32_t seed){ + using Type = typename parameter_pack_type<i,V...>::type; + constexpr string_literal Lit = parameter_key_pack_type<i,K...>::literal; + using MemberT = typename parameter_pack_type<i,schema::Member<V,K>...>::type; + + seed = hash_literal<MemberT::name>::apply(seed); + seed = schema_hash_seed<Type>::apply(seed); + seed = hash_literal<Lit>::apply(seed); + + if constexpr ( (i+1) < sizeof...(V) ){ + return apply_ele<i+1>(seed); + } + return seed; + } + + static constexpr uint32_t apply(uint32_t seed){ + seed = hash_literal<Schema::name>::apply(seed); + if constexpr (sizeof...(V) > 0){ + seed = apply_ele<0>(seed); + } + return seed; + } +}; + +template<typename Req, typename Resp> +struct schema_hash_seed<schema::Function<Req, Resp>> { + using Schema = schema::Function<Req,Resp>; + + static constexpr uint32_t apply(uint32_t seed){ + seed = hash_literal<Schema::name>::apply(seed); + seed = schema_hash_seed<Req>::apply(seed); + seed = schema_hash_seed<Resp>::apply(seed); + return seed; + } +}; + +template<typename... T, string_literal... Names> +struct schema_hash_seed<schema::Interface<schema::Member<T, Names>...>> { + using Schema = schema::Interface<schema::Member<T,Names>...>; + + template<uint64_t i> + static constexpr uint32_t apply_ele(uint32_t seed){ + using Type = typename parameter_pack_type<i,T...>::type; + constexpr string_literal Lit = parameter_key_pack_type<i,Names...>::literal; + using MemberT = schema::Member<Type,Lit>; + + seed = hash_literal<MemberT::name>::apply(seed); + seed = schema_hash_seed<Type>::apply(seed); + seed = hash_literal<Lit>::apply(seed); + + if constexpr ( (i+1) < sizeof...(T) ){ + return apply_ele<i+1>(seed); + } + + return seed; + } + + static constexpr uint32_t apply(uint32_t seed){ + seed = hash_literal<Schema::name>::apply(seed); + if constexpr ( sizeof...(T) > 0){ + seed = apply_ele<0>(seed); + } + return seed; + } +}; + +template<typename Schema> +struct schema_hash { + static constexpr uint32_t apply() { + constexpr uint32_t seed = 0; + return schema_hash_seed<Schema>::apply(seed); + } +}; + +} |