Re: [C++-sig] Conversion of python files to C++ ostreams

2010-04-03 Thread Christopher Bruns
On Thu, Apr 1, 2010 at 7:11 PM, Ralf W. Grosse-Kunstleve  wrote:
>> Is it necessary to explicitly invoke the streambuf object from python?
>
> Yes. I could be different and in fact was different in the initial
> implementation (if you look back in the svn history). But there were
> a few subtle problems (buffer size, exception handling) and in the end
> I decided the most obvious and robust approach is to require
> streambuf(sys.stdout) or ostream(sys.stdout).

I finally got streambuf to work with my wrapped classes.  This feels
much better than the approach I was using before.  I added
"[with_custodian_and_ward< 1, 2 >()]" to the streambuf wrapper init
declaration, because I imagined it might be possible for the python
file to be destroyed before the streambuf otherwise.

Now I am faced with wrapping a constructor that takes a
"std::ostream&" as an argument.  I don't know how to write a wrapper
for a constructor in boost.python.  I'm open to suggestions on this.
For example:

// C++ API
struct Foo {
Foo(ostream& os);
};

# desired python usage
foo = Foo(streambuf(sys.stdout))

How would I wrap this Foo example?
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Conversion of python files to C++ ostreams

2010-04-03 Thread Christopher Bruns
On Thu, Apr 1, 2010 at 1:32 PM, Michele De Stefano
 wrote:
> So, as shown into the doxygen example, you have to program a wrapper
> like this one:
>
> foo_wrap(boost::python::object pyfile) {
>
>     mds_utils::python::oFileObj      fobj(py_file);
>
>     foo(fobj);
> }

That's clever.  I wonder how boost.python would deal with overloaded
methods that use this technique.

void foo_wrap1(boost::python::object pyfile) {}
void foo_wrap2(bar_t bar) {}

def("foo", &foo_wrap1);
def("foo", &foo_wrap2);

Would boost.python know to send "bar" objects to foo_wrap2?
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


[C++-sig] Boost.Python to_python_indirect and intrusive_ptr.

2010-04-03 Thread Nicolas Colombe
Hi everyone.

I'm trying to use Boost.Python to expose some of my C++ classes and I
encountered an odd behaviour of the to_python_indirect result converter for
intrusive_ptr with specific classes.
Here is the deal:

I'm using a component-based design for my classes, meaning an aggregation of
objects with different features. These objects are ref-counted, and if they
are in the same aggregation, they share the same lifetime.
That is to say, as long as one of the components in the "ring" has a
strictly positive reference counter, every component in the ring survive
even if their ref-count drops to zero.
I use boost::intrusive_ptr to manipulate them easily.

There is the basic interface:

class Component
{
void AddRef();
void Release();
unsigned int GetRefCount();
bool AddComponent(Component*);
bool RemoveComponent(Component*);
Component* ComponentIterator(Component*);//-->Used to parse the
ring.

virtual some_virtual_fn();
};

To avoid lifetime problems when manipulating an object both from C++ and
python side, i want python to manipulate components only through
boost::intrusive_ptr.

There is the exposition code:

//-->Object wrapper
struct Component_wrapper : SandBoxProj::Component, bp::wrapper<
SandBoxProj::Component > {

Component_wrapper( ) :Component( ), bp::wrapper< SandBoxProj::Component
>(){}

virtual some_virtual_fn() {
  //overriding code...
}

default_some_virtual_fn() {
   Component::some_virtual_fn();
}
};

//-->Some declarations that boost.python needs to manipulate
boost::intrusive_ptr
namespace boost { namespace python {

   template  struct pointee< intrusive_ptr >   //-->pointee
struct for intrusive_ptr holder
 {
   typedef T type;
 };

 struct make_owning_intrusive_ptr_holder//-->ResultConverter to make an
intrusive_ptr from a raw one, inspired from to_python_indirect.hpp:79
  {
template 
static PyObject* execute(T* p)
{
  typedef objects::pointer_holder, T> holder_t;

  boost::intrusive_ptr ptr(p);
  return boost::python::objects::make_ptr_instance::execute(ptr);
}
  };

  struct return_by_intrusive_ptr//-->corresponding
ResultConverterGenerator
  {
template 
struct apply
{
  typedef to_python_indirect type;
//--> here is the usage of to_python_indirect
};
  };

}}

bp::class_<
Component_wrapper,boost::intrusive_ptr,boost::noncopyable
>( "Component", bp::init< >() )
.def( "AddComponent", &Component::AddComponent, ( bp::arg("arg0") ) )

.def( "ComponentIterator",&Component::ComponentIterator, (
bp::arg("arg0") ), bp::return_value_policy< bp::return_by_intrusive_ptr >()
)//-->this class uses the converter.
.def(
"some_virtual_fn",&Component::some_virtual_fn,&Component_wrapper::default_some_virtual_fn)
.def( "GetRefCount",&Component::GetRefCount)
.def( "RemoveComponent",&Component::RemoveComponent, ( bp::arg("arg0") )
) ;


And finally there is a scripts that uses this class and its output:

>>>from pythonbinder import *
>>>import gc

>>>Comp1=Component()
>>>Comp2=Component()
>>>print Comp2.GetRefCount()
1
//-->Ok, I manipulate an intrusive_ptr
>>>Comp2.AddComponent(Comp1)
>>>iter=None
>>>iter=Comp1.ComponentIterator(iter)
>>>print iter
   //-->Ok, There is my
C++ object
>>>iter=Comp1.ComponentIterator(iter)
>>>print iter

>>>print iter.GetRefCount()
1
//-->What the ? iter is supposed to be an intrusive ptr. After a look at
to_python_indirect, it seems that iter==Comp2, the python object wrapping
the intrusive_ptr was just addref'ed. Ok, fair enough.

>>>iter=Comp1.ComponentIterator(iter)
>>>print iter
None
//-->Now the troubles begin.
>>>del Comp2
>>>gc.collect()//-->ensure deletion, Comp2 is still alive from the C++
side, because Comp1 is alive.
>>>iter=Comp1.ComponentIterator(iter)  //May crash
>>>print iter
//-->if we made it through, a weak_ptr to some random structure.

After that, i figured out that i never went through the ResultConverters i
declared. Let's look at the execute function from to_python_indirect,

 template 
inline PyObject* execute(U const& x, mpl::false_) const
{
U* const p = &const_cast(x);
if
(is_polymorphic::value)
//-->My type is polymorphic
{
if (PyObject* o = detail::wrapper_base_::owner(p))
//-->Ok, that's why I have a refcount of 1, no matter how many python
intrusive_ptr wrappers I seem to have
return incref(o);
}
return
MakeHolder::execute(p); //-->There
is the call to my result converter.
}

What happen is that after deletion of the last python wrapping of the
intrusive_ptr, which is o in the code above, the Component_wrapper, which is
partly a python object, is not deleted (the component ring still holds it),
but it still reference its last owner which is the last instance_holder that
just got deleted, so the object returned is a random memory garbage.

Changing th

Re: [C++-sig] Conversion of python files to C++ ostreams

2010-04-03 Thread troy d. straszheim

Michele De Stefano wrote:


there is a much easier way to treat a FILE* as a C++ stream. The easy
way is to use my open source library (mds-utils,
http://code.google.com/p/mds-utils/).



Elegant use of boost::iostreams if I may say so.  I've been looking for
some usecases for some boost.python modifications I've been playing with
so I tried incorporating your FileObj.  Seems to work well.  One can
wrap a function that takes a std::ostream& like this:

using mds_utils::python::FileObj;

// c++ function we're wrapping
void sayhello(std::ostream& os)
{
  os << "*** hello ***\n";
}

//
// function object that converts object& and implements
// result_of protocol
//
struct conv {
  typedef FileObj result_type;

  result_type operator()(object& obj)
  {
 return FileObj(obj);
  }
};

BOOST_PYTHON_MODULE(mod)
{
  def("sayhello", as( &sayhello ));
  //  arg converter   ^
};

In this case python sees "sayhello" as taking a bp::object.

The as<> might need some clarification It takes a function type 
argument.  Above, the argument is the type of a function that returns 
void, which takes one argument, which is a function that returns conv 
and takes one argument of type object&.   In general, for a unary 
function 'fn' returning type R it is:


  as(&fn)

where T(U) means "convert the python object to C++ type U, then create a
temporary object T and use it to create result_of::type, then 
convert that type to R and return to python".  This is a little 
boost::proto-ish.   Maybe also a little like a C++1x concept map.  You 
could also provide a generic 'conv' struct, I skipped this so as not to 
confuse things.


-t


___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Conversion of python files to C++ ostreams

2010-04-03 Thread troy d. straszheim

Christopher Bruns wrote:

On Thu, Apr 1, 2010 at 1:32 PM, Michele De Stefano
 wrote:

So, as shown into the doxygen example, you have to program a wrapper
like this one:

foo_wrap(boost::python::object pyfile) {

mds_utils::python::oFileObj  fobj(py_file);

foo(fobj);
}


That's clever.  I wonder how boost.python would deal with overloaded
methods that use this technique.

void foo_wrap1(boost::python::object pyfile) {}
void foo_wrap2(bar_t bar) {}

def("foo", &foo_wrap1);
def("foo", &foo_wrap2);

Would boost.python know to send "bar" objects to foo_wrap2?


Boost python's "first match" overloading would kick in here... there was 
a long discussion about this on the list, check the archives.  Short 
story:  order of registration matters.  I have a possible alternate 
implementation that went dormant and hasn't been thoroughly vetted, but 
I'm coming back around to it now.


-t



___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Conversion of python files to C++ ostreams

2010-04-03 Thread troy d. straszheim

troy d. straszheim wrote:


  as(&fn)

where T(U) means "convert the python object to C++ type U, then create a
temporary object T and use it to create result_of::type, 


correction, add here "then pass that thing to fn"

> then
convert that type to R and return to python".  



-t
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Conversion of python files to C++ ostreams

2010-04-03 Thread Ralf W. Grosse-Kunstleve
> Now I am faced with wrapping a constructor that takes a

> "std::ostream&" as an argument.  I don't know how to write a wrapper
> for a constructor in boost.python.  I'm open to suggestions on this.
> For example:
> 
> // C++ API
> struct Foo {
> Foo(ostream& os);
> };
> 
> # desired python usage
> foo = Foo(streambuf(sys.stdout))

Did you already try the usual

  def(init((arg("os"

?

I think it should just work (but I haven't actually tried it).

Ralf
___
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig