/*============================================================================= Copyright (c) 2011-2013 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout 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) =============================================================================*/ #ifndef SPROUT_FUNCTIONAL_BIND_BIND_HPP #define SPROUT_FUNCTIONAL_BIND_BIND_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace sprout { // 20.8.9 bind // // is_bind_expression // template struct is_bind_expression : public sprout::false_type {}; template struct is_bind_expression : public sprout::is_bind_expression {}; template struct is_bind_expression : public sprout::is_bind_expression {}; template struct is_bind_expression : public sprout::is_bind_expression {}; namespace detail { struct no_tuple_element; template struct safe_tuple_element_impl : tuple_element {}; template struct safe_tuple_element_impl { public: typedef sprout::detail::no_tuple_element type; }; template struct safe_tuple_element : public sprout::detail::safe_tuple_element_impl::value)> {}; template< typename Arg, bool IsBindExp = sprout::is_bind_expression::value, bool IsPlaceholder = (sprout::is_placeholder::value > 0) > class mu; template class mu, false, false> { public: typedef T& result_type; public: template SPROUT_CONSTEXPR result_type operator()(CVRef& arg, Tuple&) const volatile { return const_cast::type>::type&>(arg).get(); } }; template class mu, false, false> { public: typedef T& result_type; public: template SPROUT_CONSTEXPR result_type operator()(CVRef& arg, Tuple&) const volatile { return const_cast::type>::type&>(arg).get(); } }; template class mu { private: template SPROUT_CONSTEXPR auto call( CVArg& arg, sprout::tuples::tuple& tuple, sprout::index_tuple ) const volatile -> decltype(arg(std::declval()...)) { return arg(sprout::forward(sprout::tuples::get(tuple))...); } public: template SPROUT_CONSTEXPR auto operator()(CVArg& arg, sprout::tuples::tuple& tuple) const volatile -> decltype(arg(std::declval()...)) { return call(arg, tuple, sprout::index_pack::make()); } }; template class mu { public: template class result; template class result { private: typedef typename sprout::detail::safe_tuple_element< (sprout::is_placeholder::value - 1), Tuple >::type base_type; public: typedef typename std::add_rvalue_reference::type type; }; public: template typename result::type SPROUT_CONSTEXPR operator()(Arg /*const volatile&*/, Tuple& tuple) const volatile { return sprout::forward::type>( sprout::tuples::get<(sprout::is_placeholder::value - 1)>(tuple) ); } }; template class mu { public: template struct result; template struct result { public: typedef typename std::add_lvalue_reference::type type; }; public: template SPROUT_CONSTEXPR CVArg&& operator()(CVArg&& arg, Tuple&) const volatile { return sprout::forward(arg); } }; template struct maybe_wrap_member_pointer { public: typedef T type; public: static SPROUT_CONSTEXPR T const& do_wrap(T const& x) { return x; } static SPROUT_CONSTEXPR T&& do_wrap(T&& x) { return static_cast(x); } }; template struct maybe_wrap_member_pointer { public: typedef sprout::mem_fn_adaptor type; public: static SPROUT_CONSTEXPR type do_wrap(T Class::* pm) { return type(pm); } }; template<> struct maybe_wrap_member_pointer { public: typedef void type; }; template inline SPROUT_CONSTEXPR auto volget(sprout::tuples::tuple volatile& tuple) -> typename sprout::tuples::tuple_element >::type volatile& { return sprout::tuples::get(const_cast&>(tuple)); } template inline SPROUT_CONSTEXPR auto volget(sprout::tuples::tuple const volatile& tuple) -> typename sprout::tuples::tuple_element >::type const volatile& { return sprout::tuples::get(const_cast const&>(tuple)); } struct is_variadic_placeholder_pred { public: template struct apply : public sprout::integral_constant< bool, (sprout::is_variadic_placeholder::value > 0) > {}; }; template struct is_variadic_bounds : public sprout::integral_constant< bool, (sprout::types::find_index_if::value != sprout::tuples::tuple_size::value) > {}; template struct tail_place : public sprout::integral_constant::value - 1> {}; template struct bound_size : public sprout::integral_constant {}; template struct bound_size< T, ArgSize, typename std::enable_if<(sprout::is_variadic_placeholder::value > 0)>::type > : public sprout::integral_constant< std::size_t, (ArgSize - sprout::detail::tail_place::value) > {}; template struct bounds_size_impl : public sprout::integral_constant {}; template struct bounds_size_impl< I, Bounds, ArgSize, typename std::enable_if<(I < sprout::tuples::tuple_size::value)>::type > : public sprout::integral_constant< std::size_t, (sprout::detail::bound_size::type, ArgSize>::value + sprout::detail::bounds_size_impl::value ) > {}; template struct bounds_size : public sprout::detail::bounds_size_impl<0, Bounds, ArgSize> {}; template struct bounds_partial_size_impl { public: typedef Seq type; }; template struct bounds_partial_size_impl< I, Bounds, ArgSize, Current, sprout::types::integral_array, typename std::enable_if<(I < sprout::tuples::tuple_size::value)>::type > : public sprout::detail::bounds_partial_size_impl< I + 1, Bounds, ArgSize, Current + sprout::detail::bound_size::type, ArgSize>::value, sprout::types::integral_array > {}; template struct bounds_partial_size : public sprout::detail::bounds_partial_size_impl<0, Bounds, ArgSize, 0, sprout::types::integral_array > {}; template struct bound_indexes : public sprout::make_index_tuple::value> {}; template struct bound_position : public sprout::integral_constant< sprout::index_t, (sprout::types::lower_bound_index< typename sprout::detail::bounds_partial_size::type, sprout::integral_constant >::type::value - 1 ) > {}; template struct is_variadic_part : public sprout::integral_constant< bool, (sprout::is_variadic_placeholder< typename sprout::tuples::tuple_element< sprout::detail::bound_position::value, Bounds >::type >::value > 0 ) > {}; template struct bound_element_impl : public sprout::tuples::tuple_element {}; template struct bound_element_impl< I, Bounds, ArgSize, BoundPos, SizeSeq, typename std::enable_if::value>::type > { public: typedef sprout::placeholder< (I + 1 - sprout::tuples::tuple_element::type::value + sprout::detail::tail_place::type>::value ) > type; }; template struct bound_element : public sprout::detail::bound_element_impl< I, Bounds, ArgSize, sprout::detail::bound_position::value, typename sprout::detail::bounds_partial_size::type > {}; struct get_bound_helper { public: template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && !std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds& bound_args) -> decltype(sprout::tuples::get(bound_args)) { return sprout::tuples::get(bound_args); } template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && !std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds const& bound_args) -> decltype(sprout::tuples::get(bound_args)) { return sprout::tuples::get(bound_args); } template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds volatile& bound_args) -> decltype(sprout::detail::volget(bound_args)) { return sprout::detail::volget(bound_args); } template< sprout::index_t I, typename Bounds, typename sprout::enabler_if::value && std::is_volatile::value>::type = sprout::enabler > static SPROUT_CONSTEXPR auto get_bound(Bounds const volatile& bound_args) -> decltype(sprout::detail::volget(bound_args)) { return sprout::detail::volget(bound_args); } }; template< sprout::index_t I, std::size_t ArgSize, typename Bounds, typename sprout::enabler_if::type, ArgSize>::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR typename sprout::detail::bound_element::type, ArgSize>::type get_bound(Bounds&&) { typedef typename sprout::detail::bound_element::type, ArgSize>::type type; return type(); } template< sprout::index_t I, std::size_t ArgSize, typename Bounds, typename sprout::enabler_if::type, ArgSize>::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR auto get_bound(Bounds&& bound_args) -> decltype( sprout::detail::get_bound_helper::get_bound< sprout::detail::bound_position::type, ArgSize>::value >(sprout::forward(bound_args)) ) { return sprout::detail::get_bound_helper::get_bound< sprout::detail::bound_position::type, ArgSize>::value >(sprout::forward(bound_args)); } } // namespace detail namespace detail { template class binder_impl; template class binder_impl : public sprout::weak_result_type { protected: typedef sprout::tuples::tuple bounds_type; private: Functor f_; bounds_type bound_args_; protected: template Result call(sprout::tuples::tuple&& args, sprout::index_tuple) { return f_( sprout::detail::mu::type>() (sprout::detail::get_bound(bound_args_), args)... ); } template SPROUT_CONSTEXPR Result call_c(sprout::tuples::tuple&& args, sprout::index_tuple) const { return f_( sprout::detail::mu::type const>() (sprout::detail::get_bound(bound_args_), args)... ); } template Result call_v(sprout::tuples::tuple&& args, sprout::index_tuple) volatile { return f_( sprout::detail::mu::type volatile>() (sprout::detail::get_bound(bound_args_), args)... ); } template SPROUT_CONSTEXPR Result call_cv(sprout::tuples::tuple&& args, sprout::index_tuple) const volatile { return f_( sprout::detail::mu::type const volatile>() (sprout::detail::get_bound(bound_args_), args)... ); } public: template< typename... Args, sprout::index_t... Indexes > static decltype( std::declval()( sprout::detail::mu::type>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_(sprout::tuples::tuple&& args, sprout::index_tuple); template< typename... Args, sprout::index_t... Indexes > static decltype( std::declval= 0), typename std::add_const::type>::type&>()( sprout::detail::mu::type const>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_c_(sprout::tuples::tuple&& args, sprout::index_tuple); template< typename... Args, sprout::index_t... Indexes > static decltype( std::declval= 0), typename std::add_volatile::type>::type&>()( sprout::detail::mu::type volatile>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_v_(sprout::tuples::tuple&& args, sprout::index_tuple); template< typename... Args, sprout::index_t... Indexes > static decltype( std::declval= 0), typename std::add_cv::type>::type&>()( sprout::detail::mu::type const volatile>() (sprout::detail::get_bound(std::declval()), std::declval&>())... ) ) call_cv_(sprout::tuples::tuple&& args, sprout::index_tuple); public: template explicit SPROUT_CONSTEXPR binder_impl(Functor const& f, Args&&... args) : f_(f) , bound_args_(sprout::forward(args)...) {} binder_impl(binder_impl const&) = default; }; } // namespace detail // // binder // template class binder; template class binder : private sprout::detail::binder_impl { private: typedef sprout::detail::binder_impl impl_type; typedef typename impl_type::bounds_type bounds_type; public: template explicit SPROUT_CONSTEXPR binder(Functor const& f, Args&&... args) : impl_type(f, sprout::forward(args)...) {} binder(binder const&) = default; template< typename... Args, typename Result = decltype( impl_type::template call_(std::declval >(), sprout::detail::bound_indexes::make()) ) > Result operator()(Args&&... args) { return impl_type::template call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template< typename... Args, typename Result = decltype( impl_type::template call_c_(std::declval >(), sprout::detail::bound_indexes::make()) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const { return impl_type::template call_c( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template< typename... Args, typename Result = decltype( impl_type::template call_v_(std::declval >(), sprout::detail::bound_indexes::make()) ) > Result operator()(Args&&... args) volatile { return impl_type::template call_v( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template< typename... Args, typename Result = decltype( impl_type::template call_cv_(std::declval >(), sprout::detail::bound_indexes::make()) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const volatile { return impl_type::template call_cv( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } }; // // cbinder // template class cbinder; template class cbinder : private sprout::detail::binder_impl { private: typedef sprout::detail::binder_impl impl_type; typedef typename impl_type::bounds_type bounds_type; public: template explicit SPROUT_CONSTEXPR cbinder(Functor const& f, Args&&... args) : impl_type(f, sprout::forward(args)...) {} cbinder(cbinder const&) = default; template< typename... Args, typename Result = decltype( impl_type::template call_c_(std::declval >(), sprout::detail::bound_indexes::make()) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const { return impl_type::template call_c( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template< typename... Args, typename Result = decltype( impl_type::template call_cv_(std::declval >(), sprout::detail::bound_indexes::make()) ) > SPROUT_CONSTEXPR Result operator()(Args&&... args) const volatile { return impl_type::template call_cv( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } }; namespace detail { template class res_binder_impl; template class res_binder_impl { public: typedef Result result_type; protected: typedef sprout::tuples::tuple bounds_type; private: template struct enable_if_void : public std::enable_if::value, int> {}; template struct disable_if_void : public std::enable_if::value, int> {}; private: Functor f_; sprout::tuples::tuple bound_args_; protected: template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) { return f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) { f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } template SPROUT_CONSTEXPR Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) const { return f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) const { f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) volatile { return f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) volatile { f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } template SPROUT_CONSTEXPR Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename disable_if_void::type = 0 ) const volatile { return f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } template Result call( sprout::tuples::tuple&& args, sprout::index_tuple, typename enable_if_void::type = 0 ) const volatile { f_(sprout::detail::mu()(sprout::detail::get_bound(bound_args_), args)...); } public: template explicit SPROUT_CONSTEXPR res_binder_impl(Functor const& f, Args&&... args) : f_(f) , bound_args_(sprout::forward(args)...) {} res_binder_impl(res_binder_impl const&) = default; }; } // namespace detail // // res_binder // template class res_binder; template class res_binder : private sprout::detail::res_binder_impl { public: typedef Result result_type; private: typedef sprout::detail::res_binder_impl impl_type; typedef typename impl_type::bounds_type bounds_type; public: template explicit res_binder(Functor const& f, Args&&... args) : impl_type(f, sprout::forward(args)...) {} res_binder(res_binder const&) = default; template result_type operator()(Args&&... args) { return impl_type::template call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const { return impl_type::template call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template result_type operator()(Args&&... args) volatile { return impl_type::template call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const volatile { return impl_type::template call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } }; // // res_cbinder // template class res_cbinder; template class res_cbinder : private sprout::detail::res_binder_impl { public: typedef Result result_type; private: typedef sprout::detail::res_binder_impl impl_type; typedef typename impl_type::bounds_type bounds_type; public: template explicit SPROUT_CONSTEXPR res_cbinder(Functor const& f, Args&&... args) : impl_type(f, sprout::forward(args)...) {} res_cbinder(res_cbinder const&) = default; template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const { return impl_type::template call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } template SPROUT_CONSTEXPR result_type operator()(Args&&... args) const volatile { return impl_type::template call( sprout::tuples::forward_as_tuple(sprout::forward(args)...), sprout::detail::bound_indexes::make() ); } }; // // is_bind_expression // template struct is_bind_expression > : public sprout::true_type {}; template struct is_bind_expression > : public sprout::true_type {}; template struct is_bind_expression > : public sprout::true_type {}; template struct is_bind_expression > : public sprout::true_type {}; namespace detail { template struct complete_placeholder { public: typedef BoundArg type; }; template struct complete_placeholder< N, BoundArg, typename std::enable_if::value>::type > { public: typedef sprout::placeholder type; }; template struct binder_complete_placeholders_impl { public: typedef Binder type; }; template struct binder_complete_placeholders_impl< I, N, Bounds, sprout::binder, typename std::enable_if<(I < sprout::tuples::tuple_size::value)>::type > : public std::conditional< sprout::is_positional_placeholder::type>::value, sprout::detail::binder_complete_placeholders_impl< I + 1, N + 1, Bounds, sprout::binder)> >, sprout::detail::binder_complete_placeholders_impl< I + 1, N, Bounds, sprout::binder::type)> > >::type {}; template struct binder_complete_placeholders_impl< I, N, Bounds, sprout::cbinder, typename std::enable_if<(I < sprout::tuples::tuple_size::value)>::type > : public std::conditional< sprout::is_positional_placeholder::type>::value, sprout::detail::binder_complete_placeholders_impl< I + 1, N + 1, Bounds, sprout::cbinder)> >, sprout::detail::binder_complete_placeholders_impl< I + 1, N, Bounds, sprout::cbinder::type)> > >::type {}; template struct binder_complete_placeholders; template struct binder_complete_placeholders< false, Func, BoundArgs... > : public sprout::detail::binder_complete_placeholders_impl< 0, 0, sprout::types::type_tuple, sprout::binder > {}; template struct binder_complete_placeholders< true, Func, BoundArgs... > : public sprout::detail::binder_complete_placeholders_impl< 0, 0, sprout::types::type_tuple, sprout::cbinder > {}; template struct res_binder_complete_placeholders_impl { public: typedef Binder type; }; template struct res_binder_complete_placeholders_impl< I, N, Bounds, sprout::res_binder, typename std::enable_if<(I < sprout::tuples::tuple_size::value)>::type > : public std::conditional< sprout::is_positional_placeholder::type>::value, sprout::detail::res_binder_complete_placeholders_impl< I + 1, N + 1, Bounds, sprout::res_binder)> >, sprout::detail::res_binder_complete_placeholders_impl< I + 1, N, Bounds, sprout::res_binder::type)> > >::type {}; template struct res_binder_complete_placeholders_impl< I, N, Bounds, sprout::res_cbinder, typename std::enable_if<(I < sprout::tuples::tuple_size::value)>::type > : public std::conditional< sprout::is_positional_placeholder::type>::value, sprout::detail::res_binder_complete_placeholders_impl< I + 1, N + 1, Bounds, sprout::res_cbinder)> >, sprout::detail::res_binder_complete_placeholders_impl< I + 1, N, Bounds, sprout::res_cbinder::type)> > >::type {}; template struct res_binder_complete_placeholders; template struct res_binder_complete_placeholders< false, Result, Func, BoundArgs... > : public sprout::detail::res_binder_complete_placeholders_impl< 0, 0, sprout::types::type_tuple, sprout::res_binder > {}; template struct res_binder_complete_placeholders< true, Result, Func, BoundArgs... > : public sprout::detail::res_binder_complete_placeholders_impl< 0, 0, sprout::types::type_tuple, sprout::res_cbinder > {}; template struct bind_helper { public: typedef sprout::detail::maybe_wrap_member_pointer::type> maybe_type; typedef typename maybe_type::type func_type; typedef typename sprout::detail::binder_complete_placeholders::type...>::type type; }; template struct res_bind_helper { public: typedef sprout::detail::maybe_wrap_member_pointer::type> maybe_type; typedef typename maybe_type::type functor_type; typedef typename sprout::detail::res_binder_complete_placeholders::type...>::type type; }; } // namespace detail // // bind_result // cbind_result // template struct bind_result { public: typedef typename sprout::detail::bind_helper::type type; }; template struct cbind_result { public: typedef typename sprout::detail::bind_helper::type type; }; // // res_bind_result // res_cbind_result // template struct res_bind_result { public: typedef typename sprout::detail::res_bind_helper::type type; }; template struct res_cbind_result { public: typedef typename sprout::detail::res_bind_helper::type type; }; // // bind // template inline SPROUT_CONSTEXPR typename sprout::bind_result::type bind(F&& f, BoundArgs&&... args) { typedef sprout::detail::bind_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } template inline SPROUT_CONSTEXPR typename sprout::res_bind_result::type bind(F&& f, BoundArgs&&... args) { typedef sprout::detail::res_bind_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } // // cbind // template inline SPROUT_CONSTEXPR typename sprout::cbind_result::type cbind(F&& f, BoundArgs&&... args) { typedef sprout::detail::bind_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } template inline SPROUT_CONSTEXPR typename sprout::res_cbind_result::type cbind(F&& f, BoundArgs&&... args) { typedef sprout::detail::res_bind_helper helper_type; typedef typename helper_type::maybe_type maybe_type; typedef typename helper_type::type result_type; return result_type(maybe_type::do_wrap(sprout::forward(f)), sprout::forward(args)...); } } // namespace sprout #endif // #ifndef SPROUT_FUNCTIONAL_BIND_BIND_HPP