mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-20 03:23:23 +08:00
307 lines
8.6 KiB
C++
307 lines
8.6 KiB
C++
// Copyright David Abrahams 2001.
|
|
// 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)
|
|
#include <boost/python/converter/registry.hpp>
|
|
#include <boost/python/converter/registrations.hpp>
|
|
#include <boost/python/converter/builtin_converters.hpp>
|
|
|
|
#include <set>
|
|
#include <stdexcept>
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__) && defined(__GNUC__) \
|
|
&& __GNUC__ == 3 && __GNUC_MINOR__ <= 4 && !defined(__APPLE_CC__)
|
|
# define BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND
|
|
#endif
|
|
|
|
#if defined(BOOST_PYTHON_TRACE_REGISTRY) \
|
|
|| defined(BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND)
|
|
# include <iostream>
|
|
#endif
|
|
|
|
namespace boost { namespace python { namespace converter {
|
|
BOOST_PYTHON_DECL PyTypeObject const* registration::expected_from_python_type() const
|
|
{
|
|
if (this->m_class_object != 0)
|
|
return this->m_class_object;
|
|
|
|
std::set<PyTypeObject const*> pool;
|
|
|
|
for(rvalue_from_python_chain* r = rvalue_chain; r ; r=r->next)
|
|
if(r->expected_pytype)
|
|
pool.insert(r->expected_pytype());
|
|
|
|
//for now I skip the search for common base
|
|
if (pool.size()==1)
|
|
return *pool.begin();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
BOOST_PYTHON_DECL PyTypeObject const* registration::to_python_target_type() const
|
|
{
|
|
if (this->m_class_object != 0)
|
|
return this->m_class_object;
|
|
|
|
if (this->m_to_python_target_type != 0)
|
|
return this->m_to_python_target_type();
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOST_PYTHON_DECL PyTypeObject* registration::get_class_object() const
|
|
{
|
|
if (this->m_class_object == 0)
|
|
{
|
|
::PyErr_Format(
|
|
PyExc_TypeError
|
|
, const_cast<char*>("No Python class registered for C++ class %s")
|
|
, this->target_type.name());
|
|
|
|
throw_error_already_set();
|
|
}
|
|
|
|
return this->m_class_object;
|
|
}
|
|
|
|
BOOST_PYTHON_DECL PyObject* registration::to_python(void const volatile* source) const
|
|
{
|
|
if (this->m_to_python == 0)
|
|
{
|
|
handle<> msg(
|
|
#if PY_VERSION_HEX >= 0x3000000
|
|
::PyUnicode_FromFormat
|
|
#else
|
|
::PyString_FromFormat
|
|
#endif
|
|
(
|
|
"No to_python (by-value) converter found for C++ type: %s"
|
|
, this->target_type.name()
|
|
)
|
|
);
|
|
|
|
PyErr_SetObject(PyExc_TypeError, msg.get());
|
|
|
|
throw_error_already_set();
|
|
}
|
|
|
|
return source == 0
|
|
? incref(Py_None)
|
|
: this->m_to_python(const_cast<void*>(source));
|
|
}
|
|
|
|
namespace
|
|
{
|
|
template< typename T >
|
|
void delete_node( T* node )
|
|
{
|
|
if( !!node && !!node->next )
|
|
delete_node( node->next );
|
|
delete node;
|
|
}
|
|
}
|
|
|
|
registration::~registration()
|
|
{
|
|
delete_node(lvalue_chain);
|
|
delete_node(rvalue_chain);
|
|
}
|
|
|
|
|
|
namespace // <unnamed>
|
|
{
|
|
typedef registration entry;
|
|
|
|
typedef std::set<entry> registry_t;
|
|
|
|
#ifndef BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND
|
|
registry_t& entries()
|
|
{
|
|
static registry_t registry;
|
|
|
|
# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION
|
|
static bool builtin_converters_initialized = false;
|
|
if (!builtin_converters_initialized)
|
|
{
|
|
// Make this true early because registering the builtin
|
|
// converters will cause recursion.
|
|
builtin_converters_initialized = true;
|
|
|
|
initialize_builtin_converters();
|
|
}
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
std::cout << "registry: ";
|
|
for (registry_t::iterator p = registry.begin(); p != registry.end(); ++p)
|
|
{
|
|
std::cout << p->target_type << "; ";
|
|
}
|
|
std::cout << '\n';
|
|
# endif
|
|
# endif
|
|
return registry;
|
|
}
|
|
#else
|
|
registry_t& static_registry()
|
|
{
|
|
static registry_t result;
|
|
return result;
|
|
}
|
|
|
|
bool static_builtin_converters_initialized()
|
|
{
|
|
static bool result = false;
|
|
if (result == false) {
|
|
result = true;
|
|
std::cout << std::flush;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
registry_t& entries()
|
|
{
|
|
# ifndef BOOST_PYTHON_SUPPRESS_REGISTRY_INITIALIZATION
|
|
if (!static_builtin_converters_initialized())
|
|
{
|
|
initialize_builtin_converters();
|
|
}
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
std::cout << "registry: ";
|
|
for (registry_t::iterator p = static_registry().begin(); p != static_registry().end(); ++p)
|
|
{
|
|
std::cout << p->target_type << "; ";
|
|
}
|
|
std::cout << '\n';
|
|
# endif
|
|
# endif
|
|
return static_registry();
|
|
}
|
|
#endif // BOOST_PYTHON_CONVERTER_REGISTRY_APPLE_MACH_WORKAROUND
|
|
|
|
entry* get(type_info type, bool is_shared_ptr = false)
|
|
{
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
registry_t::iterator p = entries().find(entry(type));
|
|
|
|
std::cout << "looking up " << type << ": "
|
|
<< (p == entries().end() || p->target_type != type
|
|
? "...NOT found\n" : "...found\n");
|
|
# endif
|
|
std::pair<registry_t::const_iterator,bool> pos_ins
|
|
= entries().insert(entry(type,is_shared_ptr));
|
|
|
|
# if __MWERKS__ >= 0x3000
|
|
// do a little invariant checking if a change was made
|
|
if ( pos_ins.second )
|
|
assert(entries().invariants());
|
|
# endif
|
|
return const_cast<entry*>(&*pos_ins.first);
|
|
}
|
|
} // namespace <unnamed>
|
|
|
|
namespace registry
|
|
{
|
|
void insert(to_python_function_t f, type_info source_t, PyTypeObject const* (*to_python_target_type)())
|
|
{
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
std::cout << "inserting to_python " << source_t << "\n";
|
|
# endif
|
|
entry* slot = get(source_t);
|
|
|
|
assert(slot->m_to_python == 0); // we have a problem otherwise
|
|
if (slot->m_to_python != 0)
|
|
{
|
|
std::string msg = (
|
|
std::string("to-Python converter for ")
|
|
+ source_t.name()
|
|
+ " already registered; second conversion method ignored."
|
|
);
|
|
|
|
if ( ::PyErr_Warn( NULL, const_cast<char*>(msg.c_str()) ) )
|
|
{
|
|
throw_error_already_set();
|
|
}
|
|
}
|
|
slot->m_to_python = f;
|
|
slot->m_to_python_target_type = to_python_target_type;
|
|
}
|
|
|
|
// Insert an lvalue from_python converter
|
|
void insert(convertible_function convert, type_info key, PyTypeObject const* (*exp_pytype)())
|
|
{
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
std::cout << "inserting lvalue from_python " << key << "\n";
|
|
# endif
|
|
entry* found = get(key);
|
|
lvalue_from_python_chain *registration = new lvalue_from_python_chain;
|
|
registration->convert = convert;
|
|
registration->next = found->lvalue_chain;
|
|
found->lvalue_chain = registration;
|
|
|
|
insert(convert, 0, key,exp_pytype);
|
|
}
|
|
|
|
// Insert an rvalue from_python converter
|
|
void insert(convertible_function convertible
|
|
, constructor_function construct
|
|
, type_info key
|
|
, PyTypeObject const* (*exp_pytype)())
|
|
{
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
std::cout << "inserting rvalue from_python " << key << "\n";
|
|
# endif
|
|
entry* found = get(key);
|
|
rvalue_from_python_chain *registration = new rvalue_from_python_chain;
|
|
registration->convertible = convertible;
|
|
registration->construct = construct;
|
|
registration->expected_pytype = exp_pytype;
|
|
registration->next = found->rvalue_chain;
|
|
found->rvalue_chain = registration;
|
|
}
|
|
|
|
// Insert an rvalue from_python converter
|
|
void push_back(convertible_function convertible
|
|
, constructor_function construct
|
|
, type_info key
|
|
, PyTypeObject const* (*exp_pytype)())
|
|
{
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
std::cout << "push_back rvalue from_python " << key << "\n";
|
|
# endif
|
|
rvalue_from_python_chain** found = &get(key)->rvalue_chain;
|
|
while (*found != 0)
|
|
found = &(*found)->next;
|
|
|
|
rvalue_from_python_chain *registration = new rvalue_from_python_chain;
|
|
registration->convertible = convertible;
|
|
registration->construct = construct;
|
|
registration->expected_pytype = exp_pytype;
|
|
registration->next = 0;
|
|
*found = registration;
|
|
}
|
|
|
|
registration const& lookup(type_info key)
|
|
{
|
|
return *get(key);
|
|
}
|
|
|
|
registration const& lookup_shared_ptr(type_info key)
|
|
{
|
|
return *get(key, true);
|
|
}
|
|
|
|
registration const* query(type_info type)
|
|
{
|
|
registry_t::iterator p = entries().find(entry(type));
|
|
# ifdef BOOST_PYTHON_TRACE_REGISTRY
|
|
std::cout << "querying " << type
|
|
<< (p == entries().end() || p->target_type != type
|
|
? "...NOT found\n" : "...found\n");
|
|
# endif
|
|
return (p == entries().end() || p->target_type != type) ? 0 : &*p;
|
|
}
|
|
} // namespace registry
|
|
|
|
}}} // namespace boost::python::converter
|