Get libc++ on ubuntu 14.04 working

The std::is_member_function_pointer<> template is broken on this version
of the libc++ standard library for const member functions.

To get ChaiScript to work with this, we had to work around the use of
automatically generated std::function wrappers in many cases. This
actually cleaned up the code in a few places and muddied it up in one.
This commit is contained in:
Jason Turner 2015-04-21 12:01:29 -06:00
parent 2f531355cd
commit 0ed9602ba9
10 changed files with 87 additions and 72 deletions

View File

@ -15,6 +15,12 @@
#endif #endif
#endif #endif
#include <vector>
#if defined( _LIBCPP_VERSION )
#define CHAISCRIPT_LIBCPP
#endif
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
#define CHAISCRIPT_WINDOWS #define CHAISCRIPT_WINDOWS
#endif #endif

View File

@ -14,63 +14,58 @@ namespace chaiscript
namespace detail namespace detail
{ {
struct Placeholder template<typename T>
{ T* get_pointer(T *t)
static std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)> placeholder() { {
return std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)>(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10); return t;
} }
};
template<int count, int maxcount, typename Sig> template<typename T>
struct Bind_First T* get_pointer(const std::reference_wrapper<T> &t)
{ {
template<typename F, typename ... InnerParams> return &t.get();
static std::function<Sig> bind(F&& f, InnerParams ... innerparams) }
{
return Bind_First<count - 1, maxcount, Sig>::bind(std::forward<F>(f), innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
}
};
template<int maxcount, typename Sig>
struct Bind_First<0, maxcount, Sig>
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
{
return std::bind(std::forward<F>(f), innerparams...);
}
};
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o) std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o)); return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return f(std::forward<O>(o), std::forward<Param>(param)...);
}
);
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o)); return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}
);
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o)); return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}
);
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o) std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o)); return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
});
} }
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(std::function<Ret (P1, Param...)> &&f, O&& o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(std::move(f), std::forward<O>(o));
}
} }
} }

View File

@ -357,7 +357,9 @@ namespace chaiscript
template<typename Function> template<typename Function>
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
{ {
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1); return [f](const dispatch::Proxy_Function_Base *b) {
return do_return_boxed_value_vector(f, b);
};
} }

View File

@ -247,7 +247,6 @@ namespace chaiscript
{ {
// cppcheck-suppress syntaxError // cppcheck-suppress syntaxError
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t); typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
typedef typename ContainerType::const_reference(ContainerType::*constindexoper)(size_t) const;
//In the interest of runtime safety for the m, we prefer the at() method for [] access, //In the interest of runtime safety for the m, we prefer the at() method for [] access,
//to throw an exception in an out of bounds condition. //to throw an exception in an out of bounds condition.
@ -255,8 +254,10 @@ namespace chaiscript
fun(std::function<typename ContainerType::reference (ContainerType *, int)> fun(std::function<typename ContainerType::reference (ContainerType *, int)>
(std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]"); (std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
m->add( m->add(
fun(std::function<typename ContainerType::const_reference (const ContainerType *, int)> fun<typename ContainerType::const_reference (const ContainerType &, int)>(
(std::mem_fn(static_cast<constindexoper>(&ContainerType::at)))), "[]"); [](const ContainerType &c, int index) -> typename ContainerType::const_reference {
return c.at(index);
}), "[]");
return m; return m;
} }

View File

@ -52,36 +52,17 @@ namespace chaiscript
template<typename Ret, typename Class, typename ... Args> template<typename Ret, typename Class, typename ... Args>
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const) std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
{ {
#ifdef CHAISCRIPT_MSVC #if defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_LIBCPP)
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for /// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
/// std::function for member function pointers seems to be broken in MSVC /// std::function for member function pointers seems to be broken in MSVC
return std::function<Ret(const Class &, Args...)>(std::mem_fn(func)); return std::function<Ret (const Class &, Args...)>([func](const Class &o, Args... args)->Ret {
return (o.*func)(std::forward<Args>(args)...);
});
#else #else
return std::function<Ret(const Class &, Args...)>(func); return std::function<Ret(const Class &, Args...)>(func);
#endif #endif
} }
template<bool Object>
struct Fun_Helper
{
template<typename T>
static Proxy_Function go(T t)
{
/// \todo is it possible to reduce the number of templates generated here?
return Proxy_Function(
static_cast<dispatch::Proxy_Function_Impl_Base *>(new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t))));
}
};
template<>
struct Fun_Helper<true>
{
template<typename T, typename Class>
static Proxy_Function go(T Class::* m)
{
return Proxy_Function(new Attribute_Access<T, Class>(m));
}
};
} }
} }
@ -106,9 +87,31 @@ namespace chaiscript
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T> template<typename T>
Proxy_Function fun(T t) Proxy_Function fun(const T &t)
{ {
return dispatch::detail::Fun_Helper<std::is_member_object_pointer<T>::value>::go(t); return Proxy_Function(
static_cast<dispatch::Proxy_Function_Impl_Base *>(new dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(t)) >::Signature>(dispatch::detail::to_function(t))));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*func)(Param...) const)
{
return Proxy_Function(
static_cast<dispatch::Proxy_Function_Impl_Base *>(new dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(func)) >::Signature>(dispatch::detail::to_function(func))));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*func)(Param...))
{
return Proxy_Function(
static_cast<dispatch::Proxy_Function_Impl_Base *>(new dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(func)) >::Signature>(dispatch::detail::to_function(func))));
}
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
{
return Proxy_Function(new dispatch::Attribute_Access<T, Class>(m));
} }
@ -149,9 +152,9 @@ namespace chaiscript
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T, typename Q> template<typename T, typename Q>
Proxy_Function fun(T t, const Q &q) Proxy_Function fun(T &&t, const Q &q)
{ {
return fun(detail::bind_first(t, q)); return fun(detail::bind_first(std::forward<T>(t), q));
} }
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it /// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
@ -175,9 +178,9 @@ namespace chaiscript
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T, typename Q, typename R> template<typename T, typename Q, typename R>
Proxy_Function fun(T t, const Q &q, const R &r) Proxy_Function fun(T &&t, Q &&q, R &&r)
{ {
return fun(detail::bind_first(detail::bind_first(t, q), r)); return fun(detail::bind_first(detail::bind_first(std::forward<T>(t), std::forward<Q>(q)), std::forward<R>(r)));
} }
} }

