annotate DEPENDENCIES/generic/include/boost/mpi/python/skeleton_and_content.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // (C) Copyright 2006 Douglas Gregor <doug.gregor -at- gmail.com>
Chris@16 2
Chris@16 3 // Use, modification and distribution is subject to the Boost Software
Chris@16 4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 // Authors: Douglas Gregor
Chris@16 8 #ifndef BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
Chris@16 9 #define BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
Chris@16 10
Chris@16 11 /** @file skeleton_and_content.hpp
Chris@16 12 *
Chris@16 13 * This file reflects the skeleton/content facilities into Python.
Chris@16 14 */
Chris@16 15 #include <boost/python.hpp>
Chris@16 16 #include <boost/mpi.hpp>
Chris@16 17 #include <boost/function/function1.hpp>
Chris@16 18 #define BOOST_MPI_PYTHON_FORWARD_ONLY
Chris@16 19 #include <boost/mpi/python.hpp>
Chris@16 20 #include <boost/mpi/python/serialize.hpp>
Chris@16 21
Chris@16 22
Chris@16 23 namespace boost { namespace mpi { namespace python {
Chris@16 24
Chris@16 25 /**
Chris@16 26 * INTERNAL ONLY
Chris@16 27 *
Chris@16 28 * This @c content class is a wrapper around the C++ "content"
Chris@16 29 * retrieved from get_content. This wrapper is only needed to store a
Chris@16 30 * copy of the Python object on which get_content() was called.
Chris@16 31 */
Chris@16 32 class content : public boost::mpi::content
Chris@16 33 {
Chris@16 34 typedef boost::mpi::content inherited;
Chris@16 35
Chris@16 36 public:
Chris@16 37 content(const inherited& base, boost::python::object object)
Chris@16 38 : inherited(base), object(object) { }
Chris@16 39
Chris@16 40 inherited& base() { return *this; }
Chris@16 41 const inherited& base() const { return *this; }
Chris@16 42
Chris@16 43 boost::python::object object;
Chris@16 44 };
Chris@16 45
Chris@16 46 /**
Chris@16 47 * INTERNAL ONLY
Chris@16 48 *
Chris@16 49 * A class specific to the Python bindings that mimics the behavior of
Chris@16 50 * the skeleton_proxy<T> template. In the case of Python skeletons, we
Chris@16 51 * only need to know the object (and its type) to transmit the
Chris@16 52 * skeleton. This is the only user-visible skeleton proxy type,
Chris@16 53 * although instantiations of its derived classes (@c
Chris@16 54 * skeleton_proxy<T>) will be returned from the Python skeleton()
Chris@16 55 * function.
Chris@16 56 */
Chris@16 57 class skeleton_proxy_base
Chris@16 58 {
Chris@16 59 public:
Chris@16 60 skeleton_proxy_base(const boost::python::object& object) : object(object) { }
Chris@16 61
Chris@16 62 boost::python::object object;
Chris@16 63 };
Chris@16 64
Chris@16 65 /**
Chris@16 66 * INTERNAL ONLY
Chris@16 67 *
Chris@16 68 * The templated @c skeleton_proxy class represents a skeleton proxy
Chris@16 69 * in Python. The only data is stored in the @c skeleton_proxy_base
Chris@16 70 * class (which is the type actually exposed as @c skeleton_proxy in
Chris@16 71 * Python). However, the type of @c skeleton_proxy<T> is important for
Chris@16 72 * (de-)serialization of @c skeleton_proxy<T>'s for transmission.
Chris@16 73 */
Chris@16 74 template<typename T>
Chris@16 75 class skeleton_proxy : public skeleton_proxy_base
Chris@16 76 {
Chris@16 77 public:
Chris@16 78 skeleton_proxy(const boost::python::object& object)
Chris@16 79 : skeleton_proxy_base(object) { }
Chris@16 80 };
Chris@16 81
Chris@16 82 namespace detail {
Chris@16 83 using boost::python::object;
Chris@16 84 using boost::python::extract;
Chris@16 85
Chris@16 86 extern BOOST_MPI_DECL boost::python::object skeleton_proxy_base_type;
Chris@16 87
Chris@16 88 template<typename T>
Chris@16 89 struct skeleton_saver
Chris@16 90 {
Chris@16 91 void
Chris@16 92 operator()(packed_oarchive& ar, const object& obj, const unsigned int)
Chris@16 93 {
Chris@16 94 packed_skeleton_oarchive pso(ar);
Chris@16 95 pso << extract<T&>(obj.attr("object"))();
Chris@16 96 }
Chris@16 97 };
Chris@16 98
Chris@16 99 template<typename T>
Chris@16 100 struct skeleton_loader
Chris@16 101 {
Chris@16 102 void
Chris@16 103 operator()(packed_iarchive& ar, object& obj, const unsigned int)
Chris@16 104 {
Chris@16 105 packed_skeleton_iarchive psi(ar);
Chris@16 106 extract<skeleton_proxy<T>&> proxy(obj);
Chris@16 107 if (!proxy.check())
Chris@16 108 obj = object(skeleton_proxy<T>(object(T())));
Chris@16 109
Chris@16 110 psi >> extract<T&>(obj.attr("object"))();
Chris@16 111 }
Chris@16 112 };
Chris@16 113
Chris@16 114 /**
Chris@16 115 * The @c skeleton_content_handler structure contains all of the
Chris@16 116 * information required to extract a skeleton and content from a
Chris@16 117 * Python object with a certain C++ type.
Chris@16 118 */
Chris@16 119 struct skeleton_content_handler {
Chris@16 120 function1<object, const object&> get_skeleton_proxy;
Chris@16 121 function1<content, const object&> get_content;
Chris@16 122 };
Chris@16 123
Chris@16 124 /**
Chris@16 125 * A function object that extracts the skeleton from of a Python
Chris@16 126 * object, which is actually a wrapped C++ object of type T.
Chris@16 127 */
Chris@16 128 template<typename T>
Chris@16 129 struct do_get_skeleton_proxy
Chris@16 130 {
Chris@16 131 object operator()(object value) {
Chris@16 132 return object(skeleton_proxy<T>(value));
Chris@16 133 }
Chris@16 134 };
Chris@16 135
Chris@16 136 /**
Chris@16 137 * A function object that extracts the content of a Python object,
Chris@16 138 * which is actually a wrapped C++ object of type T.
Chris@16 139 */
Chris@16 140 template<typename T>
Chris@16 141 struct do_get_content
Chris@16 142 {
Chris@16 143 content operator()(object value_obj) {
Chris@16 144 T& value = extract<T&>(value_obj)();
Chris@16 145 return content(boost::mpi::get_content(value), value_obj);
Chris@16 146 }
Chris@16 147 };
Chris@16 148
Chris@16 149 /**
Chris@16 150 * Determine if a skeleton and content handler for @p type has
Chris@16 151 * already been registered.
Chris@16 152 */
Chris@16 153 BOOST_MPI_PYTHON_DECL bool
Chris@16 154 skeleton_and_content_handler_registered(PyTypeObject* type);
Chris@16 155
Chris@16 156 /**
Chris@16 157 * Register a skeleton/content handler with a particular Python type
Chris@16 158 * (which actually wraps a C++ type).
Chris@16 159 */
Chris@16 160 BOOST_MPI_PYTHON_DECL void
Chris@16 161 register_skeleton_and_content_handler(PyTypeObject*,
Chris@16 162 const skeleton_content_handler&);
Chris@16 163 } // end namespace detail
Chris@16 164
Chris@16 165 template<typename T>
Chris@16 166 void register_skeleton_and_content(const T& value, PyTypeObject* type)
Chris@16 167 {
Chris@16 168 using boost::python::detail::direct_serialization_table;
Chris@16 169 using boost::python::detail::get_direct_serialization_table;
Chris@16 170 using namespace boost::python;
Chris@16 171
Chris@16 172 // Determine the type
Chris@16 173 if (!type)
Chris@16 174 type = object(value).ptr()->ob_type;
Chris@16 175
Chris@16 176 // Don't re-register the same type.
Chris@16 177 if (detail::skeleton_and_content_handler_registered(type))
Chris@16 178 return;
Chris@16 179
Chris@16 180 // Register the skeleton proxy type
Chris@16 181 {
Chris@16 182 boost::python::scope proxy_scope(detail::skeleton_proxy_base_type);
Chris@16 183 std::string name("skeleton_proxy<");
Chris@16 184 name += typeid(T).name();
Chris@16 185 name += ">";
Chris@16 186 class_<skeleton_proxy<T>, bases<skeleton_proxy_base> >(name.c_str(),
Chris@16 187 no_init);
Chris@16 188 }
Chris@16 189
Chris@16 190 // Register the saver and loader for the associated skeleton and
Chris@16 191 // proxy, to allow (de-)serialization of skeletons via the proxy.
Chris@16 192 direct_serialization_table<packed_iarchive, packed_oarchive>& table =
Chris@16 193 get_direct_serialization_table<packed_iarchive, packed_oarchive>();
Chris@16 194 table.register_type(detail::skeleton_saver<T>(),
Chris@16 195 detail::skeleton_loader<T>(),
Chris@16 196 skeleton_proxy<T>(object(value)));
Chris@16 197
Chris@16 198 // Register the rest of the skeleton/content mechanism, including
Chris@16 199 // handlers that extract a skeleton proxy from a Python object and
Chris@16 200 // extract the content from a Python object.
Chris@16 201 detail::skeleton_content_handler handler;
Chris@16 202 handler.get_skeleton_proxy = detail::do_get_skeleton_proxy<T>();
Chris@16 203 handler.get_content = detail::do_get_content<T>();
Chris@16 204 detail::register_skeleton_and_content_handler(type, handler);
Chris@16 205 }
Chris@16 206
Chris@16 207 } } } // end namespace boost::mpi::python
Chris@16 208
Chris@16 209 #endif // BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP