From db72ab626fa7945b248cde25b5ef3617300e9086 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 24 Nov 2017 22:20:52 -0700 Subject: [PATCH] Consolidate hand-rolled flat maps --- include/chaiscript/chaiscript_defines.hpp | 12 +++ .../chaiscript/dispatchkit/dispatchkit.hpp | 99 +++++-------------- include/chaiscript/utility/quick_flat_map.hpp | 46 +++++++-- 3 files changed, 74 insertions(+), 83 deletions(-) diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 6c8ee78d..f0599e23 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -212,6 +212,18 @@ namespace chaiscript { return final_value(t, base, exponent, neg_exponent); } + struct str_equal { + [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { + return t_lhs == t_rhs; + } + template + [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { + return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); + } + struct is_transparent{}; + }; + + struct str_less { [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 7fac1721..34607a1d 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -389,7 +389,7 @@ namespace chaiscript using SmallVector = std::vector; - using Scope = utility::QuickFlatMap; + using Scope = utility::QuickFlatMap; using StackData = SmallVector; using Stacks = SmallVector; using Call_Param_List = SmallVector; @@ -430,14 +430,14 @@ namespace chaiscript public: using Type_Name_Map = std::map; - using Scope = utility::QuickFlatMap; + using Scope = utility::QuickFlatMap; using StackData = Stack_Holder::StackData; struct State { - std::vector>>> m_functions; - std::vector> m_function_objects; - std::vector> m_boxed_functions; + utility::QuickFlatMap>, str_equal> m_functions; + utility::QuickFlatMap m_function_objects; + utility::QuickFlatMap m_boxed_functions; std::map m_global_objects; Type_Name_Map m_types; }; @@ -745,9 +745,7 @@ namespace chaiscript const auto &funs = get_functions_int(); - auto itr = find_keyed_value(funs, t_name, t_hint); - - if (itr != funs.end()) + if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) { return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { @@ -771,9 +769,7 @@ namespace chaiscript { const auto &funs = get_boxed_functions_int(); - auto itr = find_keyed_value(funs, t_name, t_hint); - - if (itr != funs.end()) + if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) { return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { @@ -787,8 +783,7 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_mutex); - const auto &functions = get_functions_int(); - return find_keyed_value(functions, name) != functions.end(); + return get_functions_int().count(name) > 0; } /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, @@ -1246,32 +1241,32 @@ namespace chaiscript private: - const std::vector> &get_boxed_functions_int() const noexcept + const decltype(State::m_boxed_functions) &get_boxed_functions_int() const noexcept { return m_state.m_boxed_functions; } - std::vector> &get_boxed_functions_int() noexcept + decltype(State::m_boxed_functions) &get_boxed_functions_int() noexcept { return m_state.m_boxed_functions; } - const std::vector> &get_function_objects_int() const noexcept + const decltype(State::m_function_objects) &get_function_objects_int() const noexcept { return m_state.m_function_objects; } - std::vector> &get_function_objects_int() noexcept + decltype(State::m_function_objects) &get_function_objects_int() noexcept { return m_state.m_function_objects; } - const std::vector>>> &get_functions_int() const noexcept + const decltype(State::m_functions) &get_functions_int() const noexcept { return m_state.m_functions; } - std::vector>>> &get_functions_int() noexcept + decltype(State::m_functions) &get_functions_int() noexcept { return m_state.m_functions; } @@ -1360,63 +1355,17 @@ namespace chaiscript return false; } - - - template - static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value) - { - auto itr = find_keyed_value(t_c, t_key); - - if (itr == t_c.end()) { - t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here - t_c.emplace_back(t_key, std::forward(t_value)); - } else { - using value_type = typename Container::value_type; - *itr = value_type(t_key, std::forward(t_value)); - } - } - - template - static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key) noexcept - { - return std::find_if(t_c.begin(), t_c.end(), - [&t_key](const typename Container::value_type &o) { - return o.first == t_key; - }); - } - - template - static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key) noexcept - { - return std::find_if(t_c.begin(), t_c.end(), - [&t_key](const typename Container::value_type &o) { - return std::equal(o.first.begin(), o.first.end(), t_key.begin(), t_key.end()); - }); - } - - template - static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) noexcept - { - if (t_c.size() > t_hint && t_c[t_hint].first == t_key) { - return std::next(t_c.begin(), static_cast::difference_type>(t_hint)); - } else { - return find_keyed_value(t_c, t_key); - } - } - - /// Implementation detail for adding a function. /// \throws exception::name_conflict_error if there's a function matching the given one being added void add_function(const Proxy_Function &t_f, const std::string &t_name) { chaiscript::detail::threading::unique_lock l(m_mutex); - auto &funcs = get_functions_int(); - - auto itr = find_keyed_value(funcs, t_name); - Proxy_Function new_func = [&]() -> Proxy_Function { + auto &funcs = get_functions_int(); + auto itr = funcs.find(t_name); + if (itr != funcs.end()) { auto vec = *itr->second; @@ -1437,17 +1386,21 @@ namespace chaiscript // if the function is the only function but it also contains // arithmetic operators, we must wrap it in a dispatch function // to allow for automatic arithmetic type conversions - std::vector vec({t_f}); - funcs.emplace_back(t_name, std::make_shared>(vec)); + std::vector vec; + vec.push_back(t_f); + funcs.insert(std::pair{t_name, std::make_shared>(vec)}); return std::make_shared(std::move(vec)); } else { - funcs.emplace_back(t_name, std::make_shared>(std::initializer_list({t_f}))); + auto vec = std::make_shared>(); + vec->push_back(t_f); + funcs.insert(std::pair{t_name, vec}); return t_f; } }(); - add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func)); - add_keyed_value(get_function_objects_int(), t_name, std::move(new_func)); + + get_boxed_functions_int().insert_or_assign(t_name, const_var(new_func)); + get_function_objects_int().insert_or_assign(t_name, std::move(new_func)); } mutable chaiscript::detail::threading::shared_mutex m_mutex; diff --git a/include/chaiscript/utility/quick_flat_map.hpp b/include/chaiscript/utility/quick_flat_map.hpp index d19a2d19..35bc089d 100644 --- a/include/chaiscript/utility/quick_flat_map.hpp +++ b/include/chaiscript/utility/quick_flat_map.hpp @@ -3,15 +3,29 @@ namespace chaiscript::utility { - template + template> struct QuickFlatMap { - auto find(const Key &s) noexcept { - return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); + Comparator comparator; + + template + auto find(const Lookup &s) noexcept { + return std::find_if(std::begin(data), std::end(data), [&s, this](const auto &d) { return comparator(d.first, s); }); } - auto find(const Key &s) const noexcept { - return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); + template + auto find(const Lookup &s) const noexcept { + return std::find_if(std::cbegin(data), std::cend(data), [&s, this](const auto &d) { return comparator(d.first, s); }); + } + + template + auto find(const Lookup &s, const std::size_t t_hint) const noexcept { + if (data.size() > t_hint && comparator(data[t_hint].first, s)) { + const auto begin = std::cbegin(data); + return std::next(begin, static_cast>::difference_type>(t_hint)); + } else { + return find(s); + } } auto size() const noexcept { @@ -49,6 +63,7 @@ namespace chaiscript::utility { if (itr != data.end()) { return itr->second; } else { + grow(); return data.emplace_back(s, Value()).second; } } @@ -91,7 +106,8 @@ namespace chaiscript::utility { *itr = std::forward(m); return std::pair{itr, false}; } else { - return std::pair{data.emplace(itr, std::move(key), std::forward(m)), true}; + grow(); + return std::pair{data.emplace(data.end(), std::move(key), std::forward(m)), true}; } } @@ -100,10 +116,11 @@ namespace chaiscript::utility { auto insert_or_assign(const Key &key, M &&m) { if (auto itr = find(key); itr != data.end()) { - *itr = std::forward(m); + itr->second = std::forward(m); return std::pair{itr, false}; } else { - return std::pair{data.emplace(itr, key, std::forward(m)), true}; + grow(); + return std::pair{data.emplace(data.end(), key, std::forward(m)), true}; } } @@ -116,7 +133,8 @@ namespace chaiscript::utility { } } - size_t count(const Key &s) const noexcept { + template + size_t count(const Lookup &s) const noexcept { return (find(s) != data.end())?1:0; } @@ -131,10 +149,18 @@ namespace chaiscript::utility { if (const auto itr = find(value.first); itr != data.end()) { return std::pair{itr, false}; } else { - return std::pair{data.insert(itr, std::move(value)), true}; + grow(); + return std::pair{data.insert(data.end(), std::move(value)), true}; } } + void grow() { + if ((data.capacity() - data.size()) == 0) { + data.reserve(data.size() + 2); + } + } + + }; }