From 15eb78bd8f9fd85b235506412c17975d73bccbff Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 31 Aug 2015 08:41:47 -0600 Subject: [PATCH] Move to indexed function storage --- .../chaiscript/dispatchkit/dispatchkit.hpp | 141 +++++++++++------- 1 file changed, 87 insertions(+), 54 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 4557870..3ded2df 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -417,9 +417,9 @@ namespace chaiscript struct State { - std::map > m_functions; - std::map m_function_objects; - std::map m_boxed_functions; + std::vector>>> m_functions; + std::vector> m_function_objects; + std::vector> m_boxed_functions; std::map m_global_objects; Type_Name_Map m_types; std::set m_reserved_words; @@ -518,7 +518,7 @@ namespace chaiscript throw chaiscript::exception::global_non_const(); } - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) { @@ -533,7 +533,7 @@ namespace chaiscript { validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); const auto itr = m_state.m_global_objects.find(name); if (itr == m_state.m_global_objects.end()) @@ -551,7 +551,7 @@ namespace chaiscript { validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + chaiscript::detail::threading::unique_lock l(m_mutex); if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) { @@ -648,19 +648,18 @@ namespace chaiscript return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)][loc & static_cast(Loc::loc_mask)].second; } - // Is the value we are looking for a global? - { - chaiscript::detail::threading::shared_lock l(m_global_object_mutex); + // Is the value we are looking for a global or function? + chaiscript::detail::threading::shared_lock l(m_mutex); - const auto itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) - { - return itr->second; - } + const auto itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) + { + return itr->second; } - // If all that failed, then check to see if it's a function - return get_function_object(name); + // no? is it a function object? + return get_function_object_int(name); + } /// Registers a new named type @@ -719,19 +718,19 @@ namespace chaiscript } /// Return a function by name - std::vector< Proxy_Function > get_function(const std::string &t_name) const + std::shared_ptr> get_function(const std::string &t_name) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &funs = get_functions_int(); - auto itr = funs.find(t_name); + auto itr = find_keyed_value(funs, t_name); if (itr != funs.end()) { return itr->second; } else { - return std::vector(); + return std::make_shared>(); } } @@ -739,12 +738,19 @@ namespace chaiscript /// \throws std::range_error if it does not Boxed_Value get_function_object(const std::string &t_name) const { -// std::cout << "Getting function object: " << t_name << '\n'; chaiscript::detail::threading::shared_lock l(m_mutex); + return get_function_object_int(t_name); + } + + /// \returns a function object (Boxed_Value wrapper) if it exists + /// \throws std::range_error if it does not + /// \warn does not obtain a mutex lock. \sa get_function_object for public version + Boxed_Value get_function_object_int(const std::string &t_name) const + { const auto &funs = get_boxed_functions_int(); - auto itr = funs.find(t_name); + auto itr = find_keyed_value(funs, t_name); if (itr != funs.end()) { @@ -754,13 +760,14 @@ namespace chaiscript } } + /// Return true if a function exists bool function_exists(const std::string &name) const { chaiscript::detail::threading::shared_lock l(m_mutex); const auto &functions = get_functions_int(); - return functions.find(name) != functions.end(); + return find_keyed_value(functions, name) != functions.end(); } /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, @@ -817,11 +824,8 @@ namespace chaiscript } // add the global values - { - chaiscript::detail::threading::shared_lock l(m_global_object_mutex); - - retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); - } + chaiscript::detail::threading::shared_lock l(m_mutex); + retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); return retval; } @@ -858,7 +862,7 @@ namespace chaiscript for (const auto & function : functions) { - for (const auto & internal_func : function.second) + for (const auto & internal_func : *function.second) { rets.emplace_back(function.first, internal_func); } @@ -941,14 +945,14 @@ namespace chaiscript } }; - if (is_attribute_call(funs, params, t_has_params)) { - return do_attribute_call(1, params, funs, m_conversions); + if (is_attribute_call(*funs, params, t_has_params)) { + return do_attribute_call(1, params, *funs, m_conversions); } else { std::exception_ptr except; - if (!funs.empty()) { + if (!funs->empty()) { try { - return dispatch::dispatch(funs, params, m_conversions); + return dispatch::dispatch(*funs, params, m_conversions); } catch(chaiscript::exception::dispatch_error&) { except = std::current_exception(); } @@ -960,7 +964,8 @@ namespace chaiscript const auto functions = [&]()->std::vector { std::vector fs; - for (const auto &f : get_function("method_missing")) + const auto method_missing_funs = get_function("method_missing"); + for (const auto &f : *method_missing_funs) { if(f->compare_first_type(params[0], m_conversions)) { fs.push_back(f); @@ -996,7 +1001,7 @@ namespace chaiscript if (except) { std::rethrow_exception(except); } else { - throw chaiscript::exception::dispatch_error(params, std::vector(funs.begin(), funs.end())); + throw chaiscript::exception::dispatch_error(params, std::vector(funs->begin(), funs->end())); } } } @@ -1008,7 +1013,8 @@ namespace chaiscript Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const { - Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions); + const auto funs = get_function(t_name); + Boxed_Value bv = dispatch::dispatch(*funs, params, m_conversions); // the result of a clone is never to be marked as a return_value if (t_name == "clone") { bv.reset_return_value(); @@ -1140,7 +1146,6 @@ namespace chaiscript State get_state() const { chaiscript::detail::threading::shared_lock l(m_mutex); - chaiscript::detail::threading::shared_lock l2(m_global_object_mutex); return m_state; } @@ -1148,7 +1153,6 @@ namespace chaiscript void set_state(const State &t_state) { chaiscript::detail::threading::unique_lock l(m_mutex); - chaiscript::detail::threading::unique_lock l2(m_global_object_mutex); m_state = t_state; } @@ -1245,32 +1249,32 @@ namespace chaiscript private: - const std::map &get_boxed_functions_int() const + const std::vector> &get_boxed_functions_int() const { return m_state.m_boxed_functions; } - std::map &get_boxed_functions_int() + std::vector> &get_boxed_functions_int() { return m_state.m_boxed_functions; } - const std::map &get_function_objects_int() const + const std::vector> &get_function_objects_int() const { return m_state.m_function_objects; } - std::map &get_function_objects_int() + std::vector> &get_function_objects_int() { return m_state.m_function_objects; } - const std::map > &get_functions_int() const + const std::vector>>> &get_functions_int() const { return m_state.m_functions; } - std::map > &get_functions_int() + std::vector>>> &get_functions_int() { return m_state.m_functions; } @@ -1384,6 +1388,38 @@ namespace chaiscript } } + 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.emplace_back(t_key, std::forward(t_value)); + } else { + typedef typename Container::value_type 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) + { + 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) + { + return std::find_if(t_c.begin(), t_c.end(), + [&t_key](const typename Container::value_type &o) { + return o.first == 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) @@ -1392,16 +1428,13 @@ namespace chaiscript auto &funcs = get_functions_int(); - auto itr = funcs.find(t_name); - - auto &func_objs = get_function_objects_int(); - auto &boxed_funcs = get_boxed_functions_int(); + auto itr = find_keyed_value(funcs, t_name); Proxy_Function new_func = [&]() -> Proxy_Function { if (itr != funcs.end()) { - auto &vec = itr->second; + auto vec = *itr->second; for (const auto &func : vec) { if ((*t_f) == *(func)) @@ -1412,26 +1445,26 @@ namespace chaiscript vec.push_back(t_f); std::stable_sort(vec.begin(), vec.end(), &function_less_than); - return std::make_shared(vec); + itr->second = std::make_shared>(vec); + return std::make_shared(std::move(vec)); } else if (t_f->has_arithmetic_param()) { // 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.insert(std::make_pair(t_name, vec)); + funcs.emplace_back(t_name, std::make_shared>(vec)); return std::make_shared(std::move(vec)); } else { - funcs.insert(std::make_pair(t_name, std::vector{t_f})); + funcs.emplace_back(t_name, std::make_shared>(std::initializer_list({t_f}))); return t_f; } }(); - boxed_funcs[t_name] = const_var(new_func); - func_objs[t_name] = std::move(new_func); + 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)); } mutable chaiscript::detail::threading::shared_mutex m_mutex; - mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex; Type_Conversions m_conversions;