From a7ed60efc219fc441673f10a986d85bb1d4b59bc Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Fri, 26 Nov 2021 21:52:30 +0100 Subject: [PATCH] wip --- .../TerminalSettingsModel/ActionArgs.h | 228 +++++++++++------- .../TerminalSettingsModel/ActionArgs.idl | 4 +- .../TerminalSettingsModel/ActionMap.cpp | 33 +-- .../TerminalSettingsModel/HashUtils.h | 67 ++--- src/inc/til/hash.h | 142 +++++++++++ 5 files changed, 329 insertions(+), 145 deletions(-) create mode 100644 src/inc/til/hash.h diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index 1c95209e4..fd984d76b 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -61,27 +61,6 @@ private: // * ActionEventArgs holds a single IActionArgs. For events that don't need // additional args, this can be nullptr. -template<> -constexpr size_t Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(const winrt::Microsoft::Terminal::Settings::Model::IActionArgs& args) -{ - return gsl::narrow_cast(args.Hash()); -} - -template<> -constexpr size_t Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(const winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs& args) -{ - return gsl::narrow_cast(args.Hash()); -} - -// Retrieves the hash value for an empty-constructed object. -template -static size_t EmptyHash() -{ - // cache the value of the empty hash - static const size_t cachedHash = winrt::make_self()->Hash(); - return cachedHash; -} - namespace winrt::Microsoft::Terminal::Settings::Model::implementation { using namespace ::Microsoft::Terminal::Settings::Model; @@ -185,9 +164,18 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_ColorScheme = _ColorScheme; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Commandline(), StartingDirectory(), TabTitle(), TabColor(), ProfileIndex(), Profile(), SuppressApplicationTitle(), ColorScheme()); + til::hasher h{ hasherState }; + til::hash{}(h, Commandline()); + til::hash{}(h, StartingDirectory()); + til::hash{}(h, TabTitle()); + til::hash{}(h, TabColor()); + til::hash{}(h, ProfileIndex()); + til::hash{}(h, Profile()); + til::hash{}(h, SuppressApplicationTitle()); + til::hash{}(h, ColorScheme()); + return h.finalize(); } }; @@ -241,9 +229,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_CopyFormatting = _CopyFormatting; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(SingleLine(), CopyFormatting()); + til::hasher h{ hasherState }; + til::hash{}(h, SingleLine()); + til::hash{}(h, CopyFormatting()); + return h.finalize(); } }; @@ -288,9 +279,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_TerminalArgs = _TerminalArgs.Copy(); return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(TerminalArgs()); + til::hasher h{ hasherState }; + til::hash{}(h, TerminalArgs()); + return h.finalize(); } }; @@ -339,9 +332,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_TabIndex = _TabIndex; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(TabIndex()); + til::hasher h{ hasherState }; + til::hash{}(h, TabIndex()); + return h.finalize(); } }; @@ -390,9 +385,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_TabIndex = _TabIndex; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(TabIndex()); + til::hasher h{ hasherState }; + til::hash{}(h, TabIndex()); + return h.finalize(); } }; @@ -446,9 +443,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_ResizeDirection = _ResizeDirection; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(ResizeDirection()); + til::hasher h{ hasherState }; + til::hash{}(h, ResizeDirection()); + return h.finalize(); } }; @@ -505,9 +504,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_FocusDirection = _FocusDirection; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(FocusDirection()); + til::hasher h{ hasherState }; + til::hash{}(h, FocusDirection()); + return h.finalize(); } }; @@ -564,9 +565,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Direction = _Direction; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Direction()); + til::hasher h{ hasherState }; + til::hash{}(h, Direction()); + return h.finalize(); } }; @@ -613,9 +616,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Delta = _Delta; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Delta()); + til::hasher h{ hasherState }; + til::hash{}(h, Delta()); + return h.finalize(); } }; @@ -665,9 +670,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Input = _Input; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Input()); + til::hasher h{ hasherState }; + til::hash{}(h, Input()); + return h.finalize(); } }; @@ -749,9 +756,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_SplitSize = _SplitSize; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(SplitDirection(), TerminalArgs(), SplitMode(), SplitSize()); + til::hasher h{ hasherState }; + til::hash{}(h, SplitDirection()); + til::hash{}(h, TerminalArgs()); + til::hash{}(h, SplitMode()); + til::hash{}(h, SplitSize()); + return h.finalize(); } }; @@ -800,9 +812,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Target = _Target; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Target()); + til::hasher h{ hasherState }; + til::hash{}(h, Target()); + return h.finalize(); } }; @@ -855,9 +869,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_SchemeName = _SchemeName; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(SchemeName()); + til::hasher h{ hasherState }; + til::hash{}(h, SchemeName()); + return h.finalize(); } }; @@ -906,9 +922,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_TabColor = _TabColor; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(TabColor()); + til::hasher h{ hasherState }; + til::hash{}(h, TabColor()); + return h.finalize(); } }; @@ -955,9 +973,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Title = _Title; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Title()); + til::hasher h{ hasherState }; + til::hash{}(h, Title()); + return h.finalize(); } }; @@ -1010,9 +1030,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Commandline = _Commandline; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Commandline()); + til::hasher h{ hasherState }; + til::hash{}(h, Commandline()); + return h.finalize(); } }; @@ -1061,9 +1083,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Index = _Index; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Index()); + til::hasher h{ hasherState }; + til::hash{}(h, Index()); + return h.finalize(); } }; @@ -1112,9 +1136,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Index = _Index; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Index()); + til::hasher h{ hasherState }; + til::hash{}(h, Index()); + return h.finalize(); } }; @@ -1163,9 +1189,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Index = _Index; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Index()); + til::hasher h{ hasherState }; + til::hash{}(h, Index()); + return h.finalize(); } }; @@ -1221,9 +1249,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Direction = _Direction; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Direction()); + til::hasher h{ hasherState }; + til::hash{}(h, Direction()); + return h.finalize(); } }; @@ -1270,9 +1300,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_RowsToScroll = _RowsToScroll; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(RowsToScroll()); + til::hasher h{ hasherState }; + til::hash{}(h, RowsToScroll()); + return h.finalize(); } }; @@ -1319,9 +1351,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_RowsToScroll = _RowsToScroll; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(RowsToScroll()); + til::hasher h{ hasherState }; + til::hash{}(h, RowsToScroll()); + return h.finalize(); } }; @@ -1370,9 +1404,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_LaunchMode = _LaunchMode; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(LaunchMode()); + til::hasher h{ hasherState }; + til::hash{}(h, LaunchMode()); + return h.finalize(); } }; @@ -1428,9 +1464,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Direction = _Direction; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Direction()); + til::hasher h{ hasherState }; + til::hash{}(h, Direction()); + return h.finalize(); } }; @@ -1475,9 +1513,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_TerminalArgs = _TerminalArgs.Copy(); return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(TerminalArgs()); + til::hasher h{ hasherState }; + til::hash{}(h, TerminalArgs()); + return h.finalize(); } }; @@ -1525,9 +1565,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_SwitcherMode = _SwitcherMode; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(SwitcherMode()); + til::hasher h{ hasherState }; + til::hash{}(h, SwitcherMode()); + return h.finalize(); } }; @@ -1575,9 +1617,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_SwitcherMode = _SwitcherMode; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(SwitcherMode()); + til::hasher h{ hasherState }; + til::hash{}(h, SwitcherMode()); + return h.finalize(); } }; @@ -1625,9 +1669,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Name = _Name; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Name()); + til::hasher h{ hasherState }; + til::hash{}(h, Name()); + return h.finalize(); } }; @@ -1709,9 +1755,15 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation args->_DropdownDuration = 200; return { *args, {} }; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Name(), Desktop(), Monitor(), DropdownDuration(), ToggleVisibility()); + til::hasher h{ hasherState }; + til::hash{}(h, Name()); + til::hash{}(h, Desktop()); + til::hash{}(h, Monitor()); + til::hash{}(h, DropdownDuration()); + til::hash{}(h, ToggleVisibility()); + return h.finalize(); } }; @@ -1759,9 +1811,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Id = _Id; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Id); + til::hasher h{ hasherState }; + til::hash{}(h, Id()); + return h.finalize(); } }; @@ -1809,9 +1863,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Clear = _Clear; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Clear); + til::hasher h{ hasherState }; + til::hash{}(h, Clear()); + return h.finalize(); } }; @@ -1858,9 +1914,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Actions = _Actions; return *copy; } - size_t Hash() const + size_t Hash(size_t hasherState) const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Actions); + til::hasher h{ hasherState }; + til::hash{}(h, winrt::get_abi(_Actions)); + return h.finalize(); } }; } diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 457feefce..b0edde615 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -10,7 +10,7 @@ namespace Microsoft.Terminal.Settings.Model Boolean Equals(IActionArgs other); String GenerateName(); IActionArgs Copy(); - UInt64 Hash(); + UInt64 Hash(UInt64 hasher); }; interface IActionEventArgs @@ -128,7 +128,7 @@ namespace Microsoft.Terminal.Settings.Model Boolean Equals(NewTerminalArgs other); String GenerateName(); String ToCommandline(); - UInt64 Hash(); + UInt64 Hash(UInt64 hasher); }; [default_interface] runtimeclass ActionEventArgs : IActionEventArgs diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.cpp b/src/cascadia/TerminalSettingsModel/ActionMap.cpp index 1bd4aa390..75f9920ca 100644 --- a/src/cascadia/TerminalSettingsModel/ActionMap.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionMap.cpp @@ -15,13 +15,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { static InternalActionID Hash(const Model::ActionAndArgs& actionAndArgs) { - size_t hashedAction{ HashUtils::HashProperty(actionAndArgs.Action()) }; + const auto action = actionAndArgs.Action(); + til::hasher hasher; - size_t hashedArgs{}; - if (const auto& args{ actionAndArgs.Args() }) + if (const auto args = actionAndArgs.Args()) { - // Args are defined, so hash them - hashedArgs = gsl::narrow_cast(args.Hash()); + hasher = gsl::narrow_cast(args.Hash(hasher.finalize())); } else { @@ -29,22 +28,24 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation // Check if the ShortcutAction supports args. switch (actionAndArgs.Action()) { -#define ON_ALL_ACTIONS_WITH_ARGS(action) \ - case ShortcutAction::action: \ - /* If it does, hash the default values for the args.*/ \ - hashedArgs = EmptyHash(); \ - break; +#define ON_ALL_ACTIONS_WITH_ARGS(action) \ + case ShortcutAction::action: \ + { \ + /* If it does, hash the default values for the args. */ \ + /* Since til::hasher hasn't been written to at this point, hasher.finalize() is a constexpr. */ \ + static const size_t cachedHash = winrt::make_self()->Hash(hasher.finalize()); \ + hasher = gsl::narrow_cast(cachedHash); \ + break; \ + } ALL_SHORTCUT_ACTIONS_WITH_ARGS #undef ON_ALL_ACTIONS_WITH_ARGS default: - { - // Otherwise, hash nullptr. - std::hash argsHash; - hashedArgs = argsHash(nullptr); - } + break; } } - return hashedAction ^ hashedArgs; + + hasher.write(action); + return hasher.finalize(); } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/HashUtils.h b/src/cascadia/TerminalSettingsModel/HashUtils.h index f0b814995..cebf5782e 100644 --- a/src/cascadia/TerminalSettingsModel/HashUtils.h +++ b/src/cascadia/TerminalSettingsModel/HashUtils.h @@ -17,54 +17,37 @@ Revision History: #pragma once -namespace Microsoft::Terminal::Settings::Model::HashUtils +#include + +namespace til { - // This is a helper template function for hashing multiple variables in conjunction to each other. template - constexpr size_t HashProperty(const T& val) + struct hash> { - std::hash hashFunc; - return hashFunc(val); - } - - template - constexpr size_t HashProperty(const T& val, Args&&... more) - { - // Inspired by boost::hash_combine, which causes this effect... - // seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - // Source: https://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html - const auto seed{ HashProperty(val) }; - return seed ^ (0x9e3779b9 + (seed << 6) + (seed >> 2) + HashProperty(std::forward(more)...)); - } + constexpr void operator()(hasher& h, const winrt::Windows::Foundation::IReference& v) const noexcept + { + if (v) + { + til::hash{}(h, v.Value()); + } + } + }; template<> - constexpr size_t HashProperty(const til::color& val) + struct hash { - return HashProperty(val.a, val.r, val.g, val.b); - } + void operator()(hasher& h, const winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs& value) const noexcept + { + til::hash{}(h, winrt::get_abi(value)); + } + }; -#ifdef WINRT_Windows_Foundation_H - template - constexpr size_t HashProperty(const winrt::Windows::Foundation::IReference& val) - { - return val ? HashProperty(val.Value()) : 0; - } -#endif - -#ifdef WINRT_Windows_UI_H template<> - constexpr size_t HashProperty(const winrt::Windows::UI::Color& val) + struct hash { - return HashProperty(til::color{ val }); - } -#endif - -#ifdef WINRT_Microsoft_Terminal_Core_H - template<> - constexpr size_t HashProperty(const winrt::Microsoft::Terminal::Core::Color& val) - { - return HashProperty(til::color{ val }); - } -#endif - -}; + void operator()(hasher& h, const winrt::hstring& value) const noexcept + { + h.write(reinterpret_cast(value.data()), value.size() * sizeof(wchar_t)); + } + }; +} diff --git a/src/inc/til/hash.h b/src/inc/til/hash.h new file mode 100644 index 000000000..406b8d8f2 --- /dev/null +++ b/src/inc/til/hash.h @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include + +namespace til +{ + template + struct integral_hash + { + constexpr size_t operator()(T v) const noexcept + { + auto h = static_cast(v); + if constexpr (sizeof(size_t) == 4) + { + h ^= h >> 16; + h *= UINT32_C(0x85ebca6b); + h ^= h >> 13; + h *= UINT32_C(0xc2b2ae35); + h ^= h >> 16; + } + else + { + std::_Hash_array_representation + h ^= h >> 33; + h *= UINT64_C(0xff51afd7ed558ccd); + h ^= h >> 33; + h *= UINT64_C(0xc4ceb9fe1a85ec53); + h ^= h >> 33; + } + return h; + } + }; + + template + struct hash; + + struct hasher + { + constexpr hasher(size_t state = FNV_offset_basis) noexcept : _hash{state} {} + + template>> + constexpr void write(const T& v) noexcept + { + write(reinterpret_cast(&v), sizeof(T)); + } + + template>> + constexpr void write(const T* data, size_t count) noexcept + { + write(reinterpret_cast(data), sizeof(T) * count); + } + + constexpr void write(const uint8_t* data, size_t count) noexcept + { + for (size_t i = 0; i < count; ++i) + { + _hash ^= static_cast(data[i]); + _hash *= FNV_prime; + } + } + + constexpr size_t finalize() const noexcept + { + return _hash; + } + + private: +#if defined(_WIN64) + static constexpr size_t FNV_offset_basis = 14695981039346656037ULL; + static constexpr size_t FNV_prime = 1099511628211ULL; +#else + static constexpr size_t FNV_offset_basis = 2166136261U; + static constexpr size_t FNV_prime = 16777619U; +#endif + + size_t _hash = FNV_offset_basis; + }; + + namespace details + { + template + struct conditionally_enabled_hash + { + constexpr void operator()(hasher& h, const T& v) const noexcept + { + h.write(reinterpret_cast(&v), sizeof(T)); + } + }; + + template + struct conditionally_enabled_hash + { + conditionally_enabled_hash() = delete; + conditionally_enabled_hash(const conditionally_enabled_hash&) = delete; + conditionally_enabled_hash(conditionally_enabled_hash&&) = delete; + conditionally_enabled_hash& operator=(const conditionally_enabled_hash&) = delete; + conditionally_enabled_hash& operator=(conditionally_enabled_hash&&) = delete; + }; + } + + template + struct hash : details::conditionally_enabled_hash> + { + }; + + template<> + struct hash + { + constexpr void operator()(hasher& h, float v) const noexcept + { + v = v == 0.0f ? 0.0f : v; // map -0 to 0 + h.write(reinterpret_cast(&v), sizeof(v)); + } + }; + + template<> + struct hash + { + constexpr void operator()(hasher& h, double v) const noexcept + { + v = v == 0.0 ? 0.0 : v; // map -0 to 0 + h.write(reinterpret_cast(&v), sizeof(v)); + } + }; + + template + struct hash> { + constexpr void operator()(const std::basic_string& v) const noexcept { + h.write(reinterpret_cast(v.data()), sizeof(T) * v.size()); + } + }; + + template + struct hash> { + constexpr void operator()(const std::basic_string_view& v) const noexcept { + h.write(reinterpret_cast(v.data()), sizeof(T) * v.size()); + } + }; +}