Added boost header

This commit is contained in:
Christophe Riccio
2012-01-08 01:26:07 +00:00
parent 9c3faaca40
commit c7d752cdf8
8946 changed files with 1732316 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
// Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>
// Use, modification and distribution is subject to 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)
/** @file config.hpp
*
* This header provides auto-linking and configuration support for the
* Boost.MPI python bindings.
*/
#ifndef BOOST_MPI_PYTHON_CONFIG_HPP
#define BOOST_MPI_PYTHON_CONFIG_HPP
#include <boost/mpi/config.hpp>
/*****************************************************************************
* *
* DLL import/export options *
* *
*****************************************************************************/
#if defined(BOOST_HAS_DECLSPEC) && (defined(BOOST_MPI_PYTHON_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_MPI_PYTHON_STATIC_LINK)
# if defined(BOOST_MPI_PYTHON_SOURCE)
# define BOOST_MPI_PYTHON_DECL __declspec(dllexport)
# define BOOST_MPI_PYTHON_BUILD_DLL
# else
# define BOOST_MPI_PYTHON_DECL __declspec(dllimport)
# endif
#endif
#ifndef BOOST_MPI_PYTHON_DECL
# define BOOST_MPI_PYTHON_DECL
#endif
#if !defined(BOOST_MPI_PYTHON_NO_LIB) && !defined(BOOST_MPI_PYTHON_SOURCE) && !defined(BOOST_ALL_NO_LIB)
# define BOOST_LIB_NAME boost_mpi_python
# if defined(BOOST_MPI_PYTHON_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
# define BOOST_DYN_LINK
# endif
# ifdef BOOST_MPI_PYTHON_DIAG
# define BOOST_LIB_DIAGNOSTIC
# endif
# include <boost/config/auto_link.hpp>
#endif
#endif // BOOST_MPI_PYTHON_CONFIG_HPP

View File

