[C++-sig] register_boost_array_from_python
Ralf W. Grosse-Kunstleve
rwgk at yahoo.com
Sat Jun 1 18:35:03 CEST 2002
> callback_from_python takes possession of its argument just like reference<>
> does. It looks like you're dropping a reference in the transfer from the
> tuple.
callback_from_python does not accept increment_count like reference<>
does. Are you suggesting that I use Py_INCREF directly?
> No, it's not. I think that's strictly a v1 idiom. We could consider
> reinstating it as an option, but I don't think it would play well with the
> more-sophisticated mechanism for overload resolution that I have planned.
I am happy with your approach.
> Well, yes. data->convertible is set initially to the result of your
> convertible() function. If that returns 0, the function isn't considered a
> candidate for overload resolution and the convert function is never called.
> As I said earlier, once the convert function is called, the only way to
> signal failure is with an exception.
Understood.
> How about a STL-container_from_something-which-supports-iter() converter?
> That's what people really need.
Sounds great. As it stands (new code below) I am iterating over the
sequence twice: first in convertible() and then again in construct().
Do all Python iterators support this?
Hm, if data->convertible is not 0, will construct() be called without
further preconditions? If so, I could manage my own memory where I
store the result of iterating over the input sequence. Can I then
simply assign ownership in construct() (to avoid a copy)?
Or, would it make sense to add, say, rvalue_stage0_data* to the
signature of convertible()?
About the code below: there are now three array adaptors that I have
stress-tested (so far Linux/gcc only) with boost::array, std::vector and
the "small" type of my array family which is similar to the
"fixed_capacity_vector" proposed a while ago by Synge Todo.
Example usage:
bpl_utils::register_array_from_python_list_or_tuple<
boost::array<double, 3>,
bpl_utils::fixed_size_array_registration_adaptor>();
bpl_utils::register_array_from_python_list_or_tuple<
std::vector<double>,
bpl_utils::variable_size_array_registration_adaptor>();
bpl_utils::register_array_from_python_list_or_tuple<
af::small<double, 6>,
bpl_utils::fixed_capacity_array_registration_adaptor>();
If you are interested I'd be happy to contribute this +
improvements/fixes that you might suggest + documentation to the core
library.
Ralf
struct fixed_size_array_registration_adaptor
{
template <typename ArrayType>
static bool check_size(boost::python::type<ArrayType>, std::size_t sz)
{
return ArrayType::size() == sz;
}
template <typename ArrayType>
static void reserve(ArrayType& a, std::size_t sz)
{
assert(check_size(a, sz));
}
template <typename ArrayType, typename ValueType>
static void set_value(ArrayType& a, std::size_t i, ValueType const& v)
{
a[i] = v;
}
};
struct variable_size_array_registration_adaptor
{
template <typename ArrayType>
static bool check_size(boost::python::type<ArrayType>, std::size_t sz)
{
return true;
}
template <typename ArrayType>
static void reserve(ArrayType& a, std::size_t sz)
{
a.reserve(sz);
}
template <typename ArrayType, typename ValueType>
static void set_value(ArrayType& a, std::size_t i, ValueType const& v)
{
assert(a.size() == i);
a.push_back(v);
}
};
struct fixed_capacity_array_registration_adaptor
: variable_size_array_registration_adaptor
{
template <typename ArrayType>
static bool check_size(boost::python::type<ArrayType>, std::size_t sz)
{
return ArrayType::max_size() >= sz;
}
};
template <typename ArrayType, typename ArrayAdaptor>
struct register_array_from_python_list_or_tuple
{
typedef typename ArrayType::value_type array_element_type;
register_array_from_python_list_or_tuple()
{
boost::python::converter::registry::insert(
&convertible,
&construct,
boost::python::type_id<ArrayType>());
}
static void* convertible(PyObject* obj)
{
using namespace boost::python;
tuple t = list_or_tuple_as_tuple(obj);
if (!ArrayAdaptor::check_size(type<ArrayType>(), t.size())) return 0;
for(std::size_t i=0;i<t.size();i++) {
from_python<array_element_type const&> from_py(t[i].get());
if (!from_py.convertible()) return 0;
}
return obj;
}
static void construct(
PyObject* obj, boost::python::converter::rvalue_stage1_data* data)
{
using namespace boost::python;
tuple t = list_or_tuple_as_tuple(obj);
void* storage = ((
converter::rvalue_base_data<ArrayType>*)data)->storage.bytes;
new (storage) ArrayType();
data->convertible = storage;
ArrayType& result = *((ArrayType*)storage);
ArrayAdaptor::reserve(result, t.size());
for(std::size_t i=0;i<t.size();i++) {
#if 0
result[i] = converter::callback_from_python<
array_element_type>()(t[i].get());
#else
from_python<array_element_type const&> from_py(t[i].get());
ArrayAdaptor::set_value(result, i, from_py(t[i].get()));
#endif
}
}
private:
static boost::python::tuple list_or_tuple_as_tuple(PyObject* obj)
{
using namespace boost::python;
tuple result;
if (PyList_Check(obj)) {
result = tuple(ref(PyList_AsTuple(obj)));
}
else if (PyTuple_Check(obj)) {
result = tuple(ref(obj, ref::increment_count));
}
return result;
}
};
__________________________________________________
Do You Yahoo!?
Yahoo! - Official partner of 2002 FIFA World Cup
http://fifaworldcup.yahoo.com
More information about the Cplusplus-sig
mailing list