1 // Boost.TypeErasure library 2 // 3 // Copyright 2011 Steven Watanabe 4 // 5 // Distributed under the Boost Software License Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 // 9 // $Id$ 10 11 #ifndef BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED 12 #define BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED 13 14 #include <boost/config.hpp> 15 #include <boost/shared_ptr.hpp> 16 #include <boost/make_shared.hpp> 17 #include <boost/utility/enable_if.hpp> 18 #include <boost/mpl/transform.hpp> 19 #include <boost/mpl/find_if.hpp> 20 #include <boost/mpl/and.hpp> 21 #include <boost/mpl/not.hpp> 22 #include <boost/mpl/end.hpp> 23 #include <boost/mpl/bool.hpp> 24 #include <boost/mpl/pair.hpp> 25 #include <boost/type_traits/is_same.hpp> 26 #include <boost/type_erasure/static_binding.hpp> 27 #include <boost/type_erasure/is_subconcept.hpp> 28 #include <boost/type_erasure/detail/adapt_to_vtable.hpp> 29 #include <boost/type_erasure/detail/null.hpp> 30 #include <boost/type_erasure/detail/rebind_placeholders.hpp> 31 #include <boost/type_erasure/detail/vtable.hpp> 32 #include <boost/type_erasure/detail/normalize.hpp> 33 #include <boost/type_erasure/detail/instantiate.hpp> 34 #include <boost/type_erasure/detail/check_map.hpp> 35 36 namespace boost { 37 namespace type_erasure { 38 39 template<class P> 40 class dynamic_binding; 41 42 namespace detail { 43 44 template<class Source, class Dest, class Map> 45 struct can_optimize_conversion : ::boost::mpl::and_< 46 ::boost::is_same<Source, Dest>, 47 ::boost::is_same< 48 typename ::boost::mpl::find_if< 49 Map, 50 ::boost::mpl::not_< 51 ::boost::is_same< 52 ::boost::mpl::first< ::boost::mpl::_1>, 53 ::boost::mpl::second< ::boost::mpl::_1> 54 > 55 > 56 >::type, 57 typename ::boost::mpl::end<Map>::type 58 > 59 >::type 60 {}; 61 62 } 63 64 /** 65 * Stores the binding of a @c Concept to a set of actual types. 66 * @c Concept is interpreted in the same way as with @ref any. 67 */ 68 template<class Concept> 69 class binding 70 { 71 typedef typename ::boost::type_erasure::detail::normalize_concept< 72 Concept>::type normalized; 73 typedef typename ::boost::mpl::transform<normalized, 74 ::boost::type_erasure::detail::maybe_adapt_to_vtable< ::boost::mpl::_1> 75 >::type actual_concept; 76 typedef typename ::boost::type_erasure::detail::make_vtable< 77 actual_concept>::type table_type; 78 typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map< 79 Concept 80 >::type placeholder_subs; 81 public: 82 83 /** 84 * \pre @ref relaxed must be in @c Concept. 85 * 86 * \throws Nothing. 87 */ binding()88 binding() { BOOST_MPL_ASSERT((::boost::type_erasure::is_relaxed<Concept>)); } 89 90 /** 91 * \pre @c Map must be an MPL map with an entry for each placeholder 92 * referred to by @c Concept. 93 * 94 * \throws Nothing. 95 */ 96 template<class Map> binding(const Map &)97 explicit binding(const Map&) 98 : impl(( 99 BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map), 100 static_binding<Map>() 101 )) 102 {} 103 104 /** 105 * \pre @c Map must be an MPL map with an entry for each placeholder 106 * referred to by @c Concept. 107 * 108 * \throws Nothing. 109 */ 110 template<class Map> binding(const static_binding<Map> &)111 binding(const static_binding<Map>&) 112 : impl(( 113 BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map), 114 static_binding<Map>() 115 )) 116 {} 117 118 /** 119 * Converts from another set of bindings. 120 * 121 * \pre Map must be an MPL map with an entry for each placeholder 122 * referred to by @c Concept. The mapped type should be the 123 * corresponding placeholder in Concept2. 124 * 125 * \throws std::bad_alloc 126 */ 127 template<class Concept2, class Map> binding(const binding<Concept2> & other,const Map &,typename::boost::enable_if<::boost::mpl::and_<::boost::type_erasure::detail::check_map<Concept,Map>,::boost::type_erasure::is_subconcept<Concept,Concept2,Map>>>::type * =0)128 binding(const binding<Concept2>& other, const Map& 129 #ifndef BOOST_TYPE_ERASURE_DOXYGEN 130 , typename ::boost::enable_if< 131 ::boost::mpl::and_< 132 ::boost::type_erasure::detail::check_map<Concept, Map>, 133 ::boost::type_erasure::is_subconcept<Concept, Concept2, Map> 134 > 135 >::type* = 0 136 #endif 137 ) 138 : impl( 139 other, 140 static_binding<Map>(), 141 ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>() 142 ) 143 {} 144 145 /** 146 * Converts from another set of bindings. 147 * 148 * \pre Map must be an MPL map with an entry for each placeholder 149 * referred to by @c Concept. The mapped type should be the 150 * corresponding placeholder in Concept2. 151 * 152 * \throws std::bad_alloc 153 */ 154 template<class Concept2, class Map> binding(const binding<Concept2> & other,const static_binding<Map> &,typename::boost::enable_if<::boost::mpl::and_<::boost::type_erasure::detail::check_map<Concept,Map>,::boost::type_erasure::is_subconcept<Concept,Concept2,Map>>>::type * =0)155 binding(const binding<Concept2>& other, const static_binding<Map>& 156 #ifndef BOOST_TYPE_ERASURE_DOXYGEN 157 , typename ::boost::enable_if< 158 ::boost::mpl::and_< 159 ::boost::type_erasure::detail::check_map<Concept, Map>, 160 ::boost::type_erasure::is_subconcept<Concept, Concept2, Map> 161 > 162 >::type* = 0 163 #endif 164 ) 165 : impl( 166 other, 167 static_binding<Map>(), 168 ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>() 169 ) 170 {} 171 172 /** 173 * Converts from another set of bindings. 174 * 175 * \pre Map must be an MPL map with an entry for each placeholder 176 * referred to by @c Concept. The mapped type should be the 177 * corresponding placeholder in Concept2. 178 * 179 * \throws std::bad_alloc 180 * \throws std::bad_any_cast 181 */ 182 template<class Placeholders, class Map> binding(const dynamic_binding<Placeholders> & other,const static_binding<Map> &)183 binding(const dynamic_binding<Placeholders>& other, const static_binding<Map>&) 184 : impl( 185 other, 186 static_binding<Map>() 187 ) 188 {} 189 190 /** 191 * \return true iff the sets of types that the placeholders 192 * bind to are the same for both arguments. 193 * 194 * \throws Nothing. 195 */ operator ==(const binding & lhs,const binding & rhs)196 friend bool operator==(const binding& lhs, const binding& rhs) 197 { return *lhs.impl.table == *rhs.impl.table; } 198 199 /** 200 * \return true iff the arguments do not map to identical 201 * sets of types. 202 * 203 * \throws Nothing. 204 */ operator !=(const binding & lhs,const binding & rhs)205 friend bool operator!=(const binding& lhs, const binding& rhs) 206 { return !(lhs == rhs); } 207 208 /** INTERNAL ONLY */ 209 template<class T> find() const210 typename T::type find() const { return impl.table->lookup((T*)0); } 211 private: 212 template<class C2> 213 friend class binding; 214 template<class P> 215 friend class dynamic_binding; 216 /** INTERNAL ONLY */ 217 struct impl_type 218 { impl_typeboost::type_erasure::binding::impl_type219 impl_type() { 220 table = &::boost::type_erasure::detail::make_vtable_init< 221 typename ::boost::mpl::transform< 222 actual_concept, 223 ::boost::type_erasure::detail::get_null_vtable_entry< 224 ::boost::mpl::_1 225 > 226 >::type, 227 table_type 228 >::type::value; 229 } 230 template<class Map> impl_typeboost::type_erasure::binding::impl_type231 impl_type(const static_binding<Map>&) 232 { 233 table = &::boost::type_erasure::detail::make_vtable_init< 234 typename ::boost::mpl::transform< 235 actual_concept, 236 ::boost::type_erasure::detail::rebind_placeholders< 237 ::boost::mpl::_1, 238 typename ::boost::type_erasure::detail::add_deductions< 239 Map, 240 placeholder_subs 241 >::type 242 > 243 >::type, 244 table_type 245 >::type::value; 246 } 247 template<class Concept2, class Map> impl_typeboost::type_erasure::binding::impl_type248 impl_type(const binding<Concept2>& other, const static_binding<Map>&, boost::mpl::false_) 249 : manager(new table_type) 250 { 251 manager->template convert_from< 252 typename ::boost::type_erasure::detail::convert_deductions< 253 Map, 254 placeholder_subs, 255 typename binding<Concept2>::placeholder_subs 256 >::type 257 >(*other.impl.table); 258 table = manager.get(); 259 } 260 template<class PlaceholderList, class Map> impl_typeboost::type_erasure::binding::impl_type261 impl_type(const dynamic_binding<PlaceholderList>& other, const static_binding<Map>&) 262 : manager(new table_type) 263 { 264 manager->template convert_from< 265 // FIXME: What do we need to do with deduced placeholder in other 266 typename ::boost::type_erasure::detail::add_deductions< 267 Map, 268 placeholder_subs 269 >::type 270 >(other.impl); 271 table = manager.get(); 272 } 273 template<class Concept2, class Map> impl_typeboost::type_erasure::binding::impl_type274 impl_type(const binding<Concept2>& other, const static_binding<Map>&, boost::mpl::true_) 275 : table(other.impl.table), 276 manager(other.impl.manager) 277 {} 278 const table_type* table; 279 ::boost::shared_ptr<table_type> manager; 280 } impl; 281 }; 282 283 } 284 } 285 286 #endif 287