diff options
Diffstat (limited to 'boost/poly_collection/detail/callable_wrapper.hpp')
-rw-r--r-- | boost/poly_collection/detail/callable_wrapper.hpp | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/boost/poly_collection/detail/callable_wrapper.hpp b/boost/poly_collection/detail/callable_wrapper.hpp new file mode 100644 index 0000000000..9b339db8f2 --- /dev/null +++ b/boost/poly_collection/detail/callable_wrapper.hpp @@ -0,0 +1,104 @@ +/* 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 |