boost/poly_collection/detail/callable_wrapper.hpp
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/poly_collection for library home page.
*/
#ifndef BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_HPP
#define BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/detail/is_invocable.hpp>
#include <functional>
#include <type_traits>
#include <typeinfo>
namespace boost{
namespace poly_collection{
namespace detail{
/* lightweight std::function look-alike over non-owned callable entities */
template<typename Signature>
class callable_wrapper;
template<typename R,typename... Args>
class callable_wrapper<R(Args...)>
{
public:
// TODO: we should prevent assignment by user code
template<
typename Callable,
typename std::enable_if<
!std::is_same<Callable,callable_wrapper>::value&&
is_invocable_r<R,Callable,Args...>::value
>::type* =nullptr
>
explicit callable_wrapper(Callable& x)noexcept:pt{info(x)},px{&x}{}
callable_wrapper(const callable_wrapper&)=default;
callable_wrapper& operator=(const callable_wrapper&)=default;
explicit operator bool()const noexcept{return true;}
R operator()(Args... args)const
{return pt->call(px,std::forward<Args>(args)...);}
const std::type_info& target_type()const noexcept{return pt->info;}
template<typename T>
T* target()noexcept
{return typeid(T)==pt->info?static_cast<T*>(px):nullptr;}
template<typename T>
const T* target()const noexcept
{return typeid(T)==pt->info?static_cast<const T*>(px):nullptr;}
/* not in std::function interface */
operator std::function<R(Args...)>()const noexcept{return pt->convert(px);}
void* data()noexcept{return px;}
const void* data()const noexcept{return px;}
private:
struct table
{
R(*call)(void*,Args...);
const std::type_info& info;
std::function<R(Args...)> (*convert)(void*);
};
template<typename Callable>
static table* info(Callable&)noexcept
{
static table t={
[](void* p,Args... args){
auto r=std::ref(*static_cast<Callable*>(p));
return static_cast<R>(r(std::forward<Args>(args)...));
},
typeid(Callable),
[](void* p){
auto r=std::ref(*static_cast<Callable*>(p));
return std::function<R(Args...)>{r};
}
};
return &t;
}
table* pt;
void* px;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif