1 #ifndef AWFUL_PYTHON_BASIC_TYPES_H
2 #define AWFUL_PYTHON_BASIC_TYPES_H
4 namespace awful
{ namespace PythonImpl
6 template< typename category
, typename T
> struct TypeConverter
10 // No overflow checking for now because I'm lazy.
11 struct IntegerTypeConverter
13 static bool CheckType_nothrow( PyObject
* pPyObj_
)
15 return PyInt_Check( pPyObj_
) || PyLong_Check( pPyObj_
);
19 template< typename T
> struct SignedIntegerTypeConverter
: public IntegerTypeConverter
21 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, T
& Dest_
)
23 if( PyInt_Check( pPyObj_
) )
24 Dest_
= PyInt_AS_LONG( pPyObj_
);
26 Dest_
= PyLong_AsLongLong( pPyObj_
);
29 static void ConvertFromPython( PyObject
* pPyObj_
, T
& Dest_
)
31 if( !CheckType_nothrow( pPyObj_
) )
32 throw Error::TypeMismatch();
34 ConvertFromPython_nocheck( pPyObj_
, Dest_
);
37 static PyObject
* ConvertToPython( T Value_
)
39 return PyLong_FromLongLong( Value_
);
43 template< typename T
> struct UnsignedIntegerTypeConverter
: public IntegerTypeConverter
45 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, T
& Dest_
)
47 if( PyInt_Check( pPyObj_
) )
48 Dest_
= PyInt_AS_LONG( pPyObj_
);
50 Dest_
= PyLong_AsUnsignedLongLong( pPyObj_
);
53 static void ConvertFromPython( PyObject
* pPyObj_
, T
& Dest_
)
55 if( !CheckType_nothrow( pPyObj_
) )
56 throw Error::TypeMismatch();
58 ConvertFromPython_nocheck( pPyObj_
, Dest_
);
61 static PyObject
* ConvertToPython( T Value_
)
63 return PyLong_FromUnsignedLongLong( Value_
);
67 template<> struct TypeConverter
< NormalType
, uint8_t > : public UnsignedIntegerTypeConverter
< uint8_t > {};
68 template<> struct TypeConverter
< NormalType
, int8_t > : public SignedIntegerTypeConverter
< int8_t > {};
70 template<> struct TypeConverter
< NormalType
, uint16_t > : public UnsignedIntegerTypeConverter
< uint16_t > {};
71 template<> struct TypeConverter
< NormalType
, int16_t > : public SignedIntegerTypeConverter
< int16_t > {};
73 template<> struct TypeConverter
< NormalType
, uint32_t > : public UnsignedIntegerTypeConverter
< uint32_t > {};
74 template<> struct TypeConverter
< NormalType
, int32_t > : public SignedIntegerTypeConverter
< int32_t > {};
76 template<> struct TypeConverter
< NormalType
, uint64_t > : public UnsignedIntegerTypeConverter
< uint64_t > {};
77 template<> struct TypeConverter
< NormalType
, int64_t > : public SignedIntegerTypeConverter
< int64_t > {};
79 template< typename enum_type
> struct TypeConverter
< EnumType
, enum_type
> :
80 public SignedIntegerTypeConverter
< int32_t >
82 typedef SignedIntegerTypeConverter
< int32_t > base
;
84 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, enum_type
& Dest_
)
87 base::ConvertFromPython_nocheck( pPyObj_
, val
);
88 Dest_
= static_cast< enum_type
>( val
);
91 static void ConvertFromPython( PyObject
* pPyObj_
, enum_type
& Dest_
)
94 base::ConvertFromPython( pPyObj_
, val
);
95 Dest_
= static_cast< enum_type
>( val
);
98 static PyObject
* ConvertToPython( enum_type Value_
)
100 return base::ConvertToPython( Value_
);
105 template<> struct TypeConverter
< NormalType
, float >
107 static bool CheckType_nothrow( PyObject
* pPyObj_
)
109 return !!PyFloat_Check( pPyObj_
);
112 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, float& Dest_
)
114 Dest_
= PyFloat_AS_DOUBLE( pPyObj_
);
117 static void ConvertFromPython( PyObject
* pPyObj_
, float& Dest_
)
119 if( !CheckType_nothrow( pPyObj_
) )
120 throw Error::TypeMismatch();
122 ConvertFromPython_nocheck( pPyObj_
, Dest_
);
125 static PyObject
* ConvertToPython( float Value_
)
127 return PyFloat_FromDouble( Value_
);
132 template<> struct TypeConverter
< NormalType
, bool >
134 static bool CheckType_nothrow( PyObject
* pPyObj_
)
136 return !!PyBool_Check( pPyObj_
);
139 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, bool& Dest_
)
142 // Every single python developer is a fucking brainless eat-shitting moron
143 // "warning: dereferencing type-punned pointer will break strict-aliasing rules"
144 // because those shitty Py_True/Py_False macros do retarded casting, and there is
145 // of course no way to test a boolean value without using these.
147 // And of course, it all comes from the incredibly stupid decision of python
148 // to implement numeric values as objects, and share their instances. So instead of
149 // carrying around a boolean value (1 byte), they lug around a pointer and need to
150 // update reference counters for those numeric values. And they have to be dereferenced
151 // anytime the actual numeric value is needed.
153 // So they make the common use cases slower for the sake of the rare use case
154 // where you need to consider an integer as an object. They could have implemented
155 // native types directly passed around by values, with automatic boxing/unboxing
156 // into an object of the corresponding numeric class when needed, but I guess it's way
157 // too clever for them.
159 // Anyway, if I want my stuff to build without warnings (which I of course do) I can either:
161 // - disable this warning (which I won't because it's useful to avoid
162 // accidentaly writing retarded code, but I guess that if the python
163 // fucktards did this, they wouldn't be able to figure out how to code
166 // - use a pragma to disable this warning just here (non-portable, and it doesn't seem
167 // to work for that particular warning)
169 // - fuck their shitty macros and do it by hand with some workaround, and because
170 // I then don't use the python API properly anymore (funny how in the world of
171 // python, properly means "with a disgusting compilation warning"), things
172 // will probably break down somehow in the future if they decide to break
173 // binary compatilibty.
175 // The gene pool would be so much improved if everyone intentionally choosing
176 // to use python for any purpose whatsoever, as well as anyone having anything
177 // to do with its development would suddenly choke and die.
179 // Option 2 failed, so I'm going for option 3. If you're here because you
180 // have a version of python above 2.5 and it fails to build/work, now you
183 //Dest_ = ( pPyObj_ != Py_True );
184 Dest_
= ( pPyObj_
== static_cast< PyObject
* >( static_cast< void* >( &_Py_TrueStruct
) ) );
187 static void ConvertFromPython( PyObject
* pPyObj_
, bool& Dest_
)
189 if( !CheckType_nothrow( pPyObj_
) )
190 throw Error::TypeMismatch();
192 ConvertFromPython_nocheck( pPyObj_
, Dest_
);
195 static PyObject
* ConvertToPython( const bool& Value_
)
197 return PyBool_FromLong( Value_
);
202 template<> struct TypeConverter
< NormalType
, std::string
>
204 static bool CheckType_nothrow( PyObject
* pPyObj_
)
206 return !!PyString_Check( pPyObj_
);
209 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, std::string
& Dest_
)
211 Dest_
= PyString_AsString( pPyObj_
);
214 static void ConvertFromPython( PyObject
* pPyObj_
, std::string
& Dest_
)
216 if( !CheckType_nothrow( pPyObj_
) )
217 throw Error::TypeMismatch();
219 ConvertFromPython_nocheck( pPyObj_
, Dest_
);
222 static PyObject
* ConvertToPython( const std::string
& Value_
)
224 return PyString_FromString( Value_
.c_str() );
228 // Dummy type converters for all STL container types for now
229 template< typename C
, typename T
> struct TypeConverter
< MonadicType
< C
>, T
>
231 static bool CheckType_nothrow( PyObject
* pPyObj_
) { return false; }
232 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, T
& Dest_
) {}
233 static void ConvertFromPython( PyObject
* pPyObj_
, T
& Dest_
) {}
234 static PyObject
* ConvertToPython( const T
& Value_
) { Py_RETURN_NONE
; }
237 template< typename C1
, typename C2
, typename T
> struct TypeConverter
< DyadicType
< C1
, C2
>, T
>
239 static bool CheckType_nothrow( PyObject
* pPyObj_
) { return false; }
240 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, T
& Dest_
) {}
241 static void ConvertFromPython( PyObject
* pPyObj_
, T
& Dest_
) {}
242 static PyObject
* ConvertToPython( const T
& Value_
) { Py_RETURN_NONE
; }
245 template<> struct TypeConverter
< NormalType
, DynamicBuffer
>
247 static bool CheckType_nothrow( PyObject
* pPyObj_
) { return false; }
248 static void ConvertFromPython_nocheck( PyObject
* pPyObj_
, DynamicBuffer
& Dest_
) {}
249 static void ConvertFromPython( PyObject
* pPyObj_
, DynamicBuffer
& Dest_
) {}
250 static PyObject
* ConvertToPython( const DynamicBuffer
& Value_
) { Py_RETURN_NONE
; }
253 // TODO: all other types