// Boost.TypeErasure library // // Copyright 2011 Steven Watanabe // // 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) // // $Id$ #ifndef BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED #define BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace type_erasure { template class dynamic_binding; namespace detail { template struct can_optimize_conversion : ::boost::mpl::and_< ::boost::is_same, ::boost::is_same< typename ::boost::mpl::find_if< Map, ::boost::mpl::not_< ::boost::is_same< ::boost::mpl::first< ::boost::mpl::_1>, ::boost::mpl::second< ::boost::mpl::_1> > > >::type, typename ::boost::mpl::end::type > >::type {}; } /** * Stores the binding of a @c Concept to a set of actual types. * @c Concept is interpreted in the same way as with @ref any. */ template class binding { typedef typename ::boost::type_erasure::detail::normalize_concept< Concept>::type normalized; typedef typename ::boost::mpl::transform >::type actual_concept; typedef typename ::boost::type_erasure::detail::make_vtable< actual_concept>::type table_type; typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map< Concept >::type placeholder_subs; public: /** * \pre @ref relaxed must be in @c Concept. * * \throws Nothing. */ binding() { BOOST_MPL_ASSERT((::boost::type_erasure::is_relaxed)); } /** * \pre @c Map must be an MPL map with an entry for each placeholder * referred to by @c Concept. * * \throws Nothing. */ template explicit binding(const Map&) : impl(( BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map), static_binding() )) {} /** * \pre @c Map must be an MPL map with an entry for each placeholder * referred to by @c Concept. * * \throws Nothing. */ template binding(const static_binding&) : impl(( BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map), static_binding() )) {} /** * Converts from another set of bindings. * * \pre Map must be an MPL map with an entry for each placeholder * referred to by @c Concept. The mapped type should be the * corresponding placeholder in Concept2. * * \throws std::bad_alloc */ template binding(const binding& other, const Map& #ifndef BOOST_TYPE_ERASURE_DOXYGEN , typename ::boost::enable_if< ::boost::mpl::and_< ::boost::type_erasure::detail::check_map, ::boost::type_erasure::is_subconcept > >::type* = 0 #endif ) : impl( other, static_binding(), ::boost::type_erasure::detail::can_optimize_conversion() ) {} /** * Converts from another set of bindings. * * \pre Map must be an MPL map with an entry for each placeholder * referred to by @c Concept. The mapped type should be the * corresponding placeholder in Concept2. * * \throws std::bad_alloc */ template binding(const binding& other, const static_binding& #ifndef BOOST_TYPE_ERASURE_DOXYGEN , typename ::boost::enable_if< ::boost::mpl::and_< ::boost::type_erasure::detail::check_map, ::boost::type_erasure::is_subconcept > >::type* = 0 #endif ) : impl( other, static_binding(), ::boost::type_erasure::detail::can_optimize_conversion() ) {} /** * Converts from another set of bindings. * * \pre Map must be an MPL map with an entry for each placeholder * referred to by @c Concept. The mapped type should be the * corresponding placeholder in Concept2. * * \throws std::bad_alloc * \throws std::bad_any_cast */ template binding(const dynamic_binding& other, const static_binding&) : impl( other, static_binding() ) {} /** * \return true iff the sets of types that the placeholders * bind to are the same for both arguments. * * \throws Nothing. */ friend bool operator==(const binding& lhs, const binding& rhs) { return *lhs.impl.table == *rhs.impl.table; } /** * \return true iff the arguments do not map to identical * sets of types. * * \throws Nothing. */ friend bool operator!=(const binding& lhs, const binding& rhs) { return !(lhs == rhs); } /** INTERNAL ONLY */ template typename T::type find() const { return impl.table->lookup((T*)0); } private: template friend class binding; template friend class dynamic_binding; /** INTERNAL ONLY */ struct impl_type { impl_type() { table = &::boost::type_erasure::detail::make_vtable_init< typename ::boost::mpl::transform< actual_concept, ::boost::type_erasure::detail::get_null_vtable_entry< ::boost::mpl::_1 > >::type, table_type >::type::value; } template impl_type(const static_binding&) { table = &::boost::type_erasure::detail::make_vtable_init< typename ::boost::mpl::transform< actual_concept, ::boost::type_erasure::detail::rebind_placeholders< ::boost::mpl::_1, typename ::boost::type_erasure::detail::add_deductions< Map, placeholder_subs >::type > >::type, table_type >::type::value; } template impl_type(const binding& other, const static_binding&, boost::mpl::false_) : manager(new table_type) { manager->template convert_from< typename ::boost::type_erasure::detail::convert_deductions< Map, placeholder_subs, typename binding::placeholder_subs >::type >(*other.impl.table); table = manager.get(); } template impl_type(const dynamic_binding& other, const static_binding&) : manager(new table_type) { manager->template convert_from< // FIXME: What do we need to do with deduced placeholder in other typename ::boost::type_erasure::detail::add_deductions< Map, placeholder_subs >::type >(other.impl); table = manager.get(); } template impl_type(const binding& other, const static_binding&, boost::mpl::true_) : table(other.impl.table), manager(other.impl.manager) {} const table_type* table; ::boost::shared_ptr manager; } impl; }; } } #endif