@@ -0,0 +1,539 @@
// Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
/** @file serialize.hpp
*
* This file provides Boost.Serialization support for Python objects
* within Boost.MPI. Python objects can be serialized in one of two
* ways. The default serialization method involves using the Python
* "pickle" module to pickle the Python objects, transmits the
* pickled representation, and unpickles the result when
* received. For C++ types that have been exposed to Python and
* registered with register_serialized(), objects are directly
* serialized for transmissing, skipping the pickling step.
*/
#ifndef BOOST_MPI_PYTHON_SERIALIZE_HPP
#define BOOST_MPI_PYTHON_SERIALIZE_HPP
#include <boost/mpi/python/config.hpp>
#include <boost/python/object.hpp>
#include <boost/python/str.hpp>
#include <boost/python/extract.hpp>
#include <memory>
#include <map>
#include <boost/function/function3.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/if.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/array.hpp>
#include <boost/assert.hpp>
#include <boost/type_traits/is_fundamental.hpp>
#define BOOST_MPI_PYTHON_FORWARD_ONLY
#include <boost/mpi/python.hpp>
/************************************************************************
* Boost.Python Serialization Section *
************************************************************************/
#if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE)
/**
* @brief Declare IArchive and OArchive as a Boost.Serialization
* archives that can be used for Python objects.
*
* This macro can only be expanded from the global namespace. It only
* requires that Archiver be forward-declared. IArchiver and OArchiver
* will only support Serialization of Python objects by pickling
* them. If the Archiver type should also support "direct"
* serialization (for C++ types), use
* BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE instead.
*/
# define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \
namespace boost { namespace python { namespace api { \
template<typename R, typename T> \
struct enable_binary< IArchiver , R, T> {}; \
\
template<typename R, typename T> \
struct enable_binary< OArchiver , R, T> {}; \
} } }
# else
# define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver)
#endif
/**
* @brief Declare IArchiver and OArchiver as a Boost.Serialization
* archives that can be used for Python objects and C++ objects
* wrapped in Python.
*
* This macro can only be expanded from the global namespace. It only
* requires that IArchiver and OArchiver be forward-declared. However,
* note that you will also need to write
* BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver,
* OArchiver) in one of your translation units.
DPG PICK UP HERE
*/
#define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \
BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \
namespace boost { namespace python { namespace detail { \
template<> \
BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >& \
get_direct_serialization_table< IArchiver , OArchiver >(); \
} \
\
template<> \
struct has_direct_serialization< IArchiver , OArchiver> : mpl::true_ { }; \
\
template<> \
struct output_archiver< IArchiver > { typedef OArchiver type; }; \
\
template<> \
struct input_archiver< OArchiver > { typedef IArchiver type; }; \
} }
/**
* @brief Define the implementation for Boost.Serialization archivers
* that can be used for Python objects and C++ objects wrapped in
* Python.
*
* This macro can only be expanded from the global namespace. It only
* requires that IArchiver and OArchiver be forward-declared. Before
* using this macro, you will need to declare IArchiver and OArchiver
* as direct serialization archives with
* BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver).
*/
#define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver, OArchiver) \
namespace boost { namespace python { namespace detail { \
template \
class BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >; \
\
template<> \
BOOST_MPI_PYTHON_DECL \
direct_serialization_table< IArchiver , OArchiver >& \
get_direct_serialization_table< IArchiver , OArchiver >( ) \
{ \
static direct_serialization_table< IArchiver, OArchiver > table; \
return table; \
} \
} } }
namespace boost { namespace python {
/**
* INTERNAL ONLY
*
* Provides access to the Python "pickle" module from within C++.
*/
class BOOST_MPI_PYTHON_DECL pickle {
struct data_t;
public:
static str dumps(object obj, int protocol = -1);
static object loads(str s);
private:
static void initialize_data();
static data_t* data;
};
/**
* @brief Whether the input/output archiver pair has "direct"
* serialization for C++ objects exposed in Python.
*
* Users do not typically need to specialize this trait, as it will be
* specialized as part of the macro
* BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE.
*/
template<typename IArchiver, typename OArchiver>
struct has_direct_serialization : mpl::false_ { };
/**
* @brief A metafunction that determines the output archiver for the
* given input archiver.
*
* Users do not typically need to specialize this trait, as it will be
* specialized as part of the macro
* BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE.
*/
template<typename IArchiver> struct output_archiver { };
/**
* @brief A metafunction that determines the input archiver for the
* given output archiver.
*
* Users do not typically need to specialize this trait, as it will be
* specialized as part of the macro
* BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE.
*
*/
template<typename OArchiver> struct input_archiver { };
namespace detail {
/**
* INTERNAL ONLY
*
* This class contains the direct-serialization code for the given
* IArchiver/OArchiver pair. It is intended to be used as a
* singleton class, and will be accessed when (de-)serializing a
* Boost.Python object with an archiver that supports direct
* serializations. Do not create instances of this class directly:
* instead, use get_direct_serialization_table.
*/
template<typename IArchiver, typename OArchiver>
class BOOST_MPI_PYTHON_DECL direct_serialization_table
{
public:
typedef boost::function3<void, OArchiver&, const object&, const unsigned int>
saver_t;
typedef boost::function3<void, IArchiver&, object&, const unsigned int>
loader_t;
typedef std::map<PyTypeObject*, std::pair<int, saver_t> > savers_t;
typedef std::map<int, loader_t> loaders_t;
/**
* Retrieve the saver (serializer) associated with the Python
* object @p obj.
*
* @param obj The object we want to save. Only its (Python) type
* is important.
*
* @param descriptor The value of the descriptor associated to
* the returned saver. Will be set to zero if no saver was found
* for @p obj.
*
* @returns a function object that can be used to serialize this
* object (and other objects of the same type), if possible. If
* no saver can be found, returns an empty function object..
*/
saver_t saver(const object& obj, int& descriptor)
{
typename savers_t::iterator pos = savers.find(obj.ptr()->ob_type);
if (pos != savers.end()) {
descriptor = pos->second.first;
return pos->second.second;
}
else {
descriptor = 0;
return saver_t();
}
}
/**
* Retrieve the loader (deserializer) associated with the given
* descriptor.
*
* @param descriptor The descriptor number provided by saver()
* when determining the saver for this type.
*
* @returns a function object that can be used to deserialize an
* object whose type is the same as that corresponding to the
* descriptor. If the descriptor is unknown, the return value
* will be an empty function object.
*/
loader_t loader(int descriptor)
{
typename loaders_t::iterator pos = loaders.find(descriptor);
if (pos != loaders.end())
return pos->second;
else
return loader_t();
}
/**
* Register the type T for direct serialization.
*
* @param value A sample value of the type @c T. This may be used
* to compute the Python type associated with the C++ type @c T.
*
* @param type The Python type associated with the C++ type @c
* T. If not provided, it will be computed from the same value @p
* value.
*/
template<typename T>
void register_type(const T& value = T(), PyTypeObject* type = 0)
{
// If the user did not provide us with a Python type, figure it
// out for ourselves.
if (!type) {
object obj(value);
type = obj.ptr()->ob_type;
}
register_type(default_saver<T>(), default_loader<T>(type), value, type);
}
/**
* Register the type T for direct serialization.
*
* @param saver A function object that will serialize a
* Boost.Python object (that represents a C++ object of type @c
* T) to an @c OArchive.
*
* @param loader A function object that will deserialize from an
* @c IArchive into a Boost.Python object that represents a C++
* object of type @c T.
*
* @param value A sample value of the type @c T. This may be used
* to compute the Python type associated with the C++ type @c T.
*
* @param type The Python type associated with the C++ type @c
* T. If not provided, it will be computed from the same value @p
* value.
*/
template<typename T>
void register_type(const saver_t& saver, const loader_t& loader,
const T& value = T(), PyTypeObject* type = 0)
{
// If the user did not provide us with a Python type, figure it
// out for ourselves.
if (!type) {
object obj(value);
type = obj.ptr()->ob_type;
}
int descriptor = savers.size() + 1;
if (savers.find(type) != savers.end())
return;
savers[type] = std::make_pair(descriptor, saver);
loaders[descriptor] = loader;
}
protected:
template<typename T>
struct default_saver {
void operator()(OArchiver& ar, const object& obj, const unsigned int) {
T value = extract<T>(obj)();
ar << value;
}
};
template<typename T>
struct default_loader {
default_loader(PyTypeObject* type) : type(type) { }
void operator()(IArchiver& ar, object& obj, const unsigned int) {
// If we can, extract the object in place.
if (!is_fundamental<T>::value && obj && obj.ptr()->ob_type == type) {
ar >> extract<T&>(obj)();
} else {
T value;
ar >> value;
obj = object(value);
}
}
private:
PyTypeObject* type;
};
savers_t savers;
loaders_t loaders;
};
/**
* @brief Retrieve the direct-serialization table for an
* IArchiver/OArchiver pair.
*
* This function is responsible for returning a reference to the
* singleton direct-serialization table. Its primary template is
* left undefined, to force the use of an explicit specialization
* with a definition in a single translation unit. Use the macro
* BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL to define this
* explicit specialization.
*/
template<typename IArchiver, typename OArchiver>
direct_serialization_table<IArchiver, OArchiver>&
get_direct_serialization_table();
} // end namespace detail
/**
* @brief Register the type T for direct serialization.
*
* The @c register_serialized function registers a C++ type for direct
* serialization with the given @c IArchiver/@c OArchiver pair. Direct
* serialization elides the use of the Python @c pickle package when
* serializing Python objects that represent C++ values. Direct
* serialization can be beneficial both to improve serialization
* performance (Python pickling can be very inefficient) and to permit
* serialization for Python-wrapped C++ objects that do not support
* pickling.
*
* @param value A sample value of the type @c T. This may be used
* to compute the Python type associated with the C++ type @c T.
*
* @param type The Python type associated with the C++ type @c
* T. If not provided, it will be computed from the same value @p
* value.
*/
template<typename IArchiver, typename OArchiver, typename T>
void
register_serialized(const T& value = T(), PyTypeObject* type = 0)
{
detail::direct_serialization_table<IArchiver, OArchiver>& table =
detail::get_direct_serialization_table<IArchiver, OArchiver>();
table.register_type(value, type);
}
namespace detail {
/// Save a Python object by pickling it.
template<typename Archiver>
void
save_impl(Archiver& ar, const boost::python::object& obj,
const unsigned int /*version*/,
mpl::false_ /*has_direct_serialization*/)
{
boost::python::str py_string = boost::python::pickle::dumps(obj);
int len = boost::python::extract<int>(py_string.attr("__len__")());
const char* string = boost::python::extract<const char*>(py_string);
ar << len << boost::serialization::make_array(string, len);
}
/// Try to save a Python object by directly serializing it; fall back
/// on pickling if required.
template<typename Archiver>
void
save_impl(Archiver& ar, const boost::python::object& obj,
const unsigned int version,
mpl::true_ /*has_direct_serialization*/)
{
typedef Archiver OArchiver;
typedef typename input_archiver<OArchiver>::type IArchiver;
typedef typename direct_serialization_table<IArchiver, OArchiver>::saver_t
saver_t;
direct_serialization_table<IArchiver, OArchiver>& table =
get_direct_serialization_table<IArchiver, OArchiver>();
int descriptor = 0;
if (saver_t saver = table.saver(obj, descriptor)) {
ar << descriptor;
saver(ar, obj, version);
} else {
// Pickle it
ar << descriptor;
detail::save_impl(ar, obj, version, mpl::false_());
}
}
/// Load a Python object by unpickling it
template<typename Archiver>
void
load_impl(Archiver& ar, boost::python::object& obj,
const unsigned int /*version*/,
mpl::false_ /*has_direct_serialization*/)
{
int len;
ar >> len;
std::auto_ptr<char> string(new char[len]);
ar >> boost::serialization::make_array(string.get(), len);
boost::python::str py_string(string.get(), len);
obj = boost::python::pickle::loads(py_string);
}
/// Try to load a Python object by directly deserializing it; fall back
/// on unpickling if required.
template<typename Archiver>
void
load_impl(Archiver& ar, boost::python::object& obj,
const unsigned int version,
mpl::true_ /*has_direct_serialization*/)
{
typedef Archiver IArchiver;
typedef typename output_archiver<IArchiver>::type OArchiver;
typedef typename direct_serialization_table<IArchiver, OArchiver>::loader_t
loader_t;
direct_serialization_table<IArchiver, OArchiver>& table =
get_direct_serialization_table<IArchiver, OArchiver>();
int descriptor;
ar >> descriptor;
if (descriptor) {
loader_t loader = table.loader(descriptor);
BOOST_ASSERT(loader);
loader(ar, obj, version);
} else {
// Unpickle it
detail::load_impl(ar, obj, version, mpl::false_());
}
}
} // end namespace detail
template<typename Archiver>
void
save(Archiver& ar, const boost::python::object& obj,
const unsigned int version)
{
typedef Archiver OArchiver;
typedef typename input_archiver<OArchiver>::type IArchiver;
detail::save_impl(ar, obj, version,
has_direct_serialization<IArchiver, OArchiver>());
}
template<typename Archiver>
void
load(Archiver& ar, boost::python::object& obj,
const unsigned int version)
{
typedef Archiver IArchiver;
typedef typename output_archiver<IArchiver>::type OArchiver;
detail::load_impl(ar, obj, version,
has_direct_serialization<IArchiver, OArchiver>());
}
template<typename Archive>
inline void
serialize(Archive& ar, boost::python::object& obj, const unsigned int version)
{
boost::serialization::split_free(ar, obj, version);
}
} } // end namespace boost::python
/************************************************************************
* Boost.MPI-Specific Section *
************************************************************************/
namespace boost { namespace mpi {
class packed_iarchive;
class packed_oarchive;
} } // end namespace boost::mpi
BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(
::boost::mpi::packed_iarchive,
::boost::mpi::packed_oarchive)
namespace boost { namespace mpi { namespace python {
template<typename T>
void
register_serialized(const T& value, PyTypeObject* type)
{
using boost::python::register_serialized;
register_serialized<packed_iarchive, packed_oarchive>(value, type);
}
} } } // end namespace boost::mpi::python
#endif // BOOST_MPI_PYTHON_SERIALIZE_HPP

