1# 2# Tables describing slots in the CPython type object 3# and associated know-how. 4# 5 6from __future__ import absolute_import 7 8from . import Naming 9from . import PyrexTypes 10from .Errors import error 11 12invisible = ['__cinit__', '__dealloc__', '__richcmp__', 13 '__nonzero__', '__bool__'] 14 15richcmp_special_methods = ['__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'] 16 17 18class Signature(object): 19 # Method slot signature descriptor. 20 # 21 # has_dummy_arg boolean 22 # has_generic_args boolean 23 # fixed_arg_format string 24 # ret_format string 25 # error_value string 26 # 27 # The formats are strings made up of the following 28 # characters: 29 # 30 # 'O' Python object 31 # 'T' Python object of the type of 'self' 32 # 'v' void 33 # 'p' void * 34 # 'P' void ** 35 # 'i' int 36 # 'b' bint 37 # 'I' int * 38 # 'l' long 39 # 'f' float 40 # 'd' double 41 # 'h' Py_hash_t 42 # 'z' Py_ssize_t 43 # 'Z' Py_ssize_t * 44 # 's' char * 45 # 'S' char ** 46 # 'r' int used only to signal exception 47 # 'B' Py_buffer * 48 # '-' dummy 'self' argument (not used) 49 # '*' rest of args passed as generic Python 50 # arg tuple and kw dict (must be last 51 # char in format string) 52 53 format_map = { 54 'O': PyrexTypes.py_object_type, 55 'v': PyrexTypes.c_void_type, 56 'p': PyrexTypes.c_void_ptr_type, 57 'P': PyrexTypes.c_void_ptr_ptr_type, 58 'i': PyrexTypes.c_int_type, 59 'b': PyrexTypes.c_bint_type, 60 'I': PyrexTypes.c_int_ptr_type, 61 'l': PyrexTypes.c_long_type, 62 'f': PyrexTypes.c_float_type, 63 'd': PyrexTypes.c_double_type, 64 'h': PyrexTypes.c_py_hash_t_type, 65 'z': PyrexTypes.c_py_ssize_t_type, 66 'Z': PyrexTypes.c_py_ssize_t_ptr_type, 67 's': PyrexTypes.c_char_ptr_type, 68 'S': PyrexTypes.c_char_ptr_ptr_type, 69 'r': PyrexTypes.c_returncode_type, 70 'B': PyrexTypes.c_py_buffer_ptr_type, 71 # 'T', '-' and '*' are handled otherwise 72 # and are not looked up in here 73 } 74 75 type_to_format_map = dict( 76 (type_, format_) for format_, type_ in format_map.items()) 77 78 error_value_map = { 79 'O': "NULL", 80 'T': "NULL", 81 'i': "-1", 82 'b': "-1", 83 'l': "-1", 84 'r': "-1", 85 'h': "-1", 86 'z': "-1", 87 } 88 89 def __init__(self, arg_format, ret_format): 90 self.has_dummy_arg = 0 91 self.has_generic_args = 0 92 if arg_format[:1] == '-': 93 self.has_dummy_arg = 1 94 arg_format = arg_format[1:] 95 if arg_format[-1:] == '*': 96 self.has_generic_args = 1 97 arg_format = arg_format[:-1] 98 self.fixed_arg_format = arg_format 99 self.ret_format = ret_format 100 self.error_value = self.error_value_map.get(ret_format, None) 101 self.exception_check = ret_format != 'r' and self.error_value is not None 102 self.is_staticmethod = False 103 104 def __repr__(self): 105 return '<Signature[%s(%s%s)]>' % ( 106 self.ret_format, 107 ', '.join(self.fixed_arg_format), 108 '*' if self.has_generic_args else '') 109 110 def num_fixed_args(self): 111 return len(self.fixed_arg_format) 112 113 def is_self_arg(self, i): 114 # argument is 'self' for methods or 'class' for classmethods 115 return self.fixed_arg_format[i] == 'T' 116 117 def returns_self_type(self): 118 # return type is same as 'self' argument type 119 return self.ret_format == 'T' 120 121 def fixed_arg_type(self, i): 122 return self.format_map[self.fixed_arg_format[i]] 123 124 def return_type(self): 125 return self.format_map[self.ret_format] 126 127 def format_from_type(self, arg_type): 128 if arg_type.is_pyobject: 129 arg_type = PyrexTypes.py_object_type 130 return self.type_to_format_map[arg_type] 131 132 def exception_value(self): 133 return self.error_value_map.get(self.ret_format) 134 135 def function_type(self, self_arg_override=None): 136 # Construct a C function type descriptor for this signature 137 args = [] 138 for i in range(self.num_fixed_args()): 139 if self_arg_override is not None and self.is_self_arg(i): 140 assert isinstance(self_arg_override, PyrexTypes.CFuncTypeArg) 141 args.append(self_arg_override) 142 else: 143 arg_type = self.fixed_arg_type(i) 144 args.append(PyrexTypes.CFuncTypeArg("", arg_type, None)) 145 if self_arg_override is not None and self.returns_self_type(): 146 ret_type = self_arg_override.type 147 else: 148 ret_type = self.return_type() 149 exc_value = self.exception_value() 150 return PyrexTypes.CFuncType( 151 ret_type, args, exception_value=exc_value, 152 exception_check=self.exception_check) 153 154 def method_flags(self): 155 if self.ret_format == "O": 156 full_args = self.fixed_arg_format 157 if self.has_dummy_arg: 158 full_args = "O" + full_args 159 if full_args in ["O", "T"]: 160 if self.has_generic_args: 161 return [method_varargs, method_keywords] 162 else: 163 return [method_noargs] 164 elif full_args in ["OO", "TO"] and not self.has_generic_args: 165 return [method_onearg] 166 167 if self.is_staticmethod: 168 return [method_varargs, method_keywords] 169 return None 170 171 172class SlotDescriptor(object): 173 # Abstract base class for type slot descriptors. 174 # 175 # slot_name string Member name of the slot in the type object 176 # is_initialised_dynamically Is initialised by code in the module init function 177 # is_inherited Is inherited by subtypes (see PyType_Ready()) 178 # py3 Indicates presence of slot in Python 3 179 # py2 Indicates presence of slot in Python 2 180 # ifdef Full #ifdef string that slot is wrapped in. Using this causes py3, py2 and flags to be ignored.) 181 182 def __init__(self, slot_name, dynamic=False, inherited=False, 183 py3=True, py2=True, ifdef=None): 184 self.slot_name = slot_name 185 self.is_initialised_dynamically = dynamic 186 self.is_inherited = inherited 187 self.ifdef = ifdef 188 self.py3 = py3 189 self.py2 = py2 190 191 def preprocessor_guard_code(self): 192 ifdef = self.ifdef 193 py2 = self.py2 194 py3 = self.py3 195 guard = None 196 if ifdef: 197 guard = ("#if %s" % ifdef) 198 elif not py3 or py3 == '<RESERVED>': 199 guard = ("#if PY_MAJOR_VERSION < 3") 200 elif not py2: 201 guard = ("#if PY_MAJOR_VERSION >= 3") 202 return guard 203 204 def generate(self, scope, code): 205 preprocessor_guard = self.preprocessor_guard_code() 206 if preprocessor_guard: 207 code.putln(preprocessor_guard) 208 209 end_pypy_guard = False 210 if self.is_initialised_dynamically: 211 value = "0" 212 else: 213 value = self.slot_code(scope) 214 if value == "0" and self.is_inherited: 215 # PyPy currently has a broken PyType_Ready() that fails to 216 # inherit some slots. To work around this, we explicitly 217 # set inherited slots here, but only in PyPy since CPython 218 # handles this better than we do. 219 inherited_value = value 220 current_scope = scope 221 while (inherited_value == "0" 222 and current_scope.parent_type 223 and current_scope.parent_type.base_type 224 and current_scope.parent_type.base_type.scope): 225 current_scope = current_scope.parent_type.base_type.scope 226 inherited_value = self.slot_code(current_scope) 227 if inherited_value != "0": 228 code.putln("#if CYTHON_COMPILING_IN_PYPY") 229 code.putln("%s, /*%s*/" % (inherited_value, self.slot_name)) 230 code.putln("#else") 231 end_pypy_guard = True 232 233 code.putln("%s, /*%s*/" % (value, self.slot_name)) 234 235 if end_pypy_guard: 236 code.putln("#endif") 237 238 if self.py3 == '<RESERVED>': 239 code.putln("#else") 240 code.putln("0, /*reserved*/") 241 if preprocessor_guard: 242 code.putln("#endif") 243 244 # Some C implementations have trouble statically 245 # initialising a global with a pointer to an extern 246 # function, so we initialise some of the type slots 247 # in the module init function instead. 248 249 def generate_dynamic_init_code(self, scope, code): 250 if self.is_initialised_dynamically: 251 value = self.slot_code(scope) 252 if value != "0": 253 code.putln("%s.%s = %s;" % ( 254 scope.parent_type.typeobj_cname, 255 self.slot_name, 256 value 257 ) 258 ) 259 260 261class FixedSlot(SlotDescriptor): 262 # Descriptor for a type slot with a fixed value. 263 # 264 # value string 265 266 def __init__(self, slot_name, value, py3=True, py2=True, ifdef=None): 267 SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, ifdef=ifdef) 268 self.value = value 269 270 def slot_code(self, scope): 271 return self.value 272 273 274class EmptySlot(FixedSlot): 275 # Descriptor for a type slot whose value is always 0. 276 277 def __init__(self, slot_name, py3=True, py2=True, ifdef=None): 278 FixedSlot.__init__(self, slot_name, "0", py3=py3, py2=py2, ifdef=ifdef) 279 280 281class MethodSlot(SlotDescriptor): 282 # Type slot descriptor for a user-definable method. 283 # 284 # signature Signature 285 # method_name string The __xxx__ name of the method 286 # alternatives [string] Alternative list of __xxx__ names for the method 287 288 def __init__(self, signature, slot_name, method_name, fallback=None, 289 py3=True, py2=True, ifdef=None, inherited=True): 290 SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, 291 ifdef=ifdef, inherited=inherited) 292 self.signature = signature 293 self.slot_name = slot_name 294 self.method_name = method_name 295 self.alternatives = [] 296 method_name_to_slot[method_name] = self 297 # 298 if fallback: 299 self.alternatives.append(fallback) 300 for alt in (self.py2, self.py3): 301 if isinstance(alt, (tuple, list)): 302 slot_name, method_name = alt 303 self.alternatives.append(method_name) 304 method_name_to_slot[method_name] = self 305 306 def slot_code(self, scope): 307 entry = scope.lookup_here(self.method_name) 308 if entry and entry.is_special and entry.func_cname: 309 return entry.func_cname 310 for method_name in self.alternatives: 311 entry = scope.lookup_here(method_name) 312 if entry and entry.is_special and entry.func_cname: 313 return entry.func_cname 314 return "0" 315 316 317class InternalMethodSlot(SlotDescriptor): 318 # Type slot descriptor for a method which is always 319 # synthesized by Cython. 320 # 321 # slot_name string Member name of the slot in the type object 322 323 def __init__(self, slot_name, **kargs): 324 SlotDescriptor.__init__(self, slot_name, **kargs) 325 326 def slot_code(self, scope): 327 return scope.mangle_internal(self.slot_name) 328 329 330class GCDependentSlot(InternalMethodSlot): 331 # Descriptor for a slot whose value depends on whether 332 # the type participates in GC. 333 334 def __init__(self, slot_name, **kargs): 335 InternalMethodSlot.__init__(self, slot_name, **kargs) 336 337 def slot_code(self, scope): 338 if not scope.needs_gc(): 339 return "0" 340 if not scope.has_cyclic_pyobject_attrs: 341 # if the type does not have GC relevant object attributes, it can 342 # delegate GC methods to its parent - iff the parent functions 343 # are defined in the same module 344 parent_type_scope = scope.parent_type.base_type.scope 345 if scope.parent_scope is parent_type_scope.parent_scope: 346 entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) 347 if entry.visibility != 'extern': 348 return self.slot_code(parent_type_scope) 349 return InternalMethodSlot.slot_code(self, scope) 350 351 352class GCClearReferencesSlot(GCDependentSlot): 353 354 def slot_code(self, scope): 355 if scope.needs_tp_clear(): 356 return GCDependentSlot.slot_code(self, scope) 357 return "0" 358 359 360class ConstructorSlot(InternalMethodSlot): 361 # Descriptor for tp_new and tp_dealloc. 362 363 def __init__(self, slot_name, method, **kargs): 364 InternalMethodSlot.__init__(self, slot_name, **kargs) 365 self.method = method 366 367 def slot_code(self, scope): 368 entry = scope.lookup_here(self.method) 369 if (self.slot_name != 'tp_new' 370 and scope.parent_type.base_type 371 and not scope.has_pyobject_attrs 372 and not scope.has_memoryview_attrs 373 and not scope.has_cpp_class_attrs 374 and not (entry and entry.is_special)): 375 # if the type does not have object attributes, it can 376 # delegate GC methods to its parent - iff the parent 377 # functions are defined in the same module 378 parent_type_scope = scope.parent_type.base_type.scope 379 if scope.parent_scope is parent_type_scope.parent_scope: 380 entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) 381 if entry.visibility != 'extern': 382 return self.slot_code(parent_type_scope) 383 if entry and not entry.is_special: 384 return "0" 385 return InternalMethodSlot.slot_code(self, scope) 386 387 388class SyntheticSlot(InternalMethodSlot): 389 # Type slot descriptor for a synthesized method which 390 # dispatches to one or more user-defined methods depending 391 # on its arguments. If none of the relevant methods are 392 # defined, the method will not be synthesized and an 393 # alternative default value will be placed in the type 394 # slot. 395 396 def __init__(self, slot_name, user_methods, default_value, **kargs): 397 InternalMethodSlot.__init__(self, slot_name, **kargs) 398 self.user_methods = user_methods 399 self.default_value = default_value 400 401 def slot_code(self, scope): 402 if scope.defines_any_special(self.user_methods): 403 return InternalMethodSlot.slot_code(self, scope) 404 else: 405 return self.default_value 406 407 408class RichcmpSlot(MethodSlot): 409 def slot_code(self, scope): 410 entry = scope.lookup_here(self.method_name) 411 if entry and entry.is_special and entry.func_cname: 412 return entry.func_cname 413 elif scope.defines_any_special(richcmp_special_methods): 414 return scope.mangle_internal(self.slot_name) 415 else: 416 return "0" 417 418 419class TypeFlagsSlot(SlotDescriptor): 420 # Descriptor for the type flags slot. 421 422 def slot_code(self, scope): 423 value = "Py_TPFLAGS_DEFAULT" 424 if scope.directives['type_version_tag']: 425 # it's not in 'Py_TPFLAGS_DEFAULT' in Py2 426 value += "|Py_TPFLAGS_HAVE_VERSION_TAG" 427 else: 428 # it's enabled in 'Py_TPFLAGS_DEFAULT' in Py3 429 value = "(%s&~Py_TPFLAGS_HAVE_VERSION_TAG)" % value 430 value += "|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER" 431 if not scope.parent_type.is_final_type: 432 value += "|Py_TPFLAGS_BASETYPE" 433 if scope.needs_gc(): 434 value += "|Py_TPFLAGS_HAVE_GC" 435 return value 436 437 438class DocStringSlot(SlotDescriptor): 439 # Descriptor for the docstring slot. 440 441 def slot_code(self, scope): 442 doc = scope.doc 443 if doc is None: 444 return "0" 445 if doc.is_unicode: 446 doc = doc.as_utf8_string() 447 return doc.as_c_string_literal() 448 449 450class SuiteSlot(SlotDescriptor): 451 # Descriptor for a substructure of the type object. 452 # 453 # sub_slots [SlotDescriptor] 454 455 def __init__(self, sub_slots, slot_type, slot_name, ifdef=None): 456 SlotDescriptor.__init__(self, slot_name, ifdef=ifdef) 457 self.sub_slots = sub_slots 458 self.slot_type = slot_type 459 substructures.append(self) 460 461 def is_empty(self, scope): 462 for slot in self.sub_slots: 463 if slot.slot_code(scope) != "0": 464 return False 465 return True 466 467 def substructure_cname(self, scope): 468 return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name) 469 470 def slot_code(self, scope): 471 if not self.is_empty(scope): 472 return "&%s" % self.substructure_cname(scope) 473 return "0" 474 475 def generate_substructure(self, scope, code): 476 if not self.is_empty(scope): 477 code.putln("") 478 if self.ifdef: 479 code.putln("#if %s" % self.ifdef) 480 code.putln( 481 "static %s %s = {" % ( 482 self.slot_type, 483 self.substructure_cname(scope))) 484 for slot in self.sub_slots: 485 slot.generate(scope, code) 486 code.putln("};") 487 if self.ifdef: 488 code.putln("#endif") 489 490substructures = [] # List of all SuiteSlot instances 491 492class MethodTableSlot(SlotDescriptor): 493 # Slot descriptor for the method table. 494 495 def slot_code(self, scope): 496 if scope.pyfunc_entries: 497 return scope.method_table_cname 498 else: 499 return "0" 500 501 502class MemberTableSlot(SlotDescriptor): 503 # Slot descriptor for the table of Python-accessible attributes. 504 505 def slot_code(self, scope): 506 return "0" 507 508 509class GetSetSlot(SlotDescriptor): 510 # Slot descriptor for the table of attribute get & set methods. 511 512 def slot_code(self, scope): 513 if scope.property_entries: 514 return scope.getset_table_cname 515 else: 516 return "0" 517 518 519class BaseClassSlot(SlotDescriptor): 520 # Slot descriptor for the base class slot. 521 522 def __init__(self, name): 523 SlotDescriptor.__init__(self, name, dynamic = 1) 524 525 def generate_dynamic_init_code(self, scope, code): 526 base_type = scope.parent_type.base_type 527 if base_type: 528 code.putln("%s.%s = %s;" % ( 529 scope.parent_type.typeobj_cname, 530 self.slot_name, 531 base_type.typeptr_cname)) 532 533 534class DictOffsetSlot(SlotDescriptor): 535 # Slot descriptor for a class' dict offset, for dynamic attributes. 536 537 def slot_code(self, scope): 538 dict_entry = scope.lookup_here("__dict__") if not scope.is_closure_class_scope else None 539 if dict_entry and dict_entry.is_variable: 540 if getattr(dict_entry.type, 'cname', None) != 'PyDict_Type': 541 error(dict_entry.pos, "__dict__ slot must be of type 'dict'") 542 return "0" 543 type = scope.parent_type 544 if type.typedef_flag: 545 objstruct = type.objstruct_cname 546 else: 547 objstruct = "struct %s" % type.objstruct_cname 548 return ("offsetof(%s, %s)" % ( 549 objstruct, 550 dict_entry.cname)) 551 else: 552 return "0" 553 554 555# The following dictionary maps __xxx__ method names to slot descriptors. 556 557method_name_to_slot = {} 558 559## The following slots are (or could be) initialised with an 560## extern function pointer. 561# 562#slots_initialised_from_extern = ( 563# "tp_free", 564#) 565 566#------------------------------------------------------------------------------------------ 567# 568# Utility functions for accessing slot table data structures 569# 570#------------------------------------------------------------------------------------------ 571 572def get_special_method_signature(name): 573 # Given a method name, if it is a special method, 574 # return its signature, else return None. 575 slot = method_name_to_slot.get(name) 576 if slot: 577 return slot.signature 578 elif name in richcmp_special_methods: 579 return ibinaryfunc 580 else: 581 return None 582 583 584def get_property_accessor_signature(name): 585 # Return signature of accessor for an extension type 586 # property, else None. 587 return property_accessor_signatures.get(name) 588 589 590def get_base_slot_function(scope, slot): 591 # Returns the function implementing this slot in the baseclass. 592 # This is useful for enabling the compiler to optimize calls 593 # that recursively climb the class hierarchy. 594 base_type = scope.parent_type.base_type 595 if scope.parent_scope is base_type.scope.parent_scope: 596 parent_slot = slot.slot_code(base_type.scope) 597 if parent_slot != '0': 598 entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) 599 if entry.visibility != 'extern': 600 return parent_slot 601 return None 602 603 604def get_slot_function(scope, slot): 605 # Returns the function implementing this slot in the baseclass. 606 # This is useful for enabling the compiler to optimize calls 607 # that recursively climb the class hierarchy. 608 slot_code = slot.slot_code(scope) 609 if slot_code != '0': 610 entry = scope.parent_scope.lookup_here(scope.parent_type.name) 611 if entry.visibility != 'extern': 612 return slot_code 613 return None 614 615 616def get_slot_by_name(slot_name): 617 # For now, only search the type struct, no referenced sub-structs. 618 for slot in slot_table: 619 if slot.slot_name == slot_name: 620 return slot 621 assert False, "Slot not found: %s" % slot_name 622 623 624def get_slot_code_by_name(scope, slot_name): 625 slot = get_slot_by_name(slot_name) 626 return slot.slot_code(scope) 627 628 629#------------------------------------------------------------------------------------------ 630# 631# Signatures for generic Python functions and methods. 632# 633#------------------------------------------------------------------------------------------ 634 635pyfunction_signature = Signature("-*", "O") 636pymethod_signature = Signature("T*", "O") 637 638#------------------------------------------------------------------------------------------ 639# 640# Signatures for simple Python functions. 641# 642#------------------------------------------------------------------------------------------ 643 644pyfunction_noargs = Signature("-", "O") 645pyfunction_onearg = Signature("-O", "O") 646 647#------------------------------------------------------------------------------------------ 648# 649# Signatures for the various kinds of function that 650# can appear in the type object and its substructures. 651# 652#------------------------------------------------------------------------------------------ 653 654unaryfunc = Signature("T", "O") # typedef PyObject * (*unaryfunc)(PyObject *); 655binaryfunc = Signature("OO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); 656ibinaryfunc = Signature("TO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); 657ternaryfunc = Signature("OOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); 658iternaryfunc = Signature("TOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); 659callfunc = Signature("T*", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); 660inquiry = Signature("T", "i") # typedef int (*inquiry)(PyObject *); 661lenfunc = Signature("T", "z") # typedef Py_ssize_t (*lenfunc)(PyObject *); 662 663 # typedef int (*coercion)(PyObject **, PyObject **); 664intargfunc = Signature("Ti", "O") # typedef PyObject *(*intargfunc)(PyObject *, int); 665ssizeargfunc = Signature("Tz", "O") # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t); 666intintargfunc = Signature("Tii", "O") # typedef PyObject *(*intintargfunc)(PyObject *, int, int); 667ssizessizeargfunc = Signature("Tzz", "O") # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t); 668intobjargproc = Signature("TiO", 'r') # typedef int(*intobjargproc)(PyObject *, int, PyObject *); 669ssizeobjargproc = Signature("TzO", 'r') # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *); 670intintobjargproc = Signature("TiiO", 'r') # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *); 671ssizessizeobjargproc = Signature("TzzO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); 672 673intintargproc = Signature("Tii", 'r') 674ssizessizeargproc = Signature("Tzz", 'r') 675objargfunc = Signature("TO", "O") 676objobjargproc = Signature("TOO", 'r') # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *); 677readbufferproc = Signature("TzP", "z") # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **); 678writebufferproc = Signature("TzP", "z") # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **); 679segcountproc = Signature("TZ", "z") # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *); 680charbufferproc = Signature("TzS", "z") # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **); 681objargproc = Signature("TO", 'r') # typedef int (*objobjproc)(PyObject *, PyObject *); 682 # typedef int (*visitproc)(PyObject *, void *); 683 # typedef int (*traverseproc)(PyObject *, visitproc, void *); 684 685destructor = Signature("T", "v") # typedef void (*destructor)(PyObject *); 686# printfunc = Signature("TFi", 'r') # typedef int (*printfunc)(PyObject *, FILE *, int); 687 # typedef PyObject *(*getattrfunc)(PyObject *, char *); 688getattrofunc = Signature("TO", "O") # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *); 689 # typedef int (*setattrfunc)(PyObject *, char *, PyObject *); 690setattrofunc = Signature("TOO", 'r') # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *); 691delattrofunc = Signature("TO", 'r') 692cmpfunc = Signature("TO", "i") # typedef int (*cmpfunc)(PyObject *, PyObject *); 693reprfunc = Signature("T", "O") # typedef PyObject *(*reprfunc)(PyObject *); 694hashfunc = Signature("T", "h") # typedef Py_hash_t (*hashfunc)(PyObject *); 695richcmpfunc = Signature("TOi", "O") # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int); 696getiterfunc = Signature("T", "O") # typedef PyObject *(*getiterfunc) (PyObject *); 697iternextfunc = Signature("T", "O") # typedef PyObject *(*iternextfunc) (PyObject *); 698descrgetfunc = Signature("TOO", "O") # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *); 699descrsetfunc = Signature("TOO", 'r') # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *); 700descrdelfunc = Signature("TO", 'r') 701initproc = Signature("T*", 'r') # typedef int (*initproc)(PyObject *, PyObject *, PyObject *); 702 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); 703 # typedef PyObject *(*allocfunc)(struct _typeobject *, int); 704 705getbufferproc = Signature("TBi", "r") # typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); 706releasebufferproc = Signature("TB", "v") # typedef void (*releasebufferproc)(PyObject *, Py_buffer *); 707 708 709#------------------------------------------------------------------------------------------ 710# 711# Signatures for accessor methods of properties. 712# 713#------------------------------------------------------------------------------------------ 714 715property_accessor_signatures = { 716 '__get__': Signature("T", "O"), 717 '__set__': Signature("TO", 'r'), 718 '__del__': Signature("T", 'r') 719} 720 721#------------------------------------------------------------------------------------------ 722# 723# Descriptor tables for the slots of the various type object 724# substructures, in the order they appear in the structure. 725# 726#------------------------------------------------------------------------------------------ 727 728PyNumberMethods_Py3_GUARD = "PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000)" 729 730PyNumberMethods = ( 731 MethodSlot(binaryfunc, "nb_add", "__add__"), 732 MethodSlot(binaryfunc, "nb_subtract", "__sub__"), 733 MethodSlot(binaryfunc, "nb_multiply", "__mul__"), 734 MethodSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD), 735 MethodSlot(binaryfunc, "nb_remainder", "__mod__"), 736 MethodSlot(binaryfunc, "nb_divmod", "__divmod__"), 737 MethodSlot(ternaryfunc, "nb_power", "__pow__"), 738 MethodSlot(unaryfunc, "nb_negative", "__neg__"), 739 MethodSlot(unaryfunc, "nb_positive", "__pos__"), 740 MethodSlot(unaryfunc, "nb_absolute", "__abs__"), 741 MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")), 742 MethodSlot(unaryfunc, "nb_invert", "__invert__"), 743 MethodSlot(binaryfunc, "nb_lshift", "__lshift__"), 744 MethodSlot(binaryfunc, "nb_rshift", "__rshift__"), 745 MethodSlot(binaryfunc, "nb_and", "__and__"), 746 MethodSlot(binaryfunc, "nb_xor", "__xor__"), 747 MethodSlot(binaryfunc, "nb_or", "__or__"), 748 EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD), 749 MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"), 750 MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"), 751 MethodSlot(unaryfunc, "nb_float", "__float__"), 752 MethodSlot(unaryfunc, "nb_oct", "__oct__", ifdef = PyNumberMethods_Py3_GUARD), 753 MethodSlot(unaryfunc, "nb_hex", "__hex__", ifdef = PyNumberMethods_Py3_GUARD), 754 755 # Added in release 2.0 756 MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"), 757 MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"), 758 MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"), 759 MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", ifdef = PyNumberMethods_Py3_GUARD), 760 MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"), 761 MethodSlot(ibinaryfunc, "nb_inplace_power", "__ipow__"), # actually ternaryfunc!!! 762 MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"), 763 MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__"), 764 MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__"), 765 MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__"), 766 MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__"), 767 768 # Added in release 2.2 769 # The following require the Py_TPFLAGS_HAVE_CLASS flag 770 MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"), 771 MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"), 772 MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"), 773 MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"), 774 775 # Added in release 2.5 776 MethodSlot(unaryfunc, "nb_index", "__index__"), 777 778 # Added in release 3.5 779 MethodSlot(binaryfunc, "nb_matrix_multiply", "__matmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), 780 MethodSlot(ibinaryfunc, "nb_inplace_matrix_multiply", "__imatmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), 781) 782 783PySequenceMethods = ( 784 MethodSlot(lenfunc, "sq_length", "__len__"), 785 EmptySlot("sq_concat"), # nb_add used instead 786 EmptySlot("sq_repeat"), # nb_multiply used instead 787 SyntheticSlot("sq_item", ["__getitem__"], "0"), #EmptySlot("sq_item"), # mp_subscript used instead 788 MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__"), 789 EmptySlot("sq_ass_item"), # mp_ass_subscript used instead 790 SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"), 791 MethodSlot(cmpfunc, "sq_contains", "__contains__"), 792 EmptySlot("sq_inplace_concat"), # nb_inplace_add used instead 793 EmptySlot("sq_inplace_repeat"), # nb_inplace_multiply used instead 794) 795 796PyMappingMethods = ( 797 MethodSlot(lenfunc, "mp_length", "__len__"), 798 MethodSlot(objargfunc, "mp_subscript", "__getitem__"), 799 SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"), 800) 801 802PyBufferProcs = ( 803 MethodSlot(readbufferproc, "bf_getreadbuffer", "__getreadbuffer__", py3 = False), 804 MethodSlot(writebufferproc, "bf_getwritebuffer", "__getwritebuffer__", py3 = False), 805 MethodSlot(segcountproc, "bf_getsegcount", "__getsegcount__", py3 = False), 806 MethodSlot(charbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3 = False), 807 808 MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__"), 809 MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__") 810) 811 812PyAsyncMethods = ( 813 MethodSlot(unaryfunc, "am_await", "__await__"), 814 MethodSlot(unaryfunc, "am_aiter", "__aiter__"), 815 MethodSlot(unaryfunc, "am_anext", "__anext__"), 816) 817 818#------------------------------------------------------------------------------------------ 819# 820# The main slot table. This table contains descriptors for all the 821# top-level type slots, beginning with tp_dealloc, in the order they 822# appear in the type object. 823# 824#------------------------------------------------------------------------------------------ 825 826slot_table = ( 827 ConstructorSlot("tp_dealloc", '__dealloc__'), 828 EmptySlot("tp_print", ifdef="PY_VERSION_HEX < 0x030800b4"), 829 EmptySlot("tp_vectorcall_offset", ifdef="PY_VERSION_HEX >= 0x030800b4"), 830 EmptySlot("tp_getattr"), 831 EmptySlot("tp_setattr"), 832 833 # tp_compare (Py2) / tp_reserved (Py3<3.5) / tp_as_async (Py3.5+) is always used as tp_as_async in Py3 834 MethodSlot(cmpfunc, "tp_compare", "__cmp__", ifdef="PY_MAJOR_VERSION < 3"), 835 SuiteSlot(PyAsyncMethods, "__Pyx_PyAsyncMethodsStruct", "tp_as_async", ifdef="PY_MAJOR_VERSION >= 3"), 836 837 MethodSlot(reprfunc, "tp_repr", "__repr__"), 838 839 SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"), 840 SuiteSlot(PySequenceMethods, "PySequenceMethods", "tp_as_sequence"), 841 SuiteSlot(PyMappingMethods, "PyMappingMethods", "tp_as_mapping"), 842 843 MethodSlot(hashfunc, "tp_hash", "__hash__", inherited=False), # Py3 checks for __richcmp__ 844 MethodSlot(callfunc, "tp_call", "__call__"), 845 MethodSlot(reprfunc, "tp_str", "__str__"), 846 847 SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"), #"PyObject_GenericGetAttr"), 848 SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"), 849 850 SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"), 851 852 TypeFlagsSlot("tp_flags"), 853 DocStringSlot("tp_doc"), 854 855 GCDependentSlot("tp_traverse"), 856 GCClearReferencesSlot("tp_clear"), 857 858 RichcmpSlot(richcmpfunc, "tp_richcompare", "__richcmp__", inherited=False), # Py3 checks for __hash__ 859 860 EmptySlot("tp_weaklistoffset"), 861 862 MethodSlot(getiterfunc, "tp_iter", "__iter__"), 863 MethodSlot(iternextfunc, "tp_iternext", "__next__"), 864 865 MethodTableSlot("tp_methods"), 866 MemberTableSlot("tp_members"), 867 GetSetSlot("tp_getset"), 868 869 BaseClassSlot("tp_base"), #EmptySlot("tp_base"), 870 EmptySlot("tp_dict"), 871 872 SyntheticSlot("tp_descr_get", ["__get__"], "0"), 873 SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"), 874 875 DictOffsetSlot("tp_dictoffset"), 876 877 MethodSlot(initproc, "tp_init", "__init__"), 878 EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"), 879 InternalMethodSlot("tp_new"), 880 EmptySlot("tp_free"), 881 882 EmptySlot("tp_is_gc"), 883 EmptySlot("tp_bases"), 884 EmptySlot("tp_mro"), 885 EmptySlot("tp_cache"), 886 EmptySlot("tp_subclasses"), 887 EmptySlot("tp_weaklist"), 888 EmptySlot("tp_del"), 889 EmptySlot("tp_version_tag"), 890 EmptySlot("tp_finalize", ifdef="PY_VERSION_HEX >= 0x030400a1"), 891 EmptySlot("tp_vectorcall", ifdef="PY_VERSION_HEX >= 0x030800b1"), 892 EmptySlot("tp_print", ifdef="PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000"), 893) 894 895#------------------------------------------------------------------------------------------ 896# 897# Descriptors for special methods which don't appear directly 898# in the type object or its substructures. These methods are 899# called from slot functions synthesized by Cython. 900# 901#------------------------------------------------------------------------------------------ 902 903MethodSlot(initproc, "", "__cinit__") 904MethodSlot(destructor, "", "__dealloc__") 905MethodSlot(objobjargproc, "", "__setitem__") 906MethodSlot(objargproc, "", "__delitem__") 907MethodSlot(ssizessizeobjargproc, "", "__setslice__") 908MethodSlot(ssizessizeargproc, "", "__delslice__") 909MethodSlot(getattrofunc, "", "__getattr__") 910MethodSlot(getattrofunc, "", "__getattribute__") 911MethodSlot(setattrofunc, "", "__setattr__") 912MethodSlot(delattrofunc, "", "__delattr__") 913MethodSlot(descrgetfunc, "", "__get__") 914MethodSlot(descrsetfunc, "", "__set__") 915MethodSlot(descrdelfunc, "", "__delete__") 916 917 918# Method flags for python-exposed methods. 919 920method_noargs = "METH_NOARGS" 921method_onearg = "METH_O" 922method_varargs = "METH_VARARGS" 923method_keywords = "METH_KEYWORDS" 924method_coexist = "METH_COEXIST" 925