diff --git a/src/alias_registry.hh b/src/alias_registry.hh index e2d4e271..3010ce49 100644 --- a/src/alias_registry.hh +++ b/src/alias_registry.hh @@ -3,8 +3,7 @@ #include "safe_ptr.hh" #include "string.hh" - -#include +#include "unordered_map.hh" namespace Kakoune { @@ -24,7 +23,7 @@ private: AliasRegistry() {} safe_ptr m_parent; - std::unordered_map m_aliases; + UnorderedMap m_aliases; }; } diff --git a/src/color.hh b/src/color.hh index 1de59fcd..1b3ba9c6 100644 --- a/src/color.hh +++ b/src/color.hh @@ -1,6 +1,8 @@ #ifndef color_hh_INCLUDED #define color_hh_INCLUDED +#include "hash.hh" + namespace Kakoune { @@ -32,13 +34,19 @@ struct Color Color(Colors c) : color{c}, r{0}, g{0}, b{0} {} Color(unsigned char r, unsigned char g, unsigned char b) : color{Colors::RGB}, r{r}, g{g}, b{b} {} - - bool operator==(Color c) const - { return color == c.color and r == c.r and g == c.g and b == c.b; } - bool operator!=(Color c) const - { return color != c.color or r != c.r or g != c.g or b != c.b; } }; +inline bool operator==(Color lhs, Color rhs) +{ + return lhs.color == rhs.color and + lhs.r == rhs.r and lhs.g == rhs.g and lhs.b == rhs.b; +} + +inline bool operator!=(Color lhs, Color rhs) +{ + return not (lhs == rhs); +} + Color str_to_color(StringView color); String color_to_str(Color color); @@ -47,6 +55,11 @@ void option_from_string(StringView str, Color& color); bool is_color_name(StringView color); +inline size_t hash_value(const Color& val) +{ + return hash_values(val.color, val.r, val.g, val.b); +} + } #endif // color_hh_INCLUDED diff --git a/src/command_manager.cc b/src/command_manager.cc index 02d95949..390b3e99 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -189,7 +189,7 @@ Token parse_percent_token(StringView line, ByteCount& pos) type_name + "'"}; Token::Type type = token_type(type_name); - static const std::unordered_map matching_delimiters = { + static const UnorderedMap matching_delimiters = { { '(', ')' }, { '[', ']' }, { '{', '}' }, { '<', '>' } }; diff --git a/src/command_manager.hh b/src/command_manager.hh index ca397a8f..90b583f9 100644 --- a/src/command_manager.hh +++ b/src/command_manager.hh @@ -9,8 +9,8 @@ #include "parameters_parser.hh" #include "string.hh" #include "utils.hh" +#include "unordered_map.hh" -#include #include #include @@ -88,7 +88,7 @@ private: CommandFlags flags; CommandCompleter completer; }; - using CommandMap = std::unordered_map; + using CommandMap = UnorderedMap; CommandMap m_commands; CommandMap::const_iterator find_command(const Context& context, diff --git a/src/coord.hh b/src/coord.hh index dbae5001..ed9347a5 100644 --- a/src/coord.hh +++ b/src/coord.hh @@ -2,6 +2,7 @@ #define coord_hh_INCLUDED #include "units.hh" +#include "hash.hh" namespace Kakoune { @@ -92,6 +93,11 @@ struct ByteCoord : LineAndColumn : LineAndColumn(line, column) {} }; +inline size_t hash_value(const ByteCoord& val) +{ + return hash_values(val.line, val.column); +} + struct CharCoord : LineAndColumn { [[gnu::always_inline]] @@ -99,6 +105,11 @@ struct CharCoord : LineAndColumn : LineAndColumn(line, column) {} }; +inline size_t hash_value(const CharCoord& val) +{ + return hash_values(val.line, val.column); +} + struct ByteCoordAndTarget : ByteCoord { [[gnu::always_inline]] @@ -112,6 +123,11 @@ struct ByteCoordAndTarget : ByteCoord CharCount target; }; +inline size_t hash_value(const ByteCoordAndTarget& val) +{ + return hash_values(val.line, val.column, val.target); +} + } #endif // coord_hh_INCLUDED diff --git a/src/env_vars.hh b/src/env_vars.hh index 89d3459e..cbab16ed 100644 --- a/src/env_vars.hh +++ b/src/env_vars.hh @@ -1,13 +1,13 @@ #ifndef env_vars_hh_INCLUDED #define env_vars_hh_INCLUDED -#include +#include "unordered_map.hh" namespace Kakoune { class String; -using EnvVarMap = std::unordered_map; +using EnvVarMap = UnorderedMap; EnvVarMap get_env_vars(); diff --git a/src/face_registry.hh b/src/face_registry.hh index 7e77c1cc..f99d6b12 100644 --- a/src/face_registry.hh +++ b/src/face_registry.hh @@ -4,8 +4,7 @@ #include "face.hh" #include "utils.hh" #include "completion.hh" - -#include +#include "unordered_map.hh" namespace Kakoune { @@ -30,7 +29,7 @@ private: FaceOrAlias(Face face = Face{}) : face(face) {} }; - std::unordered_map m_aliases; + UnorderedMap m_aliases; }; inline Face get_face(const String& facedesc) diff --git a/src/file.cc b/src/file.cc index 19ef313a..5bab7304 100644 --- a/src/file.cc +++ b/src/file.cc @@ -356,7 +356,7 @@ std::vector complete_command(StringView prefix, ByteCount cursor_pos) TimeSpec mtime = {}; std::vector commands; }; - static std::unordered_map command_cache; + static UnorderedMap command_cache; std::vector path; if (dir_end != -1) diff --git a/src/hash.cc b/src/hash.cc new file mode 100644 index 00000000..2ef9262d --- /dev/null +++ b/src/hash.cc @@ -0,0 +1,68 @@ +#include "hash.hh" + +#include + +namespace Kakoune +{ + +[[gnu::always_inline]] +static inline uint32_t rotl(uint32_t x, int8_t r) +{ + return (x << r) | (x >> (32 - r)); +} + +[[gnu::always_inline]] +static inline uint32_t fmix(uint32_t h) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +// murmur3 hash, based on https://github.com/PeterScott/murmur3 +size_t hash_data(const char* input, size_t len) +{ + const uint8_t* data = reinterpret_cast(input); + uint32_t hash = 0x1235678; + constexpr uint32_t c1 = 0xcc9e2d51; + constexpr uint32_t c2 = 0x1b873593; + + const int nblocks = len / 4; + const uint32_t* blocks = reinterpret_cast(data + nblocks*4); + + for (int i = -nblocks; i; ++i) + { + uint32_t key = blocks[i]; + key *= c1; + key = rotl(key, 15); + key *= c2; + + hash ^= key; + hash = rotl(hash, 13); + hash = hash * 5 + 0xe6546b64; + } + + const uint8_t* tail = data + nblocks * 4; + uint32_t key = 0; + switch (len & 3) + { + case 3: key ^= tail[2] << 16; + case 2: key ^= tail[1] << 8; + case 1: key ^= tail[0]; + key *= c1; + key = rotl(key,15); + key *= c2; + hash ^= key; + } + + hash ^= len; + hash = fmix(hash); + + return hash; +} + +} diff --git a/src/hash.hh b/src/hash.hh new file mode 100644 index 00000000..838fdffa --- /dev/null +++ b/src/hash.hh @@ -0,0 +1,57 @@ +#ifndef hash_hh_INCLUDED +#define hash_hh_INCLUDED + +#include +#include + +namespace Kakoune +{ + +size_t hash_data(const char* data, size_t len); + +template +typename std::enable_if::value, size_t>::type +hash_value(const Type& val) +{ + return std::hash()(val); +} + +template +typename std::enable_if::value, size_t>::type +hash_value(const Type& val) +{ + return hash_value((typename std::underlying_type::type)val); +} + +template +size_t hash_values(Type&& t) +{ + return hash_value(std::forward(t)); +} + +template +size_t hash_values(Type&& t, RemainingTypes&&... rt) +{ + size_t seed = hash_values(std::forward(rt)...); + return seed ^ (hash_value(std::forward(t)) + 0x9e3779b9 + + (seed << 6) + (seed >> 2)); +} + +template +size_t hash_value(const std::pair& val) +{ + return hash_values(val.first, val.second); +} + +template +struct Hash +{ + size_t operator()(const Type& val) const + { + return hash_value(val); + } +}; + +} + +#endif // hash_hh_INCLUDED diff --git a/src/highlighter.hh b/src/highlighter.hh index 88003dc0..bf67cbcb 100644 --- a/src/highlighter.hh +++ b/src/highlighter.hh @@ -9,22 +9,6 @@ #include -namespace std -{ - -template<> -struct hash -{ - size_t operator()(const Kakoune::ByteCoord& val) const - { - size_t seed = std::hash()((int)val.line); - return seed ^ (std::hash()((int)val.column) + 0x9e3779b9 + - (seed << 6) + (seed >> 2)); - } -}; - -} - namespace Kakoune { diff --git a/src/highlighters.cc b/src/highlighters.cc index 354bed0d..4f999230 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -1017,7 +1017,7 @@ private: { size_t timestamp = 0; std::vector matches; - std::unordered_map regions; + UnorderedMap regions; }; BufferSideCache m_cache; diff --git a/src/hook_manager.hh b/src/hook_manager.hh index 93a67ef7..5aa52b2f 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -2,8 +2,7 @@ #define hook_manager_hh_INCLUDED #include "id_map.hh" - -#include +#include "unordered_map.hh" namespace Kakoune { @@ -29,7 +28,7 @@ private: friend class Scope; HookManager* m_parent; - std::unordered_map> m_hook; + UnorderedMap> m_hook; }; } diff --git a/src/input_handler.cc b/src/input_handler.cc index ea6da4b0..ae6ac83b 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -9,12 +9,11 @@ #include "normal.hh" #include "regex.hh" #include "register_manager.hh" +#include "unordered_map.hh" #include "user_interface.hh" #include "utf8.hh" #include "window.hh" -#include - namespace Kakoune { @@ -736,10 +735,10 @@ private: bool m_autoshowcompl; Mode m_mode = Mode::Default; - static std::unordered_map> ms_history; + static UnorderedMap> ms_history; std::vector::iterator m_history_it; }; -std::unordered_map> Prompt::ms_history; +UnorderedMap> Prompt::ms_history; class NextKey : public InputMode { diff --git a/src/interned_string.hh b/src/interned_string.hh index fd79de2c..41a1b034 100644 --- a/src/interned_string.hh +++ b/src/interned_string.hh @@ -3,8 +3,7 @@ #include "string.hh" #include "utils.hh" - -#include +#include "unordered_map.hh" namespace Kakoune { @@ -20,7 +19,7 @@ private: void acquire(size_t slot); void release(size_t slot) noexcept; - std::unordered_map m_slot_map; + UnorderedMap m_slot_map; std::vector m_free_slots; using DataAndRefCount = std::pair, int>; std::vector m_storage; @@ -118,18 +117,11 @@ private: size_t m_slot = -1; }; +inline size_t hash_value(const Kakoune::InternedString& str) +{ + return hash_data(str.data(), (int)str.length()); } -namespace std -{ - template<> - struct hash - { - size_t operator()(const Kakoune::InternedString& str) const - { - return Kakoune::hash_data(str.data(), (int)str.length()); - } - }; } #endif // interned_string_hh_INCLUDED diff --git a/src/keymap_manager.cc b/src/keymap_manager.cc index 0d376a1b..74323a84 100644 --- a/src/keymap_manager.cc +++ b/src/keymap_manager.cc @@ -1,19 +1,7 @@ #include "keymap_manager.hh" #include "memoryview.hh" - -namespace std -{ - -template<> struct hash -{ - size_t operator()(Kakoune::KeymapMode val) const - { - return hash{}((int)val); - } -}; - -} +#include "assert.hh" namespace Kakoune { diff --git a/src/keymap_manager.hh b/src/keymap_manager.hh index 5743a18e..b7f7019b 100644 --- a/src/keymap_manager.hh +++ b/src/keymap_manager.hh @@ -2,9 +2,9 @@ #define keymap_manager_hh_INCLUDED #include "keys.hh" -#include "utils.hh" +#include "hash.hh" +#include "unordered_map.hh" -#include #include namespace Kakoune @@ -43,7 +43,8 @@ private: KeymapManager* m_parent; using KeyList = std::vector; - using Keymap = std::unordered_map, KeyList>; + using KeyAndMode = std::pair; + using Keymap = UnorderedMap; Keymap m_mapping; }; diff --git a/src/keys.hh b/src/keys.hh index 3123f7cc..92ae0f70 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -3,6 +3,7 @@ #include "unicode.hh" #include "flags.hh" +#include "hash.hh" #include @@ -11,7 +12,7 @@ namespace Kakoune struct Key { - enum class Modifiers + enum class Modifiers : int { None = 0, Control = 1 << 0, @@ -78,21 +79,8 @@ constexpr Key alt(Codepoint key) { return { Key::Modifiers::Alt, key }; } constexpr Key ctrl(Codepoint key) { return { Key::Modifiers::Control, key }; } constexpr Key ctrlalt(Codepoint key) { return { Key::Modifiers::ControlAlt, key }; } -} - -namespace std -{ - -template<> -struct hash -{ - size_t operator()(Kakoune::Key key) const - { - return static_cast(key.modifiers) * 1024 + key.key; - } -}; +inline size_t hash_value(const Key& key) { return hash_values(key.modifiers, key.key); } } - #endif // keys_hh_INCLUDED diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 896c76a8..b11f5a58 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -166,7 +166,7 @@ static int nc_color(Color color) static int get_color_pair(const Face& face) { using ColorPair = std::pair; - static std::map colorpairs; + static UnorderedMap colorpairs; static int next_pair = 1; ColorPair colors{face.fg, face.bg}; diff --git a/src/normal.hh b/src/normal.hh index 45057c48..4baa21df 100644 --- a/src/normal.hh +++ b/src/normal.hh @@ -2,9 +2,9 @@ #define normal_hh_INCLUDED #include "keys.hh" +#include "unordered_map.hh" #include -#include namespace Kakoune { @@ -23,7 +23,7 @@ struct NormalCmdDesc std::function func; }; -using KeyMap = std::unordered_map; +using KeyMap = UnorderedMap; extern KeyMap keymap; } diff --git a/src/option_types.hh b/src/option_types.hh index 739ab7a5..7b6dfe93 100644 --- a/src/option_types.hh +++ b/src/option_types.hh @@ -6,10 +6,10 @@ #include "units.hh" #include "coord.hh" #include "memoryview.hh" +#include "unordered_map.hh" #include #include -#include namespace Kakoune { @@ -68,7 +68,7 @@ bool option_add(std::vector& opt, const std::vector& vec) } template -String option_to_string(const std::unordered_map& opt) +String option_to_string(const UnorderedMap& opt) { String res; for (auto it = begin(opt); it != end(opt); ++it) @@ -83,7 +83,7 @@ String option_to_string(const std::unordered_map& opt) } template -void option_from_string(StringView str, std::unordered_map& opt) +void option_from_string(StringView str, UnorderedMap& opt) { opt.clear(); std::vector elems = split(str, list_separator, '\\'); diff --git a/src/register_manager.hh b/src/register_manager.hh index 97f84fc0..e4391c05 100644 --- a/src/register_manager.hh +++ b/src/register_manager.hh @@ -3,8 +3,8 @@ #include "register.hh" #include "utils.hh" +#include "unordered_map.hh" -#include #include #include @@ -21,7 +21,7 @@ public: void register_dynamic_register(char reg, RegisterRetriever function); protected: - std::unordered_map> m_registers; + UnorderedMap> m_registers; }; } diff --git a/src/remote.cc b/src/remote.cc index 3f8cbde2..08a13e39 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -82,7 +82,7 @@ public: } template - void write(const std::unordered_map& map) + void write(const UnorderedMap& map) { write(map.size()); for (auto& val : map) @@ -230,10 +230,10 @@ DisplayBuffer read(int socket) } template -std::unordered_map read_map(int socket) +UnorderedMap read_map(int socket) { uint32_t size = read(socket); - std::unordered_map res; + UnorderedMap res; while (size--) { auto key = read(socket); diff --git a/src/string.cc b/src/string.cc index 14c680c9..152b90aa 100644 --- a/src/string.cc +++ b/src/string.cc @@ -173,64 +173,4 @@ std::vector wrap_lines(StringView text, CharCount max_width) return lines; } -[[gnu::always_inline]] -static inline uint32_t rotl(uint32_t x, int8_t r) -{ - return (x << r) | (x >> (32 - r)); -} - -[[gnu::always_inline]] -static inline uint32_t fmix(uint32_t h) -{ - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -// murmur3 hash, based on https://github.com/PeterScott/murmur3 -size_t hash_data(const char* input, size_t len) -{ - const uint8_t* data = reinterpret_cast(input); - uint32_t hash = 0x1235678; - constexpr uint32_t c1 = 0xcc9e2d51; - constexpr uint32_t c2 = 0x1b873593; - - const int nblocks = len / 4; - const uint32_t* blocks = reinterpret_cast(data + nblocks*4); - - for (int i = -nblocks; i; ++i) - { - uint32_t key = blocks[i]; - key *= c1; - key = rotl(key, 15); - key *= c2; - - hash ^= key; - hash = rotl(hash, 13); - hash = hash * 5 + 0xe6546b64; - } - - const uint8_t* tail = data + nblocks * 4; - uint32_t key = 0; - switch (len & 3) - { - case 3: key ^= tail[2] << 16; - case 2: key ^= tail[1] << 8; - case 1: key ^= tail[0]; - key *= c1; - key = rotl(key,15); - key *= c2; - hash ^= key; - } - - hash ^= len; - hash = fmix(hash); - - return hash; -} - } diff --git a/src/string.hh b/src/string.hh index eefe6985..afab4486 100644 --- a/src/string.hh +++ b/src/string.hh @@ -3,6 +3,7 @@ #include "units.hh" #include "utf8.hh" +#include "hash.hh" #include #include @@ -267,29 +268,16 @@ String expand_tabs(StringView line, CharCount tabstop, CharCount col = 0); std::vector wrap_lines(StringView text, CharCount max_width); -size_t hash_data(const char* data, size_t len); - +inline size_t hash_value(const Kakoune::String& str) +{ + return hash_data(str.data(), (int)str.length()); } -namespace std +inline size_t hash_value(const Kakoune::StringView& str) { - template<> - struct hash : hash - { - size_t operator()(const Kakoune::String& str) const - { - return hash::operator()(str); - } - }; + return hash_data(str.data(), (int)str.length()); +} - template<> - struct hash - { - size_t operator()(Kakoune::StringView str) const - { - return Kakoune::hash_data(str.data(), (int)str.length()); - } - }; } #endif // string_hh_INCLUDED diff --git a/src/units.hh b/src/units.hh index 69ecffdb..5091c324 100644 --- a/src/units.hh +++ b/src/units.hh @@ -1,6 +1,8 @@ #ifndef units_hh_INCLUDED #define units_hh_INCLUDED +#include "hash.hh" + #include namespace Kakoune @@ -119,6 +121,8 @@ struct LineCount : public StronglyTypedNumber constexpr LineCount(int value = 0) : StronglyTypedNumber(value) {} }; +inline size_t hash_value(LineCount val) { return hash_value((int)val); } + [[gnu::always_inline]] inline constexpr LineCount operator"" _line(unsigned long long int value) { @@ -131,6 +135,8 @@ struct ByteCount : public StronglyTypedNumber constexpr ByteCount(int value = 0) : StronglyTypedNumber(value) {} }; +inline size_t hash_value(ByteCount val) { return hash_value((int)val); } + [[gnu::always_inline]] inline constexpr ByteCount operator"" _byte(unsigned long long int value) { @@ -149,6 +155,8 @@ inline constexpr CharCount operator"" _char(unsigned long long int value) return CharCount(value); } +inline size_t hash_value(CharCount val) { return hash_value((int)val); } + } #endif // units_hh_INCLUDED diff --git a/src/unordered_map.hh b/src/unordered_map.hh new file mode 100644 index 00000000..a3074ad6 --- /dev/null +++ b/src/unordered_map.hh @@ -0,0 +1,17 @@ +#ifndef unordered_map_hh_INCLUDED +#define unordered_map_hh_INCLUDED + +#include "hash.hh" + +#include + +namespace Kakoune +{ + +template +using UnorderedMap = std::unordered_map>; + +} + +#endif // unordered_map_hh_INCLUDED + diff --git a/src/user_interface.hh b/src/user_interface.hh index b0884394..f401bf14 100644 --- a/src/user_interface.hh +++ b/src/user_interface.hh @@ -2,9 +2,9 @@ #define user_interface_hh_INCLUDED #include "safe_ptr.hh" +#include "unordered_map.hh" #include -#include namespace Kakoune { @@ -63,7 +63,7 @@ public: virtual void set_input_callback(InputCallback callback) = 0; - using Options = std::unordered_map; + using Options = UnorderedMap; virtual void set_ui_options(const Options& options) = 0; }; diff --git a/src/utils.hh b/src/utils.hh index e4d392ff..c8e29f89 100644 --- a/src/utils.hh +++ b/src/utils.hh @@ -185,21 +185,4 @@ bool is_in_range(const T& val, const T& min, const T& max) } -// std::pair hashing -namespace std -{ - -template -struct hash> -{ - size_t operator()(const std::pair& val) const - { - size_t seed = std::hash()(val.second); - return seed ^ (std::hash()(val.first) + 0x9e3779b9 + - (seed << 6) + (seed >> 2)); - } -}; - -} - #endif // utils_hh_INCLUDED diff --git a/src/value.hh b/src/value.hh index 86bbfea2..e663513a 100644 --- a/src/value.hh +++ b/src/value.hh @@ -1,11 +1,11 @@ #ifndef value_hh_INCLUDED #define value_hh_INCLUDED -#include -#include - +#include "unordered_map.hh" #include "units.hh" +#include + namespace Kakoune { @@ -76,23 +76,10 @@ struct ValueId : public StronglyTypedNumber } }; -using ValueMap = std::unordered_map; +inline size_t hash_value(ValueId val) { return hash_value((int)val); } + +using ValueMap = UnorderedMap; } -namespace std -{ - -template<> -struct hash -{ - size_t operator()(Kakoune::ValueId val) const - { - return std::hash()((int)val); - } -}; - -} - - #endif // value_hh_INCLUDED diff --git a/src/word_db.hh b/src/word_db.hh index 999d03b0..1e9e4318 100644 --- a/src/word_db.hh +++ b/src/word_db.hh @@ -28,7 +28,7 @@ public: UsedChars letters; int refcount; }; - using WordList = std::unordered_map; + using WordList = UnorderedMap; private: using LineToWords = std::vector>;