[pygccxml-commit] SF.net SVN: pygccxml:[1388] pyplusplus_dev
Brought to you by:
mbaas,
roman_yakovenko
|
From: <rom...@us...> - 2008-08-08 17:44:24
|
Revision: 1388
http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1388&view=rev
Author: roman_yakovenko
Date: 2008-08-08 17:44:27 +0000 (Fri, 08 Aug 2008)
Log Message:
-----------
adding sizeof and some documentation
Modified Paths:
--------------
pyplusplus_dev/docs/documentation/functions/call_policies.rest
pyplusplus_dev/pyplusplus/code_creators/__init__.py
pyplusplus_dev/pyplusplus/code_creators/ctypes_integration_creators.py
pyplusplus_dev/pyplusplus/code_repository/ctypes_integration.py
pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py
pyplusplus_dev/pyplusplus/module_creator/creator.py
pyplusplus_dev/unittests/classes_tester.py
pyplusplus_dev/unittests/data/classes_to_be_exported.hpp
Added Paths:
-----------
pyplusplus_dev/docs/documentation/ctypes/ctypes_integration.rest
pyplusplus_dev/docs/documentation/ctypes/this_and_sizeof.rest
pyplusplus_dev/docs/documentation/ctypes/unions.rest
pyplusplus_dev/docs/documentation/ctypes/variables.rest
pyplusplus_dev/docs/documentation/ctypes/www_configuration.py
Added: pyplusplus_dev/docs/documentation/ctypes/ctypes_integration.rest
===================================================================
--- pyplusplus_dev/docs/documentation/ctypes/ctypes_integration.rest (rev 0)
+++ pyplusplus_dev/docs/documentation/ctypes/ctypes_integration.rest 2008-08-08 17:44:27 UTC (rev 1388)
@@ -0,0 +1,94 @@
+==================
+ctypes integration
+==================
+
+.. contents:: Table of contents
+
+------------
+Introduction
+------------
+
+`Boost.Python`_ is really a very powerful library, but if you are working
+with code written in plain "C" - you've got a problem. You have to create
+wrappers for almost every function or variable.
+
+In general, if you want to work with plain "C" code from `Python`_
+you don't have to create any wrapper - you can use `ctypes`_ package.
+
+About ctypes
+------------
+`ctypes`_ is a foreign function library for Python. It provides C
+compatible data types, and allows to call functions in dlls/shared
+libraries. It can be used to wrap these libraries in pure Python.
+
+
+--------
+The idea
+--------
+
+The idea behind "ctypes integration" functionality is really simple: you
+configure `Py++`_ to expose address of the variable\\return value, and than you
+you use `ctypes`_ `from_address`_ functionality to access and modify the data.
+
+Obviously, this approach has pros and cons:
+
+* cons - it could be very dangerous - you can corrupt your application memory
+
+* cons - managing memory is not something a typical `Python`_ user get used to.
+ It is too "low level".
+
+* pros - you don't need to create wrapper in C++
+
+* pros - a Python user has access to the data
+
+* pros - compilation time is smaller
+
+* pros - you still can create wrapper, but using `Python`_
+
+
+In my opinion, the better way to go is to "mix":
+
+1. expose your native code using `Boost.Python`_ and "ctypes integration"
+ functionality - it is easy and cheap
+
+2. use `ctypes`_ module to access your data
+
+3. create high level API in Python: the wrappers, which will ensure the
+ constraints and will provide more "natural" interface
+
+-------------------------
+Implemented functionality
+-------------------------
+
+`Py++`_ is able to
+
+* expose global and member variable address
+
+* expose "this" pointer value
+
+* expose a class "sizeof"
+
+* expose variable, which has a union type
+
+* return address of return value as integer - `new call policy was created`_
+
+-----------------
+Future directions
+-----------------
+
+The functionality is going to be developed father and I intend to add
+next features:
+
+* to port this functionality to 64bit systems
+
+* to add ability to expose "C" functions without using `Boost.Python`_.
+
+.. _`new call policy was created` : ./../../documentation/functions/call_policies.html#return-addressof
+.. _`ctypes` : http://docs.python.org/lib/module-ctypes.html
+.. _`from_address` : http://docs.python.org/lib/ctypes-data-types.html
+.. _`Py++` : ./../../pyplusplus.html
+.. _`pygccxml` : ./../../../pygccxml/pygccxml.html
+.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html
+.. _`Python`: http://www.python.org
+.. _`GCC-XML`: http://www.gccxml.org
+
Added: pyplusplus_dev/docs/documentation/ctypes/this_and_sizeof.rest
===================================================================
--- pyplusplus_dev/docs/documentation/ctypes/this_and_sizeof.rest (rev 0)
+++ pyplusplus_dev/docs/documentation/ctypes/this_and_sizeof.rest 2008-08-08 17:44:27 UTC (rev 1388)
@@ -0,0 +1,47 @@
+=============
+this & sizeof
+=============
+
+.. contents:: Table of contents
+
+-----------
+The purpose
+-----------
+
+`Py++`_ can expose a class ``sizeof`` and ``this`` pointer value to `Python`_.
+I created this functionality without special purpose in mind.
+
+-------
+Example
+-------
+
+ .. code-block:: Python
+
+ mb = module_builder_t( ... )
+ cls = mb.class_( <your class> )
+ cls.expose_this = True
+ cls.expose_sizeof = True
+
+The `Python`_ class will contain two properties ``this`` and ``sizeof``. The usage
+is pretty simple:
+
+ .. code-block:: Python
+
+ import ctypes
+ import <your module> import <your class> as data_t
+
+ d = data_t()
+ print d.this
+ print d.sizeof
+
+
+Warning: I hope you know what you are doing, otherwise don't blame me :-)
+
+.. _`ctypes` : http://docs.python.org/lib/module-ctypes.html
+.. _`from_address` : http://docs.python.org/lib/ctypes-data-types.html
+.. _`Py++` : ./../../pyplusplus.html
+.. _`pygccxml` : ./../../../pygccxml/pygccxml.html
+.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html
+.. _`Python`: http://www.python.org
+.. _`GCC-XML`: http://www.gccxml.org
+
Added: pyplusplus_dev/docs/documentation/ctypes/unions.rest
===================================================================
--- pyplusplus_dev/docs/documentation/ctypes/unions.rest (rev 0)
+++ pyplusplus_dev/docs/documentation/ctypes/unions.rest 2008-08-08 17:44:27 UTC (rev 1388)
@@ -0,0 +1,75 @@
+=========
+C++ union
+=========
+
+.. contents:: Table of contents
+
+------------
+Introduction
+------------
+
+`Boost.Python`_ does not help you to expose a variable, which has a union type.
+In this document, I am going to show you a complete example how to get access
+to the data, stored in the variable.
+
+`Py++`_ will not expose a union - it is impossible using `Boost.Python`_,
+instead it will expose the address of the variable and the rest is done from the
+`Python`_ using `ctypes`_ package.
+
+--------
+Example
+--------
+
+For this example I am going to use next code:
+
+ .. code-block:: C++
+
+ struct data_t{
+ union actual_data_t{
+ int i;
+ double d;
+ };
+ actual_data_t data;
+ };
+
+As in many other cases, `Py++`_ does the job automatically:
+
+ .. code-block:: Python
+
+ mb = module_builder_t( ... )
+ mb.class_( 'data_t' ).include()
+
+no special code, to achieve the desired result, was written.
+
+The generated code is boring, so I will skip it and will continue to the usage
+example:
+
+ .. code-block:: Python
+
+ import ctypes
+ import <your module> import data_t
+
+ #lets define our union
+ class actual_data_t( ctypes.Union ):
+ _fields_ = [( "i", ctypes.c_int ), ( 'd', ctypes.c_double )]
+
+ obj = data_t()
+ actual_data = actual_data_t.from_address( obj.data )
+ #you can set\get data
+ actual_data.i = 18
+ prit actual_data.i
+ actual_data.d = 12.12
+ print actual_data.d
+
+That's all. Everything should work fine. You can add few getters and setters to
+class ``data_t``, so you could verify the results. I did this for a tester, that
+checks this functionality.
+
+.. _`ctypes` : http://docs.python.org/lib/module-ctypes.html
+.. _`from_address` : http://docs.python.org/lib/ctypes-data-types.html
+.. _`Py++` : ./../../pyplusplus.html
+.. _`pygccxml` : ./../../../pygccxml/pygccxml.html
+.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html
+.. _`Python`: http://www.python.org
+.. _`GCC-XML`: http://www.gccxml.org
+
Added: pyplusplus_dev/docs/documentation/ctypes/variables.rest
===================================================================
--- pyplusplus_dev/docs/documentation/ctypes/variables.rest (rev 0)
+++ pyplusplus_dev/docs/documentation/ctypes/variables.rest 2008-08-08 17:44:27 UTC (rev 1388)
@@ -0,0 +1,78 @@
+=========
+Variables
+=========
+
+.. contents:: Table of contents
+
+--------------
+expose_address
+--------------
+
+``variable_t`` declarations have got new property ``expose_address``. If you set
+it value to ``True``, `Py++`_ will register new property with the same name, but
+the type of it will be ``unsigned int`` and the value is address of the variable.
+
+`Py++`_ will take care and generate the right code for global, static and member
+variables.
+
+----------------
+Show me the code
+----------------
+
+Lets say you have the following C++ code:
+
+ .. code-block:: C++
+
+ struct bytes_t{
+ bytes_t(){
+ data = new int[5];
+ for(int i=0; i<5; i++){
+ data[i] = i;
+ }
+ }
+ ...
+ int* data;
+ static int* x;
+ };
+
+ //somewhere in a cpp file
+ int* bytes_t::x = new int( 1997 );
+
+In order to get access to the ``bytes_t::data`` and ``bytes_t::x`` you
+have to turn on ``expose_address`` property to ``True``:
+
+ .. code-block:: Python
+
+ mb = module_builder_t( ... )
+ bytes = mb.class_( 'bytes_t' )
+ bytes.vars().expose_address = True
+
+`Py++`_ will generate code, which will expose the address of the variables.
+
+and now it is a time to show some `ctypes`_ magic:
+
+ .. code-block:: Python
+
+ import ctypes
+ import your_module as m
+
+ bytes = m.bytes_t()
+
+ data_type = ctypes.POINTER( ctypes.c_int )
+ data = data_type.from_address( bytes.data )
+ for j in range(5):
+ print '%d : %d' % ( j, data[j] )
+
+ data_type = ctypes.POINTER( ctypes.c_int )
+ data = data_type.from_address( m.bytes_t.x )
+ print x.contents.value
+
+
+.. _`ctypes` : http://docs.python.org/lib/module-ctypes.html
+.. _`from_address` : http://docs.python.org/lib/ctypes-data-types.html
+.. _`Py++` : ./../../pyplusplus.html
+.. _`pygccxml` : ./../../../pygccxml/pygccxml.html
+.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html
+.. _`Python`: http://www.python.org
+.. _`GCC-XML`: http://www.gccxml.org
+
Added: pyplusplus_dev/docs/documentation/ctypes/www_configuration.py
===================================================================
--- pyplusplus_dev/docs/documentation/ctypes/www_configuration.py (rev 0)
+++ pyplusplus_dev/docs/documentation/ctypes/www_configuration.py 2008-08-08 17:44:27 UTC (rev 1388)
@@ -0,0 +1,6 @@
+name = 'ctypes integration'
+main_html_file = 'ctypes_integration.html'
+
+names = { 'ctypes_integration' : 'ctypes integration'
+ , 'this_and_sizeof' : 'this & sizeof'}
+
Modified: pyplusplus_dev/docs/documentation/functions/call_policies.rest
===================================================================
--- pyplusplus_dev/docs/documentation/functions/call_policies.rest 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/docs/documentation/functions/call_policies.rest 2008-08-08 17:44:27 UTC (rev 1388)
@@ -209,6 +209,57 @@
mb.free_function( ... ).call_policies \
= call_policies.custom_call_policies( your call policies code, "xyz.hpp" )
+return_addressof
+----------------
+
+Class ``return_addressof`` is a model of `ResultConverterGenerator`_ which
+can be used to wrap C++ functions returning any pointer, such that the pointer
+value is converted to ``unsigned int`` and it is copied into a new Python object.
+
+This call policy was created to be used with ``ctypes`` package and provide access
+to some raw\\low level data, without creating wrappers.
+
+Pay attention: you have to manage the memory by your own.
+
+Example
+~~~~~~~
+
+.. code-block:: C++
+
+ int* get_value(){
+ static int buffer[] = { 0,1,2,3,4 };
+ return buffer;
+ }
+
+ namespace bpl = boost::python;
+ BOOST_PYTHON_MODULE(my_module){
+ def( "get_value"
+ , bpl::return_value_policy< pyplusplus::call_policies::return_addressof<> >() );
+ }
+
+The `Py++`_ code is not that different from what you already know:
+
+.. code-block:: Python
+
+ from pyplusplus import module_builder
+ from pyplusplus.module_builder import call_policies
+
+ mb = module_builder.module_builder_t( ... )
+ mb.free_function( return_type='float *' ).call_policies \
+ = call_policies.return_value_policy( call_policies.return_addressof )
+
+Python code:
+
+.. code-block:: Python
+
+ import ctypes
+ import my_module
+
+ buffer_type = ctypes.c_int * 5
+ buffer = buffer_type.from_address( my_module.get_value() )
+ assert [0,1,2,3,4] == list( buffer )
+
+
return_pointee_value
--------------------
Modified: pyplusplus_dev/pyplusplus/code_creators/__init__.py
===================================================================
--- pyplusplus_dev/pyplusplus/code_creators/__init__.py 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/pyplusplus/code_creators/__init__.py 2008-08-08 17:44:27 UTC (rev 1388)
@@ -137,3 +137,4 @@
from properties import property_t
from ctypes_integration_creators import expose_this_t
+from ctypes_integration_creators import expose_sizeof_t
Modified: pyplusplus_dev/pyplusplus/code_creators/ctypes_integration_creators.py
===================================================================
--- pyplusplus_dev/pyplusplus/code_creators/ctypes_integration_creators.py 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/pyplusplus/code_creators/ctypes_integration_creators.py 2008-08-08 17:44:27 UTC (rev 1388)
@@ -37,3 +37,19 @@
def _get_system_headers_impl( self ):
return [code_repository.ctypes_integration.file_name]
+
+class expose_sizeof_t( registration_based.registration_based_t
+ , declaration_based.declaration_based_t ):
+ """
+ creates code that expose address of the object to Python
+ """
+
+ def __init__(self, class_ ):
+ registration_based.registration_based_t.__init__( self )
+ declaration_based.declaration_based_t.__init__( self, declaration=class_)
+
+ def _create_impl(self):
+ return 'def( pyplus_conv::register_sizeof( boost::type< %s >() ) )' % self.decl_identifier
+
+ def _get_system_headers_impl( self ):
+ return [code_repository.ctypes_integration.file_name]
Modified: pyplusplus_dev/pyplusplus/code_repository/ctypes_integration.py
===================================================================
--- pyplusplus_dev/pyplusplus/code_repository/ctypes_integration.py 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/pyplusplus/code_repository/ctypes_integration.py 2008-08-08 17:44:27 UTC (rev 1388)
@@ -26,6 +26,7 @@
#include "boost/mpl/vector.hpp"
#include "boost/function.hpp"
#include "boost/cstdint.hpp"
+#include "boost/type.hpp"
#include "boost/bind.hpp"
@@ -94,6 +95,29 @@
const char* m_name;
};
+
+class register_sizeof : public boost::python::def_visitor<register_sizeof>
+{
+ friend class boost::python::def_visitor_access;
+
+public:
+
+ template< typename TType >
+ register_sizeof( boost::type< TType > )
+ : m_sizeof( sizeof( TType ) )
+ {}
+
+ template <class classT>
+ void visit(classT& c) const{
+ boost::python::scope cls_scope( c );
+ cls_scope.attr("sizeof") = m_sizeof;
+ }
+
+private:
+ size_t m_sizeof;
+};
+
+
} /*pyplusplus*/ } /*convenience*/
namespace pyplus_conv = pyplusplus::convenience;
Modified: pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py
===================================================================
--- pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py 2008-08-08 17:44:27 UTC (rev 1388)
@@ -191,6 +191,7 @@
self._require_self_reference = False
self._exposed_class_type = self.EXPOSED_CLASS_TYPE.DECLARED
self._expose_this = None
+ self._expose_sizeof = None
def _get_redefine_operators( self ):
return self._redefine_operators
@@ -636,6 +637,13 @@
expose_this = property( _get_expose_this, _set_expose_this
, doc="boolean, if True an object address( this pointer ) will be exposed to Python as integer.")
+ def _get_expose_sizeof( self ):
+ return self._expose_sizeof
+ def _set_expose_sizeof( self, new_value ):
+ self._expose_sizeof = new_value
+ expose_sizeof = property( _get_expose_sizeof, _set_expose_sizeof
+ , doc="boolean, if True the sizeof(obj) will be exposed to Python as integer.")
+
@property
def introduces_new_scope(self):
"""returns True, if during exposing this class, new scope will be created
Modified: pyplusplus_dev/pyplusplus/module_creator/creator.py
===================================================================
--- pyplusplus_dev/pyplusplus/module_creator/creator.py 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/pyplusplus/module_creator/creator.py 2008-08-08 17:44:27 UTC (rev 1388)
@@ -592,6 +592,9 @@
if cls_decl.expose_this:
cls_cc.adopt_creator( code_creators.expose_this_t( cls_decl ) )
+ if cls_decl.expose_sizeof:
+ cls_cc.adopt_creator( code_creators.expose_sizeof_t( cls_decl ) )
+
for decl in exportable_members:
if decl in exposed:
continue
Modified: pyplusplus_dev/unittests/classes_tester.py
===================================================================
--- pyplusplus_dev/unittests/classes_tester.py 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/unittests/classes_tester.py 2008-08-08 17:44:27 UTC (rev 1388)
@@ -19,6 +19,7 @@
def customize(self, mb ):
mb.classes().expose_this = True
+ mb.classes().expose_sizeof = True
mb.class_( 'fundamental2' ).alias = 'FUNDAMENTAL2'
apple = mb.class_( 'apple' )
self.failUnless( apple.alias == 'the_tastest_fruit' )
@@ -53,6 +54,7 @@
self.failUnless( -24 == module.protected_static_t().invert_sign(24) )
self.failUnless( 67 == module.protected_static_t().invert_sign(-67) )
self.failUnless( module.protected_static_t().this )
+ self.failUnless( module.protected_static_t().sizeof )
def create_suite():
suite = unittest.TestSuite()
Modified: pyplusplus_dev/unittests/data/classes_to_be_exported.hpp
===================================================================
--- pyplusplus_dev/unittests/data/classes_to_be_exported.hpp 2008-08-08 14:32:06 UTC (rev 1387)
+++ pyplusplus_dev/unittests/data/classes_to_be_exported.hpp 2008-08-08 17:44:27 UTC (rev 1388)
@@ -38,7 +38,7 @@
namespace abstracts{
class abstract{
-public:
+public:
abstract(){}
abstract(int){}
abstract(int, double, const abstract&){}
@@ -48,13 +48,13 @@
virtual bool overloaded_virtual(){ return true;}
virtual bool overloaded_virtual(int){ return true;}
-
+
virtual int overloaded_pure_virtual(int) const = 0;
virtual void overloaded_pure_virtual(double) const = 0;
-
+
virtual int some_virtual(){ return 1; }
-};
-
+};
+
}
namespace constructors{
@@ -64,11 +64,11 @@
constructor1( const constructor1& ){}
constructor1(int x, int y){}
constructor1(int y, const constructor1& x ){}
-
+
constructor1( const double ){}
struct internal_data{};
constructor1( const internal_data ){}
-};
+};
}
@@ -76,15 +76,17 @@
struct scope_based_exposer{
enum EColor{ red, green, blue };
scope_based_exposer(EColor c=blue){}
-};
+};
}
namespace protected_static{
class protected_static_t{
protected:
static int identity(int x){ return x; }
-
+
int invert_sign(int x){ return -1*x; }
+private:
+ int i;
};
};
@@ -104,15 +106,15 @@
};
};
-}//classes
+}//classes
namespace pyplusplus{ namespace aliases{
-
+
typedef classes::hierarchical::apple the_tastest_fruit;
-
+
typedef classes::protected_static::protected_static_t PROTECTED_STATIC_T_1;
typedef classes::protected_static::protected_static_t PROTECTED_STATIC_T_2;
-
+
}}
#endif//__classes_to_be_exported_hpp__
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|