Simplify how functions are stored and passed. This is the first step in allowing us to sort functions so that dispatches are attempted in an organized order (as opposed to just the order they were added in).

Should have resulted in a speed imrovement too - fewer string copies during dispatch.
This commit is contained in:
Jason Turner
2010-11-15 05:52:48 +00:00
parent 3aee589274
commit 7ef1b81504
4 changed files with 81 additions and 63 deletions

View File

@@ -119,7 +119,7 @@ namespace chaiscript
class Dispatch_Function : public Proxy_Function_Base
{
public:
Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
Dispatch_Function(const std::vector<Proxy_Function> &t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs)),
m_funcs(t_funcs)
{
@@ -139,39 +139,26 @@ namespace chaiscript
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
function_vec::const_iterator begin = m_funcs.begin();
const function_vec::const_iterator end = m_funcs.end();
std::vector<Const_Proxy_Function> fs;
while (begin != end)
{
fs.push_back(begin->second);
++begin;
}
return fs;
return std::vector<Const_Proxy_Function>(m_funcs.begin(), m_funcs.end());
}
virtual int get_arity() const
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
typedef std::vector<Proxy_Function> function_vec;
function_vec::const_iterator begin = m_funcs.begin();
const function_vec::const_iterator end = m_funcs.end();
if (begin != end)
{
int arity = begin->second->get_arity();
int arity = (*begin)->get_arity();
++begin;
while (begin != end)
{
if (arity != begin->second->get_arity())
if (arity != (*begin)->get_arity())
{
// The arities in the list do not match, so it's unspecified
return -1;
@@ -188,14 +175,14 @@ namespace chaiscript
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
typedef std::vector<Proxy_Function> function_vec;
function_vec::const_iterator begin = m_funcs.begin();
function_vec::const_iterator end = m_funcs.end();
while (begin != end)
{
if (begin->second->call_match(vals))
if ((*begin)->call_match(vals))
{
return true;
} else {
@@ -218,18 +205,18 @@ namespace chaiscript
}
private:
std::vector<std::pair<std::string, Proxy_Function > > m_funcs;
std::vector<Proxy_Function> m_funcs;
static std::vector<Type_Info> build_type_infos(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
static std::vector<Type_Info> build_type_infos(const std::vector<Proxy_Function> &t_funcs)
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
typedef std::vector<Proxy_Function> function_vec;
function_vec::const_iterator begin = t_funcs.begin();
const function_vec::const_iterator end = t_funcs.end();
if (begin != end)
{
std::vector<Type_Info> type_infos = begin->second->get_param_types();
std::vector<Type_Info> type_infos = (*begin)->get_param_types();
++begin;
@@ -237,7 +224,7 @@ namespace chaiscript
while (begin != end)
{
std::vector<Type_Info> param_types = begin->second->get_param_types();
std::vector<Type_Info> param_types = (*begin)->get_param_types();
if (param_types.size() != type_infos.size())
{
@@ -316,7 +303,7 @@ namespace chaiscript
struct State
{
std::multimap<std::string, Proxy_Function> m_functions;
std::map<std::string, std::vector<Proxy_Function> > m_functions;
std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types;
std::set<std::string> m_reserved_words;
@@ -486,23 +473,20 @@ namespace chaiscript
}
// If all that failed, then check to see if it's a function
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs = get_function(name);
std::vector<Proxy_Function> funcs = get_function(name);
if (funcs.empty())
{
throw std::range_error("Object not known: " + name);
} else {
if (funcs.size() == 1)
{
// Return the first item if there is only one,
// no reason to take the cast of the extra level of dispatch
return const_var(funcs.begin()->second);
return const_var(*funcs.begin());
} else {
return Boxed_Value(Const_Proxy_Function(new Dispatch_Function(funcs)));
}
Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs)));
return f;
}
}
@@ -578,17 +562,25 @@ namespace chaiscript
/**
* Return a function by name
*/
std::vector<std::pair<std::string, Proxy_Function > >
std::vector< Proxy_Function >
get_function(const std::string &t_name) const
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= get_functions_int().equal_range(t_name);
const std::map<std::string, std::vector<Proxy_Function> > &funs = get_functions_int();
std::map<std::string, std::vector<Proxy_Function> >::const_iterator itr
= funs.find(t_name);
if (itr != funs.end())
{
return itr->second;
} else {
return std::vector<Proxy_Function>();
}
return std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >(range.first, range.second);
}
/**
@@ -600,7 +592,7 @@ namespace chaiscript
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
const std::multimap<std::string, Proxy_Function> &functions = get_functions_int();
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int();
return functions.find(name) != functions.end();
}
@@ -612,9 +604,23 @@ namespace chaiscript
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
std::vector<std::pair<std::string, Proxy_Function> > rets;
const std::multimap<std::string, Proxy_Function> &functions = get_functions_int();
return std::vector<std::pair<std::string, Proxy_Function > >(functions.begin(), functions.end());
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int();
for (std::map<std::string, std::vector<Proxy_Function> >::const_iterator itr = functions.begin();
itr != functions.end();
++itr)
{
for (std::vector<Proxy_Function>::const_iterator itr2 = itr->second.begin();
itr2 != itr->second.end();
++itr2)
{
rets.push_back(std::make_pair(itr->first, *itr2));
}
}
return rets;
}
void add_reserved_word(const std::string &name)
@@ -628,7 +634,7 @@ namespace chaiscript
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{
std::vector<std::pair<std::string, Proxy_Function> > functions = get_function(t_name);
std::vector<Proxy_Function> functions = get_function(t_name);
return dispatch(functions.begin(), functions.end(), params);
}
@@ -787,12 +793,12 @@ namespace chaiscript
return *(m_stack_holder->stack);
}
const std::multimap<std::string, Proxy_Function> &get_functions_int() const
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
{
return m_state.m_functions;
}
std::multimap<std::string, Proxy_Function> &get_functions_int()
std::map<std::string, std::vector<Proxy_Function> > &get_functions_int()
{
return m_state.m_functions;
}
@@ -818,25 +824,36 @@ namespace chaiscript
* true if the function was added, false if a function with the
* same signature and name already exists.
*/
bool add_function(const Proxy_Function &f, const std::string &t_name)
bool add_function(const Proxy_Function &t_f, const std::string &t_name)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= m_state.m_functions.equal_range(t_name);
std::map<std::string, std::vector<Proxy_Function> > &funcs = get_functions_int();
while (range.first != range.second)
std::map<std::string, std::vector<Proxy_Function> >::iterator itr
= funcs.find(t_name);
if (itr != funcs.end())
{
if ((*f) == *(range.first->second))
std::vector<Proxy_Function> &vec = itr->second;
for (std::vector<Proxy_Function>::const_iterator itr2 = vec.begin();
itr2 != vec.end();
++itr2)
{
if ((*t_f) == *(*itr2))
{
return false;
}
++range.first;
}
m_state.m_functions.insert(std::make_pair(t_name, f));
vec.push_back(t_f);
} else {
std::vector<Proxy_Function> vec;
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec));
}
return true;
}

View File

@@ -30,7 +30,7 @@ namespace chaiscript
*/
template<typename FunctionType>
boost::function<FunctionType>
functor(const std::vector<std::pair<std::string, Const_Proxy_Function > > &funcs)
functor(const std::vector<Const_Proxy_Function> &funcs)
{
FunctionType *p=0;
return detail::build_function_caller_helper(p, funcs);
@@ -53,8 +53,8 @@ namespace chaiscript
boost::function<FunctionType>
functor(Const_Proxy_Function func)
{
std::vector<std::pair<std::string, Const_Proxy_Function > > funcs;
funcs.push_back(std::make_pair(std::string(), func));
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func);
return functor<FunctionType>(funcs);
}

View File

@@ -32,7 +32,7 @@ namespace chaiscript
template<typename Ret>
struct Function_Caller_Ret
{
static Ret call(const std::vector<std::pair<std::string, Const_Proxy_Function > > &t_funcs,
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch(t_funcs, params));
@@ -45,7 +45,7 @@ namespace chaiscript
template<>
struct Function_Caller_Ret<void>
{
static void call(const std::vector<std::pair<std::string, Const_Proxy_Function > > &t_funcs,
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch(t_funcs, params);
@@ -70,7 +70,7 @@ namespace chaiscript
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<std::pair<std::string, Const_Proxy_Function > > &funcs
Ret function_caller(const std::vector<Const_Proxy_Function> &funcs
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
@@ -85,13 +85,14 @@ namespace chaiscript
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, Const_Proxy_Function> > &funcs)
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<Const_Proxy_Function> &funcs)
{
if (funcs.size() == 1)
{
boost::shared_ptr<const Proxy_Function_Impl<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> > pfi =
boost::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> >
(funcs[0].second);
(funcs[0]);
if (pfi)
{
return pfi->internal_function();

View File

@@ -583,9 +583,9 @@ namespace chaiscript
while (begin != end)
{
try {
if (begin->second->filter(plist))
if ((*begin)->filter(plist))
{
return (*begin->second)(plist);
return (*(*begin))(plist);
}
} catch (const bad_boxed_cast &) {
//parameter failed to cast, try again