Re: [C++-sig] question about implicit type conversion of vector to a custom type

2011-08-18 Thread Grant Tang


"Jim Bosch"  wrote in message news:[email protected]...

Unfortunately, there's no "best-match" type checking in Boost.Python; when 
trying to convert a Python object to a particular C++ type, it simply runs 
over a list of all the converters registered (using RTTI) for that C++ 
type.


Each of those converters then gets a chance to check whether it "matches" 
the Python object; if it thinks it does, none of the other converters get 
tried.


I'd guess that's what's happening to you - implicitly_convertible doesn't 
really do enough work in that match stage, so the first conversion you've 
registered says "I match!" and then fails by throwing an exception.


The fix might be in how you've written your vector<> conversions; when 
given a list or tuple that contains the wrong element type, they need to 
report that they "don't match", rather than matching any list or tuple and 
then throwing an exception when the element type is incorrect.


Good luck!

Jim Bosch


I change my vector<> conversion(see it in my last reply) to add 
specialization for int, float, string etc.

I added type check in convertible() function:

   template <>
   struct vector_from_python 
   {
   vector_from_python()
   {
   python::converter::registry::push_back(&convertible, &construct,
  python::type_id 
>());

   }

   static void* convertible(PyObject* obj_ptr)
   {
   if (!(PyList_Check(obj_ptr) || PyTuple_Check(obj_ptr)
 || PyIter_Check(obj_ptr)  || PyRange_Check(obj_ptr))) {
   return 0;
   }

   PyObject * first_obj = PyObject_GetItem(obj_ptr, 
PyInt_FromLong(0));

   if( !PyObject_TypeCheck(first_obj, &PyFloat_Type) ) {
   return 0;
   }

   return obj_ptr;
   }


   static void construct(PyObject* obj_ptr,
 python::converter::rvalue_from_python_stage1_data* 
data)

   {
   void* storage =
((python::converter::rvalue_from_python_storage >*)
data)->storage.bytes;
   new (storage) vector();

   data->convertible = storage;

   vector& result = *((vector*) storage);

   python::handle<> obj_iter(PyObject_GetIter(obj_ptr));

   while(1) {
   python::handle<>
py_elem_hdl(python::allow_null(PyIter_Next(obj_iter.get(;
   if (PyErr_Occurred()) {
   python::throw_error_already_set();
   }

   if (!py_elem_hdl.get()) {
   break;
   }

   python::object py_elem_obj(py_elem_hdl);
   python::extract elem_proxy(py_elem_obj);
   result.push_back(elem_proxy());
   }
   }
   };

This time the implicit type conversion works perfectly. But I got a new 
problem: the memory leak!
The memory leak happens only for float type, whenever I convert the float 
list in python to vector
of float in c++, the memory for float list is leaked. I put the call in a 
function, and called the gc.collect()

after exit the function, the memory is still not recycled.

Why is the memory of the python list is not freed after exit the scope?

Grant 



___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question about implicit type conversion of vector to a custom type

2011-08-18 Thread Jim Bosch

On 08/18/2011 09:37 AM, Grant Tang wrote:


I change my vector<> conversion(see it in my last reply) to add
specialization for int, float, string etc.
I added type check in convertible() function:



Sorry I didn't reply to your last email earlier, but it looks like 
you're on the right track.


Here's a slightly modified version of your convertible function:

static void* convertible(PyObject* obj_ptr)
{
  // Unfortunately, this no longer works on pure iterators, because
  // they don't necessarily support "obj[0]".
  // PySequence_Check should work on lists, tuples, and other
  // things that support __getitem__ with integer arguments.
  if (!(PySequence_Check(obj_ptr)) {
return 0;
  }
  // Succeed if there are no items in the sequence.
  if (PySequence_Size(obj_ptr) == 0) {
return obj_ptr;
  }
  // PySequence_GetItem takes an int directly; otherwise you'd need
  // to DECREF the int object you pass to PyObject_GetItem as well.
  PyObject * first_obj = PySequence_GetItem(obj_ptr, 0);
  if( !PyObject_TypeCheck(first_obj, &PyFloat_Type) ) {
Py_DECREF(first_obj); // avoid memory leaks on failure
return 0;
  }
  Py_DECREF(first_obj); // avoid memory leaks on success
  return obj_ptr;
}


This time the implicit type conversion works perfectly. But I got a new
problem: the memory leak!
The memory leak happens only for float type, whenever I convert the
float list in python to vector
of float in c++, the memory for float list is leaked. I put the call in
a function, and called the gc.collect()
after exit the function, the memory is still not recycled.

Why is the memory of the python list is not freed after exit the scope?



It's the missing Py_DECREF calls; it's only because of a Python 
implementation detail that you didn't have leaks with the other types. 
The Python C-API requires you to call Py_DECREF whenever you're done 
with an object.  Alternately, you can put your PyObject pointers in 
bp::handle<> or bp::object, and they'll be managed automatically.


Jim

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] question about implicit type conversion of vector to a custom type

2011-08-18 Thread Grant Tang


"Jim Bosch"  wrote in message news:[email protected]... 


On 08/18/2011 09:37 AM, Grant Tang wrote:


I change my vector<> conversion(see it in my last reply) to add
specialization for int, float, string etc.
I added type check in convertible() function:



Sorry I didn't reply to your last email earlier, but it looks like 
you're on the right track.


Here's a slightly modified version of your convertible function:

static void* convertible(PyObject* obj_ptr)
{
  // Unfortunately, this no longer works on pure iterators, because
  // they don't necessarily support "obj[0]".
  // PySequence_Check should work on lists, tuples, and other
  // things that support __getitem__ with integer arguments.
  if (!(PySequence_Check(obj_ptr)) {
return 0;
  }
  // Succeed if there are no items in the sequence.
  if (PySequence_Size(obj_ptr) == 0) {
return obj_ptr;
  }
  // PySequence_GetItem takes an int directly; otherwise you'd need
  // to DECREF the int object you pass to PyObject_GetItem as well.
  PyObject * first_obj = PySequence_GetItem(obj_ptr, 0);
  if( !PyObject_TypeCheck(first_obj, &PyFloat_Type) ) {
Py_DECREF(first_obj); // avoid memory leaks on failure
return 0;
  }
  Py_DECREF(first_obj); // avoid memory leaks on success
  return obj_ptr;
}


This time the implicit type conversion works perfectly. But I got a new
problem: the memory leak!
The memory leak happens only for float type, whenever I convert the
float list in python to vector
of float in c++, the memory for float list is leaked. I put the call in
a function, and called the gc.collect()
after exit the function, the memory is still not recycled.

Why is the memory of the python list is not freed after exit the scope?



It's the missing Py_DECREF calls; it's only because of a Python 
implementation detail that you didn't have leaks with the other types. 
The Python C-API requires you to call Py_DECREF whenever you're done 
with an object.  Alternately, you can put your PyObject pointers in 
bp::handle<> or bp::object, and they'll be managed automatically.


Jim



Bingo! This fixes my problem. Thank you very much Jim!

Grant

___
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig