1
2
3
4
5
6 """
7 This file contains C++ code needed to export one dimensional static arrays.
8 """
9
10
11 namespace = "pyplusplus::convenience"
12
13 file_name = "__convenience.pypp.hpp"
14
15 code = \
16 """// Copyright 2004-2008 Roman Yakovenko.
17 // Distributed under the Boost Software License, Version 1.0. (See
18 // accompanying file LICENSE_1_0.txt or copy at
19 // http://www.boost.org/LICENSE_1_0.txt)
20
21 #ifndef __convenience_pyplusplus_hpp__
22 #define __convenience_pyplusplus_hpp__
23
24 #include "boost/python.hpp"
25
26 namespace pyplusplus{ namespace convenience{
27
28 //TODO: Replace index_type with Boost.Python defined ssize_t type.
29 // This should be done by checking Python and Boost.Python version.
30 typedef int index_type;
31
32 inline void
33 raise_error( PyObject *exception, const char *message ){
34 PyErr_SetString(exception, message);
35 boost::python::throw_error_already_set();
36 }
37
38 inline index_type sequence_len(boost::python::object const& obj){
39 if( !PySequence_Check( obj.ptr() ) ){
40 raise_error( PyExc_TypeError, "Sequence expected" );
41 }
42
43 index_type result = PyObject_Length( obj.ptr() );
44 if( PyErr_Occurred() ){
45 boost::python::throw_error_already_set();
46 }
47 return result;
48 }
49
50 inline void
51 ensure_sequence( boost::python::object seq, index_type expected_length=-1 ){
52 index_type length = sequence_len( seq );
53 if( expected_length != -1 && length != expected_length ){
54 std::stringstream err;
55 err << "Expected sequence length is " << expected_length << ". "
56 << "Actual sequence length is " << length << ".";
57 raise_error( PyExc_ValueError, err.str().c_str() );
58 }
59 }
60
61 template< class ExpectedType >
62 void ensure_uniform_sequence( boost::python::object seq, index_type expected_length=-1 ){
63 ensure_sequence( seq, expected_length );
64
65 index_type length = sequence_len( seq );
66 for( index_type index = 0; index < length; ++index ){
67 boost::python::object item = seq[index];
68
69 boost::python::extract<ExpectedType> type_checker( item );
70 if( !type_checker.check() ){
71 std::string expected_type_name( boost::python::type_id<ExpectedType>().name() );
72
73 std::string item_type_name("different");
74 PyObject* item_impl = item.ptr();
75 if( item_impl && item_impl->ob_type && item_impl->ob_type->tp_name ){
76 item_type_name = std::string( item_impl->ob_type->tp_name );
77 }
78
79 std::stringstream err;
80 err << "Sequence should contain only items with type \\"" << expected_type_name << "\\". "
81 << "Item at position " << index << " has \\"" << item_type_name << "\\" type.";
82 raise_error( PyExc_ValueError, err.str().c_str() );
83 }
84 }
85 }
86
87 template< class Iterator, class Inserter >
88 void copy_container( Iterator begin, Iterator end, Inserter inserter ){
89 for( Iterator index = begin; index != end; ++index )
90 inserter( *index );
91 }
92
93 template< class Inserter >
94 void copy_sequence( boost::python::object const& seq, Inserter inserter ){
95 index_type length = sequence_len( seq );
96 for( index_type index = 0; index < length; ++index ){
97 inserter = seq[index];
98 }
99 }
100
101 template< class Inserter, class TItemType >
102 void copy_sequence( boost::python::object const& seq, Inserter inserter, boost::type< TItemType > ){
103 index_type length = sequence_len( seq );
104 for( index_type index = 0; index < length; ++index ){
105 boost::python::object item = seq[index];
106 inserter = boost::python::extract< TItemType >( item );
107 }
108 }
109
110 struct list_inserter{
111 list_inserter( boost::python::list& py_list )
112 : m_py_list( py_list )
113 {}
114
115 template< class T >
116 void operator()( T const & value ){
117 m_py_list.append( value );
118 }
119 private:
120 boost::python::list& m_py_list;
121 };
122
123 template < class T >
124 struct array_inserter_t{
125 array_inserter_t( T* array, index_type size )
126 : m_array( array )
127 , m_curr_pos( 0 )
128 , m_size( size )
129 {}
130
131 void insert( const T& item ){
132 if( m_size <= m_curr_pos ){
133 std::stringstream err;
134 err << "Index out of range. Array size is" << m_size << ", "
135 << "current position is" << m_curr_pos << ".";
136 raise_error( PyExc_ValueError, err.str().c_str() );
137 }
138 m_array[ m_curr_pos ] = item;
139 m_curr_pos += 1;
140 }
141
142 array_inserter_t<T>&
143 operator=( boost::python::object const & item ){
144 insert( boost::python::extract< T >( item ) );
145 return *this;
146 }
147
148 private:
149 T* m_array;
150 index_type m_curr_pos;
151 const index_type m_size;
152 };
153
154 template< class T>
155 array_inserter_t<T> array_inserter( T* array, index_type size ){
156 return array_inserter_t<T>( array, size );
157 }
158
159 inline boost::python::object
160 get_out_argument( boost::python::object result, const char* arg_name ){
161 if( !PySequence_Check( result.ptr() ) ){
162 return result;
163 }
164 boost::python::object cls = boost::python::getattr( result, "__class__" );
165 boost::python::object cls_name = boost::python::getattr( cls, "__name__" );
166 std::string name = boost::python::extract< std::string >( cls_name );
167 if( "named_tuple" == name ){
168 return boost::python::getattr( result, arg_name );
169 }
170 else{
171 return result;
172 }
173
174 }
175
176 inline boost::python::object
177 get_out_argument( boost::python::object result, index_type index ){
178 if( !PySequence_Check( result.ptr() ) ){
179 return result;
180 }
181 boost::python::object cls = boost::python::getattr( result, "__class__" );
182 boost::python::object cls_name = boost::python::getattr( cls, "__name__" );
183 std::string name = boost::python::extract< std::string >( cls_name );
184 if( "named_tuple" == name ){
185 return result[ index ];
186 }
187 else{
188 return result;
189 }
190 }
191
192 } /*pyplusplus*/ } /*convenience*/
193
194 namespace pyplus_conv = pyplusplus::convenience;
195
196 #endif//__convenience_pyplusplus_hpp__
197
198 """
199