PageRenderTime 59ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/external/pycxx/CXX/ExtensionOldType.hxx

https://github.com/worldforge/cyphesis
C++ Header | 398 lines | 259 code | 65 blank | 74 comment | 27 complexity | 772cb88b135165f1c0c977178111cb52 MD5 | raw file
  1. //-----------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1998 - 2007, The Regents of the University of California
  4. // Produced at the Lawrence Livermore National Laboratory
  5. // All rights reserved.
  6. //
  7. // This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The
  8. // full copyright notice is contained in the file COPYRIGHT located at the root
  9. // of the PyCXX distribution.
  10. //
  11. // Redistribution and use in source and binary forms, with or without
  12. // modification, are permitted provided that the following conditions are met:
  13. //
  14. // - Redistributions of source code must retain the above copyright notice,
  15. // this list of conditions and the disclaimer below.
  16. // - Redistributions in binary form must reproduce the above copyright notice,
  17. // this list of conditions and the disclaimer (as noted below) in the
  18. // documentation and/or materials provided with the distribution.
  19. // - Neither the name of the UC/LLNL nor the names of its contributors may be
  20. // used to endorse or promote products derived from this software without
  21. // specific prior written permission.
  22. //
  23. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF
  27. // CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR
  28. // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  30. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  31. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  34. // DAMAGE.
  35. //
  36. //-----------------------------------------------------------------------------
  37. #ifndef __CXX_ExtensionOldType__h
  38. #define __CXX_ExtensionOldType__h
  39. namespace Py
  40. {
  41. template<TEMPLATE_TYPENAME T> class PythonExtension
  42. : public PythonExtensionBase
  43. {
  44. public:
  45. static PyTypeObject *type_object()
  46. {
  47. return behaviors().type_object();
  48. }
  49. static bool check( PyObject *p )
  50. {
  51. // is p like me?
  52. return p->ob_type == type_object();
  53. }
  54. static bool check( const Object &ob )
  55. {
  56. return check( ob.ptr() );
  57. }
  58. //
  59. // every object needs getattr implemented
  60. // to support methods
  61. //
  62. virtual Object getattr( const char *name )
  63. {
  64. return getattr_methods( name );
  65. }
  66. PyObject *selfPtr()
  67. {
  68. return this;
  69. }
  70. Object self()
  71. {
  72. return asObject( this );
  73. }
  74. protected:
  75. explicit PythonExtension()
  76. : PythonExtensionBase()
  77. {
  78. PyObject_Init( this, type_object() );
  79. // every object must support getattr
  80. behaviors().supportGetattr();
  81. }
  82. virtual ~PythonExtension()
  83. {}
  84. static PythonType &behaviors()
  85. {
  86. static PythonType* p;
  87. if( p == nullptr )
  88. {
  89. #if defined( _CPPRTTI ) || defined( __GNUG__ )
  90. const char *default_name =( typeid( T ) ).name();
  91. #else
  92. const char *default_name = "unknown";
  93. #endif
  94. p = new PythonType( sizeof( T ), 0, default_name );
  95. p->set_tp_dealloc( extension_object_deallocator );
  96. }
  97. return *p;
  98. }
  99. typedef Object (T::*method_noargs_function_t)();
  100. typedef Object (T::*method_varargs_function_t)( const Tuple &args );
  101. typedef Object (T::*method_keyword_function_t)( const Tuple &args, const Dict &kws );
  102. typedef std::map<std::string, MethodDefExt<T> *> method_map_t;
  103. // support the default attributes, __name__, __doc__ and methods
  104. virtual Object getattr_default( const char *_name )
  105. {
  106. std::string name( _name );
  107. if( name == "__name__" && type_object()->tp_name != nullptr )
  108. {
  109. return Py::String( type_object()->tp_name );
  110. }
  111. if( name == "__doc__" && type_object()->tp_doc != nullptr )
  112. {
  113. return Py::String( type_object()->tp_doc );
  114. }
  115. // trying to fake out being a class for help()
  116. // else if( name == "__bases__" )
  117. // {
  118. // return Py::Tuple( 0 );
  119. // }
  120. // else if( name == "__module__" )
  121. // {
  122. // return Py::Nothing();
  123. // }
  124. // else if( name == "__dict__" )
  125. // {
  126. // return Py::Dict();
  127. // }
  128. return getattr_methods( _name );
  129. }
  130. // turn a name into function object
  131. virtual Object getattr_methods( const char *_name )
  132. {
  133. std::string name( _name );
  134. method_map_t &mm = methods();
  135. // see if name exists and get entry with method
  136. EXPLICIT_TYPENAME method_map_t::const_iterator i = mm.find( name );
  137. if( i == mm.end() )
  138. {
  139. if( name == "__methods__" )
  140. {
  141. List methods;
  142. i = mm.begin();
  143. EXPLICIT_TYPENAME method_map_t::const_iterator i_end = mm.end();
  144. for( ; i != i_end; ++i )
  145. methods.append( String( (*i).first ) );
  146. return methods;
  147. }
  148. throw AttributeError( name );
  149. }
  150. MethodDefExt<T> *method_def = i->second;
  151. Tuple self( 2 );
  152. self[0] = Object( this );
  153. self[1] = Object( PyCapsule_New( method_def, nullptr, nullptr ), true );
  154. PyObject *func = PyCFunction_NewEx( &method_def->ext_meth_def, self.ptr(), nullptr );
  155. return Object(func, true);
  156. }
  157. // check that all methods added are unique
  158. static void check_unique_method_name( const char *name )
  159. {
  160. method_map_t &mm = methods();
  161. EXPLICIT_TYPENAME method_map_t::const_iterator i;
  162. i = mm.find( name );
  163. if( i != mm.end() )
  164. throw AttributeError( name );
  165. }
  166. static void add_noargs_method( const char *name, method_noargs_function_t function, const char *doc="" )
  167. {
  168. check_unique_method_name( name );
  169. method_map_t &mm = methods();
  170. mm[ std::string( name ) ] = new MethodDefExt<T>( name, function, method_noargs_call_handler, doc );
  171. }
  172. static void add_varargs_method( const char *name, method_varargs_function_t function, const char *doc="" )
  173. {
  174. check_unique_method_name( name );
  175. method_map_t &mm = methods();
  176. mm[ std::string( name ) ] = new MethodDefExt<T>( name, function, method_varargs_call_handler, doc );
  177. }
  178. static void add_keyword_method( const char *name, method_keyword_function_t function, const char *doc="" )
  179. {
  180. check_unique_method_name( name );
  181. method_map_t &mm = methods();
  182. mm[ std::string( name ) ] = new MethodDefExt<T>( name, function, method_keyword_call_handler, doc );
  183. }
  184. private:
  185. static method_map_t &methods( void )
  186. {
  187. static method_map_t *map_of_methods = nullptr;
  188. if( map_of_methods == nullptr )
  189. map_of_methods = new method_map_t;
  190. return *map_of_methods;
  191. }
  192. // Note: Python calls noargs as varargs buts args==nullptr
  193. static PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, PyObject * )
  194. {
  195. try
  196. {
  197. Tuple self_and_name_tuple( _self_and_name_tuple );
  198. PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
  199. T *self = static_cast<T *>( self_in_cobject );
  200. MethodDefExt<T> *meth_def = reinterpret_cast<MethodDefExt<T> *>(
  201. PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), nullptr ) );
  202. Object result;
  203. // Adding try & catch in case of STL debug-mode exceptions.
  204. #ifdef _STLP_DEBUG
  205. try
  206. {
  207. result = (self->*meth_def->ext_noargs_function)();
  208. }
  209. catch( std::__stl_debug_exception )
  210. {
  211. // throw cxx::RuntimeError( sErrMsg );
  212. throw RuntimeError( "Error message not set yet." );
  213. }
  214. #else
  215. result = (self->*meth_def->ext_noargs_function)();
  216. #endif // _STLP_DEBUG
  217. return new_reference_to( result.ptr() );
  218. }
  219. catch( BaseException & )
  220. {
  221. return 0;
  222. }
  223. }
  224. static PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args )
  225. {
  226. try
  227. {
  228. Tuple self_and_name_tuple( _self_and_name_tuple );
  229. PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
  230. T *self = static_cast<T *>( self_in_cobject );
  231. MethodDefExt<T> *meth_def = reinterpret_cast<MethodDefExt<T> *>(
  232. PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), nullptr ) );
  233. Tuple args( _args );
  234. Object result;
  235. // Adding try & catch in case of STL debug-mode exceptions.
  236. #ifdef _STLP_DEBUG
  237. try
  238. {
  239. result = (self->*meth_def->ext_varargs_function)( args );
  240. }
  241. catch( std::__stl_debug_exception )
  242. {
  243. throw RuntimeError( "Error message not set yet." );
  244. }
  245. #else
  246. result = (self->*meth_def->ext_varargs_function)( args );
  247. #endif // _STLP_DEBUG
  248. return new_reference_to( result.ptr() );
  249. }
  250. catch( BaseException & )
  251. {
  252. return 0;
  253. }
  254. }
  255. static PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords )
  256. {
  257. try
  258. {
  259. Tuple self_and_name_tuple( _self_and_name_tuple );
  260. PyObject *self_in_cobject = self_and_name_tuple[0].ptr();
  261. T *self = static_cast<T *>( self_in_cobject );
  262. MethodDefExt<T> *meth_def = reinterpret_cast<MethodDefExt<T> *>(
  263. PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), nullptr ) );
  264. Tuple args( _args );
  265. // _keywords may be nullptr so be careful about the way the dict is created
  266. Dict keywords;
  267. if( _keywords != nullptr )
  268. keywords = Dict( _keywords );
  269. Object result( ( self->*meth_def->ext_keyword_function )( args, keywords ) );
  270. return new_reference_to( result.ptr() );
  271. }
  272. catch( BaseException & )
  273. {
  274. return 0;
  275. }
  276. }
  277. static void extension_object_deallocator( PyObject* t )
  278. {
  279. delete (T *)( t );
  280. }
  281. //
  282. // prevent the compiler generating these unwanted functions
  283. //
  284. explicit PythonExtension( const PythonExtension<T> &other );
  285. void operator=( const PythonExtension<T> &rhs );
  286. };
  287. //
  288. // ExtensionObject<T> is an Object that will accept only T's.
  289. //
  290. template<TEMPLATE_TYPENAME T>
  291. class ExtensionObject: public Object
  292. {
  293. public:
  294. explicit ExtensionObject( PyObject *pyob )
  295. : Object( pyob )
  296. {
  297. validate();
  298. }
  299. ExtensionObject( const ExtensionObject<T> &other )
  300. : Object( *other )
  301. {
  302. validate();
  303. }
  304. ExtensionObject( const Object &other )
  305. : Object( *other )
  306. {
  307. validate();
  308. }
  309. ExtensionObject &operator=( const Object &rhs )
  310. {
  311. return( *this = *rhs );
  312. }
  313. ExtensionObject &operator=( PyObject *rhsp )
  314. {
  315. if( ptr() != rhsp )
  316. set( rhsp );
  317. return *this;
  318. }
  319. virtual bool accepts( PyObject *pyob ) const
  320. {
  321. return( pyob && T::check( pyob ) );
  322. }
  323. //
  324. // Obtain a pointer to the PythonExtension object
  325. //
  326. T *extensionObject( void )
  327. {
  328. return static_cast<T *>( ptr() );
  329. }
  330. };
  331. } // Namespace Py
  332. // End of __CXX_ExtensionOldType__h
  333. #endif