105 lines
2.6 KiB
C++
105 lines
2.6 KiB
C++
/* 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
|