View File

@ -367,7 +367,13 @@ namespace chaiscript
[this](const std::vector<Boxed_Value> &t_params) { [this](const std::vector<Boxed_Value> &t_params) {
return m_engine.call_exists(t_params); return m_engine.call_exists(t_params);
})), "call_exists"); })), "call_exists");
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
// m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
//
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base &, const std::vector<Boxed_Value> &)>(
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) {
return t_fun(t_params, this->m_engine.conversions());
}), "call");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");

View File

@ -712,7 +712,7 @@ namespace chaiscript
fpp.save_params(params); fpp.save_params(params);
std::string fun_name = [&](){ std::string fun_name = [&]()->std::string{
if ((this->children[i]->identifier == AST_Node_Type::Fun_Call) || (this->children[i]->identifier == AST_Node_Type::Array_Call)) { if ((this->children[i]->identifier == AST_Node_Type::Fun_Call) || (this->children[i]->identifier == AST_Node_Type::Array_Call)) {
return this->children[i]->children[0]->text; return this->children[i]->children[0]->text;
} }

View File

@ -617,7 +617,7 @@ namespace chaiscript
} }
const size_t size = [&](){ const size_t size = [&]()->size_t{
if (longlong_) if (longlong_)
{ {
return sizeof(int64_t) * 8; return sizeof(int64_t) * 8;
@ -800,7 +800,7 @@ namespace chaiscript
const auto prev_line = m_line; const auto prev_line = m_line;
if (Id_()) { if (Id_()) {
m_match_stack.push_back(std::make_shared<eval::Id_AST_Node>( m_match_stack.push_back(std::make_shared<eval::Id_AST_Node>(
[&](){ [&]()->std::string{
if (*start == '`') { if (*start == '`') {
//Id Literal //Id Literal
return std::string(start+1, m_input_pos-1); return std::string(start+1, m_input_pos-1);

View File

@ -76,7 +76,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
chai.add(var(&system), "system"); chai.add(var(&system), "system");
//Add a bound callback method //Add a bound callback method
chai.add(fun(&System::add_callback, system), "add_callback_bound"); chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
//Register the two methods of the System structure. //Register the two methods of the System structure.
chai.add(fun(&System::add_callback), "add_callback"); chai.add(fun(&System::add_callback), "add_callback");

View File

@ -68,7 +68,9 @@ int main()
std::vector<std::shared_ptr<std::thread> > threads; std::vector<std::shared_ptr<std::thread> > threads;
// Ensure at least two, but say only 7 on an 8 core processor // Ensure at least two, but say only 7 on an 8 core processor
int num_threads = std::max(std::thread::hardware_concurrency() - 1, 2u); int num_threads = std::max(static_cast<int>(std::thread::hardware_concurrency()) - 1, 2);
std::cout << "Num threads: " << num_threads << '\n';
for (int i = 0; i < num_threads; ++i) for (int i = 0; i < num_threads; ++i)
{ {