summaryrefslogtreecommitdiff
path: root/boost/type_erasure/binding.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/type_erasure/binding.hpp')
-rw-r--r--boost/type_erasure/binding.hpp250
1 files changed, 250 insertions, 0 deletions
diff --git a/boost/type_erasure/binding.hpp b/boost/type_erasure/binding.hpp
new file mode 100644
index 0000000000..a5023a59eb
--- /dev/null
+++ b/boost/type_erasure/binding.hpp
@@ -0,0 +1,250 @@
+// 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 <boost/config.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/mpl/find_if.hpp>
+#include <boost/mpl/and.hpp>
+#include <boost/mpl/not.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_erasure/static_binding.hpp>
+#include <boost/type_erasure/is_subconcept.hpp>
+#include <boost/type_erasure/detail/adapt_to_vtable.hpp>
+#include <boost/type_erasure/detail/null.hpp>
+#include <boost/type_erasure/detail/rebind_placeholders.hpp>
+#include <boost/type_erasure/detail/vtable.hpp>
+#include <boost/type_erasure/detail/normalize.hpp>
+#include <boost/type_erasure/detail/instantiate.hpp>
+#include <boost/type_erasure/detail/check_map.hpp>
+
+namespace boost {
+namespace type_erasure {
+
+namespace detail {
+
+template<class Source, class Dest, class Map>
+struct can_optimize_conversion : ::boost::mpl::and_<
+ ::boost::is_same<Source, Dest>,
+ ::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<Map>::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 Concept>
+class binding
+{
+ typedef typename ::boost::type_erasure::detail::normalize_concept<
+ Concept>::type normalized;
+ typedef typename ::boost::mpl::transform<normalized,
+ ::boost::type_erasure::detail::maybe_adapt_to_vtable< ::boost::mpl::_1>
+ >::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<Concept>)); }
+
+ /**
+ * \pre @c Map must be an MPL map with an entry for each placeholder
+ * referred to by @c Concept.
+ *
+ * \throws Nothing.
+ */
+ template<class Map>
+ explicit binding(const Map&)
+ : impl((
+ BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map),
+ static_binding<Map>()
+ ))
+ {}
+
+ /**
+ * \pre @c Map must be an MPL map with an entry for each placeholder
+ * referred to by @c Concept.
+ *
+ * \throws Nothing.
+ */
+ template<class Map>
+ binding(const static_binding<Map>&)
+ : impl((
+ BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map),
+ static_binding<Map>()
+ ))
+ {}
+
+ /**
+ * 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<class Concept2, class Map>
+ binding(const binding<Concept2>& other, const Map&
+#ifndef BOOST_TYPE_ERASURE_DOXYGEN
+ , 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
+#endif
+ )
+ : impl(
+ other,
+ static_binding<Map>(),
+ ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>()
+ )
+ {}
+
+ /**
+ * 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<class Concept2, class Map>
+ binding(const binding<Concept2>& other, const static_binding<Map>&
+#ifndef BOOST_TYPE_ERASURE_DOXYGEN
+ , 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
+#endif
+ )
+ : impl(
+ other,
+ static_binding<Map>(),
+ ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>()
+ )
+ {}
+
+ /**
+ * \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<class T>
+ typename T::type find() const { return impl.table->lookup((T*)0); }
+private:
+ template<class C2>
+ friend class 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<class Map>
+ impl_type(const static_binding<Map>&)
+ {
+ 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<class Concept2, class Map>
+ impl_type(const binding<Concept2>& other, const static_binding<Map>&, boost::mpl::false_)
+ : manager(new table_type)
+ {
+ manager->template convert_from<
+ typename ::boost::type_erasure::detail::convert_deductions<
+ Map,
+ placeholder_subs,
+ typename binding<Concept2>::placeholder_subs
+ >::type
+ >(*other.impl.table);
+ table = manager.get();
+ }
+ template<class Concept2, class Map>
+ impl_type(const binding<Concept2>& other, const static_binding<Map>&, boost::mpl::true_)
+ : table(other.impl.table),
+ manager(other.impl.manager)
+ {}
+ const table_type* table;
+ ::boost::shared_ptr<table_type> manager;
+ } impl;
+};
+
+}
+}
+
+#endif