View File

@@ -0,0 +1,209 @@
// (C) Copyright 2006 Douglas Gregor <doug.gregor -at- gmail.com>
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
#ifndef BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
#define BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
/** @file skeleton_and_content.hpp
*
* This file reflects the skeleton/content facilities into Python.
*/
#include <boost/python.hpp>
#include <boost/mpi.hpp>
#include <boost/function/function1.hpp>
#define BOOST_MPI_PYTHON_FORWARD_ONLY
#include <boost/mpi/python.hpp>
#include <boost/mpi/python/serialize.hpp>
namespace boost { namespace mpi { namespace python {
/**
* INTERNAL ONLY
*
* This @c content class is a wrapper around the C++ "content"
* retrieved from get_content. This wrapper is only needed to store a
* copy of the Python object on which get_content() was called.
*/
class content : public boost::mpi::content
{
typedef boost::mpi::content inherited;
public:
content(const inherited& base, boost::python::object object)
: inherited(base), object(object) { }
inherited& base() { return *this; }
const inherited& base() const { return *this; }
boost::python::object object;
};
/**
* INTERNAL ONLY
*
* A class specific to the Python bindings that mimics the behavior of
* the skeleton_proxy<T> template. In the case of Python skeletons, we
* only need to know the object (and its type) to transmit the
* skeleton. This is the only user-visible skeleton proxy type,
* although instantiations of its derived classes (@c
* skeleton_proxy<T>) will be returned from the Python skeleton()
* function.
*/
class skeleton_proxy_base
{
public:
skeleton_proxy_base(const boost::python::object& object) : object(object) { }
boost::python::object object;
};
/**
* INTERNAL ONLY
*
* The templated @c skeleton_proxy class represents a skeleton proxy
* in Python. The only data is stored in the @c skeleton_proxy_base
* class (which is the type actually exposed as @c skeleton_proxy in
* Python). However, the type of @c skeleton_proxy<T> is important for
* (de-)serialization of @c skeleton_proxy<T>'s for transmission.
*/
template<typename T>
class skeleton_proxy : public skeleton_proxy_base
{
public:
skeleton_proxy(const boost::python::object& object)
: skeleton_proxy_base(object) { }
};
namespace detail {
using boost::python::object;
using boost::python::extract;
extern BOOST_MPI_DECL boost::python::object skeleton_proxy_base_type;
template<typename T>
struct skeleton_saver
{
void
operator()(packed_oarchive& ar, const object& obj, const unsigned int)
{
packed_skeleton_oarchive pso(ar);
pso << extract<T&>(obj.attr("object"))();
}
};
template<typename T>
struct skeleton_loader
{
void
operator()(packed_iarchive& ar, object& obj, const unsigned int)
{
packed_skeleton_iarchive psi(ar);
extract<skeleton_proxy<T>&> proxy(obj);
if (!proxy.check())
obj = object(skeleton_proxy<T>(object(T())));
psi >> extract<T&>(obj.attr("object"))();
}
};
/**
* The @c skeleton_content_handler structure contains all of the
* information required to extract a skeleton and content from a
* Python object with a certain C++ type.
*/
struct skeleton_content_handler {
function1<object, const object&> get_skeleton_proxy;
function1<content, const object&> get_content;
};
/**
* A function object that extracts the skeleton from of a Python
* object, which is actually a wrapped C++ object of type T.
*/
template<typename T>
struct do_get_skeleton_proxy
{
object operator()(object value) {
return object(skeleton_proxy<T>(value));
}
};
/**
* A function object that extracts the content of a Python object,
* which is actually a wrapped C++ object of type T.
*/
template<typename T>
struct do_get_content
{
content operator()(object value_obj) {
T& value = extract<T&>(value_obj)();
return content(boost::mpi::get_content(value), value_obj);
}
};
/**
* Determine if a skeleton and content handler for @p type has
* already been registered.
*/
BOOST_MPI_PYTHON_DECL bool
skeleton_and_content_handler_registered(PyTypeObject* type);
/**
* Register a skeleton/content handler with a particular Python type
* (which actually wraps a C++ type).
*/
BOOST_MPI_PYTHON_DECL void
register_skeleton_and_content_handler(PyTypeObject*,
const skeleton_content_handler&);
} // end namespace detail
template<typename T>
void register_skeleton_and_content(const T& value, PyTypeObject* type)
{
using boost::python::detail::direct_serialization_table;
using boost::python::detail::get_direct_serialization_table;
using namespace boost::python;
// Determine the type
if (!type)
type = object(value).ptr()->ob_type;
// Don't re-register the same type.
if (detail::skeleton_and_content_handler_registered(type))
return;
// Register the skeleton proxy type
{
boost::python::scope proxy_scope(detail::skeleton_proxy_base_type);
std::string name("skeleton_proxy<");
name += typeid(T).name();
name += ">";
class_<skeleton_proxy<T>, bases<skeleton_proxy_base> >(name.c_str(),
no_init);
}
// Register the saver and loader for the associated skeleton and
// proxy, to allow (de-)serialization of skeletons via the proxy.
direct_serialization_table<packed_iarchive, packed_oarchive>& table =
get_direct_serialization_table<packed_iarchive, packed_oarchive>();
table.register_type(detail::skeleton_saver<T>(),
detail::skeleton_loader<T>(),
skeleton_proxy<T>(object(value)));
// Register the rest of the skeleton/content mechanism, including
// handlers that extract a skeleton proxy from a Python object and
// extract the content from a Python object.
detail::skeleton_content_handler handler;
handler.get_skeleton_proxy = detail::do_get_skeleton_proxy<T>();
handler.get_content = detail::do_get_content<T>();
detail::register_skeleton_and_content_handler(type, handler);
}
} } } // end namespace boost::mpi::python
#endif // BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP