Revision: 852
http://svn.sourceforge.net/pygccxml/?rev=852&view=rev
Author: roman_yakovenko
Date: 2007-01-06 13:55:12 -0800 (Sat, 06 Jan 2007)
Log Message:
-----------
adding new guide, which will cover automatic conversion
Modified Paths:
--------------
pyplusplus_dev/docs/troubleshooting_guide/lessons_learned.rest
Added Paths:
-----------
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/auto_conversion.cpp
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/automatic_conversion.rest
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/definition.rest
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct.rest
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py.rest
pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/www_configuration.py
Removed Paths:
-------------
pyplusplus_dev/docs/troubleshooting_guide/smart_ptrs/generate_code.py
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/auto_conversion.cpp
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/auto_conversion.cpp (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/auto_conversion.cpp 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,114 @@
+#include "boost/python.hpp"
+#include "boost/python/object.hpp" //len function
+#include "boost/python/ssize_t.hpp" //ssize_t type definition
+#include <string>
+
+struct point3d_t{
+ point3d_t()
+ : x(0), y(0), z(0)
+ {}
+
+ int x, y, z;
+};
+
+namespace bpl = boost::python;
+
+namespace point3d_conversion{
+
+struct to_tuple{
+
+ to_tuple(){
+ bpl::to_python_converter< point3d_t, to_tuple>();
+ }
+
+ static PyObject* convert(point3d_t const& pt){
+ return bpl::incref( bpl::make_tuple( pt.x, pt.y, pt.z ).ptr() );
+ }
+
+};
+
+struct from_tuple{
+
+ static void* convertible(PyObject* py_seq){
+ if( !PySequence_Check( py_seq ) ){
+ //check that the argument is a sequence
+ return 0;
+ }
+ bpl::object seq = bpl::object( bpl::handle<>( py_seq ) );
+ bpl::ssize_t size = bpl::len( seq );
+ if( 3 != size ){
+ return 0;
+ }
+ for( bpl::ssize_t i = 0; i < 3; ++i ){
+ //test that every item in sequence has int type
+ bpl::object item = seq[i];
+ bpl::extract<int> type_checker( item );
+ if( !type_checker.check() ){
+ return 0;
+ }
+ }
+ return py_seq;
+ }
+
+ //rvalue_from_python_stage1_data is a class defined in
+ //boost/python/converter/rvalue_from_python_data.hpp file. The file contains
+ //nice and not "very" technical explanation about data management for rvalue
+ //conversions from Python to C++ types.
+
+ //In my words, the rvalue_from_python_stage1_data class contains memory
+ //needed for construction of appropriate C++ object. The class also manages
+ //the life time of the constructed C++ object.
+
+ static void
+ construct( PyObject* py_seq, bpl::converter::rvalue_from_python_stage1_data* data){
+ if( !convertible( py_seq ) ){
+ bpl::throw_error_already_set();
+ }
+
+ //At this point you are exposed to low level implementation details
+ //of Boost.Python library. You use the reinterpret_cast, in order to get
+ //access to the number of bytes, needed to store C++ object
+ typedef bpl::converter::rvalue_from_python_storage<point3d_t> point3d_storage_t;
+ point3d_storage_t* the_storage = reinterpret_cast<point3d_storage_t*>( data );
+ //Now we need to get access to the memory, which will held the object.
+ void* memory_chunk = the_storage->storage.bytes;
+ //You should use placement new in order to create object in specific
+ //location
+ point3d_t* point = new (memory_chunk) point3d_t();
+ //We allocated the memory, now we should tell Boost.Python to manage( free )
+ //it later
+ data->convertible = memory_chunk;
+
+ bpl::object seq = bpl::object( bpl::handle<>( py_seq ) );
+ //Now I actually creates the object from the Python tuple
+ bpl::object tmp = seq[0];
+ point->x = bpl::extract< int >( tmp );
+ tmp = seq[1];
+ point->y = bpl::extract< int >( tmp );
+ tmp = seq[2];
+ point->z = bpl::extract< int >( tmp );
+ }
+
+};
+
+void register_conversion(){
+
+ bpl::to_python_converter< point3d_t, to_tuple>();
+
+ bpl::converter::registry::push_back( &from_tuple::convertible
+ , &from_tuple::construct
+ , bpl::type_id<point3d_t>() );
+}
+
+}//namespace point3d_conversion
+
+point3d_t zero_point() {
+ return point3d_t();
+}
+
+
+BOOST_PYTHON_MODULE( auto_conversion ){
+ point3d_conversion::register_conversion();
+ bpl::def("zero_point", &::zero_point);
+}
+
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/automatic_conversion.rest
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/automatic_conversion.rest (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/automatic_conversion.rest 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,103 @@
+===================================================
+How to register ``shared_ptr<const T>`` conversion?
+===================================================
+
+.. contents:: Table of contents
+
+------------
+Introduction
+------------
+
+.. include:: ./definition.rest
+
+---------
+Solutions
+---------
+
+There are two possible solutions to the problem. The first one is to fix
+Boost.Python library: `pointer_holder.hpp.patch`_ . The patch was contributed
+to the library ( 8-December-2006 ) and some day it will be commited to the CVS.
+
+It is also possible to solve the problem, without changing Boost.Python library:
+
+ .. code-block:: C++
+
+ namespace boost{
+
+ template<class T>
+ inline T* get_pointer( boost::shared_ptr<const T> const& p ){
+ return const_cast< T* >( p.get() );
+ }
+
+ }
+
+ namespace boost{ namespace python{
+
+ template<class T>
+ struct pointee< boost::shared_ptr<T const> >{
+ typedef T type;
+ };
+
+ } } //boost::python
+
+ namespace utils{
+
+ template< class T >
+ register_shared_ptrs_to_python(){
+ namespace bpl = boost::python;
+ bpl::register_ptr_to_python< boost::shared_ptr< T > >();
+ bpl::register_ptr_to_python< boost::shared_ptr< const T > >();
+ bpl::implicitly_convertible< boost::shared_ptr< T >, boost::shared_ptr< const T > >();
+ }
+
+ }
+
+ BOOST_PYTHON_MODULE(...){
+ class_< YourClass >( "YourClass" )
+ ...;
+ utils::register_shared_ptrs_to_python< YourClass >();
+ }
+
+The second approach is a little bit "evil" because it redefines ``get_pointer``
+function for all shared pointer class instantiations. So you should be careful.
+
+Files
+-----
+
+* `solution.cpp`_ file contains definition of a class and few functions, which
+ have ``shared_ptr< T >`` and ``shared_ptr< const T>`` as return type or as an
+ argument. The file also contains source code that exposes the defined
+ functionality to Python.
+
+* `sconstruct`_ file contains build instructions for scons build tool.
+
+* `test.py`_ file contains complete unit tests for the exposed classes
+
+* `pointer_holder.hpp.patch`_ file contains patch for the library
+
+All files contain comments, which describe what and why was done.
+
+.. _`solution.cpp` : ./solution.cpp.html
+.. _`sconstruct` : ./sconstruct.html
+.. _`test.py` : ./test.py.html
+.. _`pointer_holder.hpp.patch` : ./pointer_holder.hpp.patch.html
+
+--------
+Download
+--------
+
+https://sourceforge.net/project/showfiles.php?group_id=118209
+
+
+.. _`Py++` : ./../pyplusplus.html
+.. _`pygccxml` : http://www.language-binding.net/pygccxml/pygccxml.html
+.. _`SourceForge`: http://sourceforge.net/index.php
+
+..
+ Local Variables:
+ mode: indented-text
+ indent-tabs-mode: nil
+ sentence-end-double-space: t
+ fill-column: 70
+ End:
+
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/definition.rest
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/definition.rest (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/definition.rest 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,3 @@
+Boost.Python allows to define automatic conversion from\\to Python classes.
+While this is very, very useful functionality, the documentation for it does not
+exist. The example will shed some light on "rvalue"\\"lvalue" converters.
\ No newline at end of file
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,10 @@
+#scons build script
+SharedLibrary( target=r'auto_conversion'
+ , source=[ r'auto_conversion.cpp' ]
+ , LIBS=[ r"boost_python" ]
+ , LIBPATH=[ r"/home/roman/boost_cvs/bin",r"" ]
+ , CPPPATH=[ r"/home/roman/boost_cvs"
+ , r"/usr/include/python2.4" ]
+ , SHLIBPREFIX=''
+ , SHLIBSUFFIX='.so'
+)
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct.rest
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct.rest (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/sconstruct.rest 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,3 @@
+.. code-block::
+ :language: Python
+ :source-file: ./sconstruct
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,30 @@
+import unittest
+import shared_ptr
+
+
+class tester_t( unittest.TestCase ):
+ def __init__( self, *args ):
+ unittest.TestCase.__init__( self, *args )
+
+ def test( self ):
+ ptr = shared_ptr.create_ptr()
+ self.failUnless( ptr.text == "ptr" )
+ self.failUnless( shared_ptr.read_ptr( ptr ) == "ptr" )
+
+ const_ptr = shared_ptr.create_const_ptr()
+ self.failUnless( const_ptr.text == "const ptr" )
+ self.failUnless( shared_ptr.read_const_ptr( const_ptr ) == "const ptr" )
+
+ #testing conversion functionality
+ self.failUnless( shared_ptr.read_const_ptr( ptr ) == "ptr" )
+
+def create_suite():
+ suite = unittest.TestSuite()
+ suite.addTest( unittest.makeSuite(tester_t))
+ return suite
+
+def run_suite():
+ unittest.TextTestRunner(verbosity=2).run( create_suite() )
+
+if __name__ == "__main__":
+ run_suite()
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py.rest
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py.rest (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/test.py.rest 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,3 @@
+.. code-block::
+ :language: Python
+ :source-file: ./test.py
Added: pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/www_configuration.py
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/www_configuration.py (rev 0)
+++ pyplusplus_dev/docs/troubleshooting_guide/automatic_conversion/www_configuration.py 2007-01-06 21:55:12 UTC (rev 852)
@@ -0,0 +1,3 @@
+name = 'automatic conversion'
+files_to_skip = ['definition.rest']
+names = {}
Modified: pyplusplus_dev/docs/troubleshooting_guide/lessons_learned.rest
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/lessons_learned.rest 2007-01-06 19:27:46 UTC (rev 851)
+++ pyplusplus_dev/docs/troubleshooting_guide/lessons_learned.rest 2007-01-06 21:55:12 UTC (rev 852)
@@ -26,6 +26,13 @@
.. _`boost::shared_ptr< const T>` : ./shared_ptr/shared_ptr.html
+`automatic conversion`_
+
+ .. include:: ./automatic_conversion/definition.rest
+
+.. _`automatic conversion` : ./automatic_conversion/automatic_conversion.html
+
+
.. _`Py++` : ./../pyplusplus.html
.. _`pygccxml` : http://www.language-binding.net/pygccxml/pygccxml.html
.. _`SourceForge`: http://sourceforge.net/index.php
Deleted: pyplusplus_dev/docs/troubleshooting_guide/smart_ptrs/generate_code.py
===================================================================
--- pyplusplus_dev/docs/troubleshooting_guide/smart_ptrs/generate_code.py 2007-01-06 19:27:46 UTC (rev 851)
+++ pyplusplus_dev/docs/troubleshooting_guide/smart_ptrs/generate_code.py 2007-01-06 21:55:12 UTC (rev 852)
@@ -1,120 +0,0 @@
-#The code contained in this file will show you how to instruct Py++ to generate
-#code, that uses your smart pointer class.
-#
-
-#Advise:
-#Using your favorite editor create regular C++ header file and to it next code.
-#You don't really need to generate it every time.
-#
-# template<class T>
-# inline T * get_pointer(smart_ptr_t<T> const& p){
-# return p.get();
-# }
-#
-# template <class T>
-# struct pointee< smart_ptr_t<T> >{
-# typedef T type;
-# };
-
-
-HELD_TYPE_TMPL = \
-"""
-namespace boost{ namespace python{
-
-%(class_name)s* get_pointer( %(class_ptr_name)s const& p ){
- return p.get();
-}
-
-template <>
-struct pointee< %(class_ptr_name)s >{
- typedef %(class_name)s type;
-};
-
-}}// namespace boost::python
-"""
-
-REGISTER_PTR_TO_PYTHON_TMPL = \
-"""
-boost::python::register_ptr_to_python< %(sp_inst_class_name)s >();
-"""
-
-IMPLICITLY_CONVERTIBLE_TMPL = \
-"""
-boost::python::implicitly_convertible< %(derived)s, %(base)s >();
-"""
-
-
-def get_pointee( sp_instantiation ):
- #sp_instantiation - reference to smart_ptr_t<XXX>
- #returns reference to XXX type/declaration
- #I will find m_managed member variable and will find out its type
- no_ptr = declarations.remove_pointer( sp_instantiation.variable ('m_managed').type )
- no_alias = declarations.remove_alias( no_ptr )
- return declarations.remove_declarated( no_alias )
-
-def expose_single( sp_instantiation ):
- #This function instructs Py++ how to expose pointee class functionality
- #related to your smart pointer
- #sp_instantiation - reference to smart_ptr_t<XXX>
-
- # You don't need to expose smart_ptr_t< X > class
- sp_instantiation.exclude()
-
- pointee = get_pointee( sp_instantiation )
-
- #Our example defines derived_ptr_t class:
- #struct derived_ptr_t : public smart_ptr_t< derived_t >
- #{...};
- #Next if checks that smart_ptr_t< XXX > class has a derived class
- #and "exposes" it.
- if sp_instantiation.derived:
- assert 1 == len( sp_instantiation.derived )
- sp_derived = sp_instantiation.derived[0].related_class
- #You don't want to expose it
- sp_derived.exclude()
-
- #Adding your custom code to pointee class.
- #You don't have to warry about order or place of generated code,
- #Py++ does it right.
-
- #Telling Boost.Python how to work with your smart pointer
- pointee.add_declaration_code(
- HELD_TYPE_TMPL % { 'class_name': pointee.decl_string
- , 'class_ptr_name': sp_derived.decl_string } )
-
- #Telling Boost.Python about relationship between classes
- pointee.add_registration_code(
- IMPLICITLY_CONVERTIBLE_TMPL % { 'derived' : sp_derived.decl_string
- , 'base' : sp_instantiation.decl_string }
- , works_on_instance=False )
-
- pointee.add_registration_code(
- REGISTER_PTR_TO_PYTHON_TMPL % { 'sp_inst_class_name' : sp_derived.decl_string }
- , works_on_instance=False )
-
- #Setting class held type
- pointee.held_type = 'smart_ptr_t< %s >' % pointee.wrapper_alias
-
- #Registering relationships between classes
- pointee.add_registration_code(
- IMPLICITLY_CONVERTIBLE_TMPL % { 'derived' : pointee.held_type
- , 'base' : sp_instantiation.decl_string }
- , works_on_instance=False )
-
- pointee.add_registration_code(
- REGISTER_PTR_TO_PYTHON_TMPL % { 'sp_inst_class_name' : sp_instantiation.decl_string }
- , works_on_instance=False )
-
- #Registering relationships between classes
- base_classes = filter( lambda hierarchy_info: hierarchy_info.access_type == 'public', pointee.bases )
- for base in base_classes:
- pointee.add_registration_code(
- IMPLICITLY_CONVERTIBLE_TMPL % { 'derived' : sp_instantiation.decl_string
- , 'base' : 'smart_ptr_t< %s >' % base.related_class.decl_string }
- , works_on_instance=False)
-
-def expose(mb):
- sp_instantiations = mb.classes( lambda decl: decl.name.startswith( 'smart_ptr_t' ) )
- map( lambda sp: expose_single( sp ), sp_instantiations )
-
-
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|