[C++-sig] register_boost_array_from_python

Ralf W. Grosse-Kunstleve rwgk at yahoo.com
Sat Jun 1 14:58:04 CEST 2002


> Very nice effort!

Thanks for the encouragement. Attached is the next version of the tiny
array converter, this time for boost::array<T,N> in case someone else
wants to play with it.

As shown, it does about 50000 conversions from tuples to boost::arrays
per second on our Linux PC without showing memory leaks. This includes
recovering from TypeErrors 20000 times (tuple too long; wrong element
type).

> You should use converter::callback_from_python<ElementType> instead of
> from_python<ElementType> to extract elements.

If I change #if 0 below to #if 1 I receive a segmentation fault after
a few successful passes. What am I doing wrong?

The following questions are not directly relevant to the code below,
but if you could answer them it would help foster my understanding.

> An rvalue (server side) converter must always register a function to signal
> convertibility; that's how overload resolution works. If conversion is
> going to fail after the convertible function returns true, it must be via
> an exception.

While playing around I tried throw_argument_error(). Then Python was
complaining about a "NULL result without error in PyObject_Call."
Of course, I was hoping that the overload resolution would catch
the exception and continue. Is that not an option anymore?

> > - I was hoping that
> >       data->convertible = storage;
> >   signals that the conversion was successful, and failed otherwise.
> 
> Not quite:
> data->convertible = 0 signals failure.
> data->convertible = storage signals that the result object was constructed
> in the converter, and must be destroyed

What is the behavior if data->convertible == 0? If I just set
data->convertible = 0 flow control still arrives in my wrapped
function, but accessing the passed value causes a segmentation fault.
Does that mean I absolutely have to throw an exception if something
goes wrong in construct()?

Thanks,
        Ralf

P.S.: I will now try to work this into a generic
array_from_python_list_or_tuple converter.


  template <typename ElementType, std::size_t N>
  struct register_boost_array_from_python
  {
    typedef boost::array<ElementType, N> array_type;

    register_boost_array_from_python()
    {
      boost::python::converter::registry::insert(
        &convertible,
        &construct,
        boost::python::type_id<array_type>());
    }

    static void* convertible(PyObject* obj)
    {
      using namespace boost::python;
      tuple t = list_or_tuple_as_tuple(obj);
      if (t.size() != N) return 0;
      for(std::size_t i=0;i<t.size();i++) {
        from_python<ElementType 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);
      //if (t.size() == 4) { data->convertible = 0; return; }
      void* storage = ((
        converter::rvalue_base_data<array_type>*)data)->storage.bytes;
      new (storage) array_type();
      data->convertible = storage;
      array_type& result = *((array_type*)storage);
      cctbx_assert(t.size() == result.size());
      for(std::size_t i=0;i<result.size();i++) {
#if 0
        result[i] = converter::callback_from_python<ElementType>()(t[i].get());
#else
        from_python<ElementType const&> from_py(t[i].get());
        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