~gjc/pybindgen/new-waf

« back to all changes in this revision

Viewing changes to pybindgen/cppclass.py

  • Committer: Gustavo J. A. M. Carneiro
  • Date: 2008-11-17 17:38:14 UTC
  • mfrom: (525.1.78 trunk)
  • Revision ID: gjc@gnome.org-20081117173814-6k0ejk3ovblbhla8
merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
 
8
8
from typehandlers.base import ReturnValue, \
9
9
    join_ctype_and_name, CodeGenerationError, \
10
 
    param_type_matcher, return_type_matcher, CodegenErrorBase
 
10
    param_type_matcher, return_type_matcher, CodegenErrorBase, \
 
11
    DeclarationsScope, CodeBlock
11
12
 
12
13
from typehandlers.codesink import NullCodeSink, MemoryCodeSink
13
14
 
15
16
    CppStaticAttributeGetter, CppStaticAttributeSetter, \
16
17
    PyGetSetDef, PyMetaclass
17
18
 
 
19
from pytypeobject import PyTypeObject, PyNumberMethods
 
20
 
18
21
import settings
19
22
import utils
20
23
 
 
24
if 'set' not in dir(__builtins__):
 
25
    from sets import Set as set
 
26
 
21
27
 
22
28
class MemoryPolicy(object):
23
29
    """memory management policy for a C++ class or C/C++ struct"""
373
379
    A CppClass object takes care of generating the code for wrapping a C++ class
374
380
    """
375
381
 
376
 
    TYPE_TMPL = (
377
 
        'PyTypeObject %(typestruct)s = {\n'
378
 
        '    PyObject_HEAD_INIT(NULL)\n'
379
 
        '    0,                                 /* ob_size */\n'
380
 
        '    (char *) "%(tp_name)s",            /* tp_name */\n'
381
 
        '    %(tp_basicsize)s,                  /* tp_basicsize */\n'
382
 
        '    0,                                 /* tp_itemsize */\n'
383
 
        '    /* methods */\n'
384
 
        '    (destructor)%(tp_dealloc)s,        /* tp_dealloc */\n'
385
 
        '    (printfunc)0,                      /* tp_print */\n'
386
 
        '    (getattrfunc)%(tp_getattr)s,       /* tp_getattr */\n'
387
 
        '    (setattrfunc)%(tp_setattr)s,       /* tp_setattr */\n'
388
 
        '    (cmpfunc)%(tp_compare)s,           /* tp_compare */\n'
389
 
        '    (reprfunc)%(tp_repr)s,             /* tp_repr */\n'
390
 
        '    (PyNumberMethods*)%(tp_as_number)s,     /* tp_as_number */\n'
391
 
        '    (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n'
392
 
        '    (PyMappingMethods*)%(tp_as_mapping)s,   /* tp_as_mapping */\n'
393
 
        '    (hashfunc)%(tp_hash)s,             /* tp_hash */\n'
394
 
        '    (ternaryfunc)%(tp_call)s,          /* tp_call */\n'
395
 
        '    (reprfunc)%(tp_str)s,              /* tp_str */\n'
396
 
        '    (getattrofunc)%(tp_getattro)s,     /* tp_getattro */\n'
397
 
        '    (setattrofunc)%(tp_setattro)s,     /* tp_setattro */\n'
398
 
        '    (PyBufferProcs*)%(tp_as_buffer)s,  /* tp_as_buffer */\n'
399
 
        '    %(tp_flags)s,                      /* tp_flags */\n'
400
 
        '    %(tp_doc)s,                        /* Documentation string */\n'
401
 
        '    (traverseproc)%(tp_traverse)s,     /* tp_traverse */\n'
402
 
        '    (inquiry)%(tp_clear)s,             /* tp_clear */\n'
403
 
        '    (richcmpfunc)%(tp_richcompare)s,   /* tp_richcompare */\n'
404
 
        '    %(tp_weaklistoffset)s,             /* tp_weaklistoffset */\n'
405
 
        '    (getiterfunc)%(tp_iter)s,          /* tp_iter */\n'
406
 
        '    (iternextfunc)%(tp_iternext)s,     /* tp_iternext */\n'
407
 
        '    (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n'
408
 
        '    (struct PyMemberDef*)0,              /* tp_members */\n'
409
 
        '    %(tp_getset)s,                     /* tp_getset */\n'
410
 
        '    NULL,                              /* tp_base */\n'
411
 
        '    NULL,                              /* tp_dict */\n'
412
 
        '    (descrgetfunc)%(tp_descr_get)s,    /* tp_descr_get */\n'
413
 
        '    (descrsetfunc)%(tp_descr_set)s,    /* tp_descr_set */\n'
414
 
        '    %(tp_dictoffset)s,                 /* tp_dictoffset */\n'
415
 
        '    (initproc)%(tp_init)s,             /* tp_init */\n'
416
 
        '    (allocfunc)%(tp_alloc)s,           /* tp_alloc */\n'
417
 
        '    (newfunc)%(tp_new)s,               /* tp_new */\n'
418
 
        '    (freefunc)%(tp_free)s,             /* tp_free */\n'
419
 
        '    (inquiry)%(tp_is_gc)s,             /* tp_is_gc */\n'
420
 
        '    NULL,                              /* tp_bases */\n'
421
 
        '    NULL,                              /* tp_mro */\n'
422
 
        '    NULL,                              /* tp_cache */\n'
423
 
        '    NULL,                              /* tp_subclasses */\n'
424
 
        '    NULL,                              /* tp_weaklist */\n'
425
 
        '    (destructor) NULL                  /* tp_del */\n'
426
 
        '};\n'
427
 
        )
428
 
 
429
382
    def __init__(self, name, parent=None, incref_method=None, decref_method=None,
430
383
                 automatic_type_narrowing=None, allow_subclassing=None,
431
384
                 is_singleton=False, outer_class=None,
483
436
        self._dummy_methods = [] # methods that have parameter/retval binding problems
484
437
        self.nonpublic_methods = []
485
438
        self.constructors = [] # (name, wrapper) pairs
486
 
        self.slots = dict()
 
439
        self.pytype = PyTypeObject()
 
440
        self.slots = self.pytype.slots
487
441
        self.helper_class = None
488
442
        self.instance_creation_function = None
489
443
        ## set to True when we become aware generating the helper
491
445
        self.helper_class_disabled = False
492
446
        self.cannot_be_constructed = '' # reason
493
447
        self.has_trivial_constructor = False
 
448
        self.has_copy_constructor = False
494
449
        self.has_output_stream_operator = False
495
450
        self._have_pure_virtual_methods = None
 
451
        self._wrapper_registry = None
 
452
        self.binary_comparison_operators = set()
 
453
        self.binary_numeric_operators = dict()
 
454
 
496
455
        ## list of CppClasses from which a value of this class can be
497
456
        ## implicitly generated; corresponds to a
498
457
        ## operator ThisClass(); in the other class.
617
576
    def __repr__(self):
618
577
        return "<pybindgen.CppClass %r>" % self.full_name
619
578
 
 
579
    def add_binary_comparison_operator(self, operator):
 
580
        """
 
581
        Add support for a C++ binary comparison operator, such as == or <.
 
582
 
 
583
        The binary operator is assumed to operate with both operands
 
584
        of the type of the class, either by reference or by value.
 
585
        
 
586
        @param operator: string indicating the name of the operator to
 
587
        support, e.g. '=='
 
588
        """
 
589
        if not isinstance(operator, str):
 
590
            raise TypeError("expected operator name as string")
 
591
        if operator not in ['==', '!=', '<', '<=', '>', '>=']:
 
592
            raise ValueError("The operator %r is invalid or not yet supported by PyBindGen" % (operator,))
 
593
        self.binary_comparison_operators.add(operator)
 
594
 
 
595
    def add_binary_numeric_operator(self, operator, result_cppclass=None,
 
596
                                    left_cppclass=None, right_cppclass=None):
 
597
        """
 
598
        Add support for a C++ binary numeric operator, such as +, -, *, or /.
 
599
 
 
600
        @param operator: string indicating the name of the operator to
 
601
        support, e.g. '=='
 
602
 
 
603
        @param result_cppclass: the CppClass object of the result type, assumed to be this class if omitted
 
604
        @param left_cppclass: the CppClass object of the left operand type, assumed to be this class if omitted
 
605
        @param right_cppclass: the CppClass object of the right operand type, assumed to be this class if omitted
 
606
        """
 
607
        if not isinstance(operator, str):
 
608
            raise TypeError("expected operator name as string")
 
609
        if operator not in ['+', '-', '*', '/']:
 
610
            raise ValueError("The operator %r is invalid or not yet supported by PyBindGen" % (operator,))
 
611
        try:
 
612
            l = self.binary_numeric_operators[operator]
 
613
        except KeyError:
 
614
            l = []
 
615
            self.binary_numeric_operators[operator] = l
 
616
        if result_cppclass is None:
 
617
            result_cppclass = self
 
618
        if left_cppclass is None:
 
619
            left_cppclass = self
 
620
        if right_cppclass is None:
 
621
            right_cppclass = self
 
622
        op = (result_cppclass, left_cppclass, right_cppclass)
 
623
        if op not in l:
 
624
            l.append(op)
620
625
 
621
626
    def add_class(self, *args, **kwargs):
622
627
        """
1035
1040
        method.class_ = self
1036
1041
 
1037
1042
        if method.visibility == 'public':
 
1043
            if name == '__call__': # needs special handling
 
1044
                method.force_parse = method.PARSE_TUPLE_AND_KEYWORDS
 
1045
 
1038
1046
            try:
1039
1047
                overload = self.methods[name]
1040
1048
            except KeyError:
1190
1198
        self.constructors.append(wrapper)
1191
1199
        if not wrapper.parameters:
1192
1200
            self.has_trivial_constructor = True # FIXME: I don't remember what is this used for anymore, maybe remove
 
1201
        if len(wrapper.parameters) == 1 and isinstance(wrapper.parameters[0], (CppClassRefParameter, CppClassParameter)) \
 
1202
                and wrapper.parameters[0].cpp_class is self and wrapper.visibility == 'public':
 
1203
            self.has_copy_constructor = True
1193
1204
 
1194
1205
    def add_output_stream_operator(self):
1195
1206
        """
1204
1215
        to a string.
1205
1216
        """
1206
1217
        self.has_output_stream_operator = True
 
1218
        self.module.add_include("<ostream>")
 
1219
        self.module.add_include("<sstream>")
1207
1220
 
1208
1221
    def add_constructor(self, *args, **kwargs):
1209
1222
        """
1232
1245
        self._add_constructor_obj(constructor)
1233
1246
        return constructor
1234
1247
 
 
1248
    def add_copy_constructor(self):
 
1249
        """
 
1250
        Utility method to add a 'copy constructor' method to this class.
 
1251
        """
 
1252
        try:
 
1253
            constructor = CppConstructor([self.ThisClassRefParameter("const %s &" % self.full_name,
 
1254
                                                                     'ctor_arg')])
 
1255
        except utils.SkipWrapper:
 
1256
            return None
 
1257
        constructor.stack_where_defined = traceback.extract_stack()
 
1258
        self._add_constructor_obj(constructor)
 
1259
        return constructor
 
1260
 
1235
1261
    def add_function_as_constructor(self, *args, **kwargs):
1236
1262
        """
1237
1263
        Wrap a function that behaves as a constructor to the class. See the documentation for
1320
1346
                method = method.clone()
1321
1347
                self.helper_class.add_virtual_method(method)
1322
1348
 
 
1349
    def _get_wrapper_registry(self):
 
1350
        # there is one wrapper registry object per root class only,
 
1351
        # which is used for all subclasses.
 
1352
        if self.parent is None:
 
1353
            if self._wrapper_registry is None:
 
1354
                self._wrapper_registry = settings.wrapper_registry(self.pystruct)
 
1355
            return self._wrapper_registry
 
1356
        else:
 
1357
            return self.parent._get_wrapper_registry()
 
1358
    wrapper_registry = property(_get_wrapper_registry)
1323
1359
 
1324
1360
    def generate_forward_declarations(self, code_sink, module):
1325
1361
        """
1368
1404
        if self.typeid_map_name is not None:
1369
1405
            self._generate_typeid_map(code_sink, module)
1370
1406
 
 
1407
        if self.parent is None:
 
1408
            self.wrapper_registry.generate_forward_declarations(code_sink, module)
1371
1409
 
1372
1410
    def generate(self, code_sink, module, docstring=None):
1373
1411
        """Generates the class to a code sink"""
1375
1413
        if self.typeid_map_name is not None:
1376
1414
            code_sink.writeln("\npybindgen::TypeMap %s;\n" % self.typeid_map_name)
1377
1415
 
 
1416
        if self.parent is None:
 
1417
            self.wrapper_registry.generate(code_sink, module)
 
1418
 
1378
1419
        if self.helper_class is not None:
1379
1420
            parent_caller_methods = self.helper_class.generate(code_sink)
1380
1421
        else:
1443
1484
        self._generate_destructor(code_sink, have_constructor)
1444
1485
        if self.has_output_stream_operator:
1445
1486
            self._generate_str(code_sink)
 
1487
        
 
1488
        #self._generate_tp_hash(code_sink)
 
1489
        #self._generate_tp_compare(code_sink)
1446
1490
 
1447
1491
        if self.slots.get("tp_richcompare", "NULL") == "NULL":
1448
1492
            self.slots["tp_richcompare"] = self._generate_tp_richcompare(code_sink)
 
1493
 
 
1494
        if self.binary_numeric_operators:
 
1495
            self.slots["tp_as_number"] = self._generate_number_methods(code_sink)
1449
1496
        
1450
1497
        self._generate_type_structure(code_sink, docstring)
 
1498
 
 
1499
    def _generate_number_methods(self, code_sink):
 
1500
        number_methods_var_name = "%s__py_number_methods" % (self.mangled_full_name,)
 
1501
 
 
1502
        pynumbermethods = PyNumberMethods()
 
1503
        pynumbermethods.slots['variable'] = number_methods_var_name
 
1504
 
 
1505
        # iterate over all types and request generation of the
 
1506
        # convertion functions for that type (so that those functions
 
1507
        # are not generated in the middle of one of the wrappers we
 
1508
        # are about to generate)
 
1509
        root_module = self.module.get_root()
 
1510
        for dummy_op_symbol, op_types in self.binary_numeric_operators.iteritems():
 
1511
            for (retval, left, right) in op_types:
 
1512
                root_module.generate_c_to_python_type_converter(retval.ThisClassReturn(retval.full_name), code_sink)
 
1513
                root_module.generate_python_to_c_type_converter(left.ThisClassReturn(left.full_name), code_sink)
 
1514
                root_module.generate_python_to_c_type_converter(right.ThisClassReturn(right.full_name), code_sink)
 
1515
 
 
1516
        def try_wrap_operator(op_symbol, slot_name):
 
1517
            try:
 
1518
                op_types = self.binary_numeric_operators[op_symbol]
 
1519
            except KeyError:
 
1520
                return
 
1521
            wrapper_name = "%s__%s" % (self.mangled_full_name, slot_name)
 
1522
            pynumbermethods.slots[slot_name] = wrapper_name
 
1523
            code_sink.writeln(("static PyObject*\n"
 
1524
                               "%s (PyObject *py_left, PyObject *py_right)\n"
 
1525
                               "{") % wrapper_name)
 
1526
            code_sink.indent()
 
1527
            for (retval, left, right) in op_types:
 
1528
                retval_converter = root_module.generate_c_to_python_type_converter(retval.ThisClassReturn(retval.full_name), code_sink)
 
1529
                left_converter = root_module.generate_python_to_c_type_converter(left.ThisClassReturn(left.full_name), code_sink)
 
1530
                right_converter = root_module.generate_python_to_c_type_converter(right.ThisClassReturn(right.full_name), code_sink)
 
1531
 
 
1532
                code_sink.writeln("{")
 
1533
                code_sink.indent()
 
1534
                
 
1535
                code_sink.writeln("%s left;" % left.full_name)
 
1536
                code_sink.writeln("%s right;" % right.full_name)
 
1537
                
 
1538
                code_sink.writeln("if (%s(py_left, &left) && %s(py_right, &right)) {" % (left_converter, right_converter))
 
1539
                code_sink.indent()
 
1540
                code_sink.writeln("%s result = (left %s right);" % (retval.full_name, op_symbol))
 
1541
                code_sink.writeln("return %s(&result);" % retval_converter)
 
1542
                code_sink.unindent()
 
1543
                code_sink.writeln("}")
 
1544
                code_sink.writeln("PyErr_Clear();")
 
1545
 
 
1546
                code_sink.unindent()
 
1547
                code_sink.writeln("}")
 
1548
                
 
1549
            code_sink.writeln("Py_INCREF(Py_NotImplemented);")
 
1550
            code_sink.writeln("return Py_NotImplemented;")
 
1551
            code_sink.unindent()
 
1552
            code_sink.writeln("}")
 
1553
 
 
1554
        try_wrap_operator('+', 'nb_add')
 
1555
        try_wrap_operator('-', 'nb_subtract')
 
1556
        try_wrap_operator('*', 'nb_multiply')
 
1557
        try_wrap_operator('/', 'nb_divide')
 
1558
        
 
1559
        pynumbermethods.generate(code_sink)
 
1560
        return '&' + number_methods_var_name
1451
1561
        
1452
1562
    def _generate_type_structure(self, code_sink, docstring):
1453
1563
        """generate the type structure"""
1454
1564
        self.slots.setdefault("tp_basicsize",
1455
1565
                              "sizeof(%s)" % (self.pystruct,))
1456
 
        for slot in ["tp_getattr", "tp_setattr", "tp_compare", "tp_repr",
1457
 
                     "tp_as_number", "tp_as_sequence", "tp_as_mapping",
1458
 
                     "tp_hash", "tp_call", "tp_str", "tp_getattro", "tp_setattro",
1459
 
                     "tp_as_buffer", "tp_traverse", "tp_clear", "tp_richcompare",
1460
 
                     "tp_iter", "tp_iternext", "tp_descr_get",
1461
 
                     "tp_descr_set", "tp_is_gc"]:
1462
 
            self.slots.setdefault(slot, "NULL")
1463
 
 
1464
 
        self.slots.setdefault("tp_alloc", "PyType_GenericAlloc")
1465
 
        self.slots.setdefault("tp_new", "PyType_GenericNew")
1466
 
        #self.slots.setdefault("tp_free", "_PyObject_Del")
1467
 
        self.slots.setdefault("tp_free", "0")
1468
 
        self.slots.setdefault("tp_weaklistoffset", "0")
 
1566
        tp_flags = set(['Py_TPFLAGS_DEFAULT'])
1469
1567
        if self.allow_subclassing:
1470
 
            self.slots.setdefault("tp_flags", ("Py_TPFLAGS_DEFAULT|"
1471
 
                                               "Py_TPFLAGS_HAVE_GC|"
1472
 
                                               "Py_TPFLAGS_BASETYPE"))
 
1568
            tp_flags.add("Py_TPFLAGS_HAVE_GC")
 
1569
            tp_flags.add("Py_TPFLAGS_BASETYPE")
1473
1570
            self.slots.setdefault("tp_dictoffset",
1474
1571
                                  "offsetof(%s, inst_dict)" % self.pystruct)
1475
1572
        else:
1476
 
            self.slots.setdefault("tp_flags", "Py_TPFLAGS_DEFAULT")
1477
1573
            self.slots.setdefault("tp_dictoffset", "0")
 
1574
        if self.binary_numeric_operators:
 
1575
            tp_flags.add("Py_TPFLAGS_CHECKTYPES")            
 
1576
        self.slots.setdefault("tp_flags", '|'.join(tp_flags))
1478
1577
        self.slots.setdefault("tp_doc", (docstring is None and 'NULL'
1479
1578
                                         or "\"%s\"" % (docstring,)))
1480
1579
        dict_ = self.slots
1486
1585
            dict_.setdefault("tp_name", '.'.join(mod_path))
1487
1586
        else:
1488
1587
            dict_.setdefault("tp_name", '%s.%s' % (self.outer_class.slots['tp_name'], self.name))
1489
 
            
1490
 
        code_sink.writeln(self.TYPE_TMPL % dict_)
 
1588
 
 
1589
        ## tp_call support
 
1590
        try:
 
1591
            call_method = self.methods['__call__']
 
1592
        except KeyError:
 
1593
            pass
 
1594
        else:
 
1595
            dict_.setdefault("tp_call", call_method.wrapper_actual_name)
 
1596
 
 
1597
        self.pytype.generate(code_sink)
1491
1598
 
1492
1599
 
1493
1600
    def _generate_constructor(self, code_sink):
1534
1641
                                          or constructor))
1535
1642
        return have_constructor
1536
1643
 
 
1644
    def _generate_copy_method(self, code_sink):
 
1645
        construct_name = self.get_construct_name()
 
1646
        copy_wrapper_name = '_wrap_%s__copy__' % self.pystruct
 
1647
        code_sink.writeln('''
 
1648
static PyObject*\n%s(%s *self)
 
1649
{
 
1650
''' % (copy_wrapper_name, self.pystruct))
 
1651
        code_sink.indent()
 
1652
 
 
1653
        declarations = DeclarationsScope()
 
1654
        code_block = CodeBlock("return NULL;", declarations)
 
1655
 
 
1656
        if self.allow_subclassing:
 
1657
            new_func = 'PyObject_GC_New'
 
1658
        else:
 
1659
            new_func = 'PyObject_New'
 
1660
 
 
1661
        py_copy = declarations.declare_variable("%s*" % self.pystruct, "py_copy")
 
1662
        code_block.write_code("%s = %s(%s, %s);" %
 
1663
                              (py_copy, new_func, self.pystruct, '&'+self.pytypestruct))
 
1664
        code_block.write_code("%s->obj = new %s(*self->obj);" % (py_copy, construct_name))
 
1665
        if self.allow_subclassing:
 
1666
            code_block.write_code("%s->inst_dict = NULL;" % py_copy)
 
1667
 
 
1668
        self.wrapper_registry.write_register_new_wrapper(code_block, py_copy, "%s->obj" % py_copy)
 
1669
 
 
1670
        code_block.write_code("return (PyObject*) %s;" % py_copy)
 
1671
 
 
1672
        declarations.get_code_sink().flush_to(code_sink)
 
1673
 
 
1674
        code_block.write_cleanup()
 
1675
        code_block.sink.flush_to(code_sink)
 
1676
 
 
1677
        code_sink.unindent()
 
1678
        code_sink.writeln("}")
 
1679
        code_sink.writeln()
 
1680
        return copy_wrapper_name
 
1681
 
1537
1682
    def _generate_methods(self, code_sink, parent_caller_methods):
1538
1683
        """generate the method wrappers"""
1539
1684
        method_defs = []
1544
1689
                utils.call_with_error_handling(overload.generate, (code_sink,), {}, overload)
1545
1690
            except utils.SkipWrapper:
1546
1691
                continue
1547
 
            method_defs.append(overload.get_py_method_def(meth_name))
 
1692
            if meth_name not in ['__call__']: # need to be converted to slots
 
1693
                method_defs.append(overload.get_py_method_def(meth_name))
1548
1694
            code_sink.writeln()
1549
1695
        method_defs.extend(parent_caller_methods)
 
1696
 
 
1697
        if self.has_copy_constructor:
 
1698
            try:
 
1699
                copy_wrapper_name = utils.call_with_error_handling(self._generate_copy_method, (code_sink,), {}, self)
 
1700
            except utils.SkipWrapper:
 
1701
                pass
 
1702
            else:
 
1703
                method_defs.append('{(char *) "__copy__", (PyCFunction) %s, METH_NOARGS, NULL},' % copy_wrapper_name)
 
1704
 
1550
1705
        ## generate the method table
1551
1706
        code_sink.writeln("static PyMethodDef %s_methods[] = {" % (self.pystruct,))
1552
1707
        code_sink.indent()
1628
1783
        self.slots.setdefault("tp_str", tp_str_function_name )
1629
1784
 
1630
1785
        code_sink.writeln('''
 
1786
 
1631
1787
static PyObject *
1632
1788
%s(%s *self)
1633
1789
{
1635
1791
    oss << *self->obj;
1636
1792
    return PyString_FromString(oss.str ().c_str ());
1637
1793
}
 
1794
 
1638
1795
''' % (tp_str_function_name, self.pystruct))
1639
 
        code_sink.writeln()
1640
 
 
 
1796
 
 
1797
    def _generate_tp_hash(self, code_sink):
 
1798
        """generates a tp_hash function, which returns a hash of the self->obj pointer"""
 
1799
 
 
1800
        tp_hash_function_name = "_wrap_%s__tp_hash" % (self.pystruct,)
 
1801
        self.slots.setdefault("tp_hash", tp_hash_function_name )
 
1802
 
 
1803
        code_sink.writeln('''
 
1804
 
 
1805
static long
 
1806
%s(%s *self)
 
1807
{
 
1808
    return (long) self->obj;
 
1809
}
 
1810
 
 
1811
''' % (tp_hash_function_name, self.pystruct))
 
1812
 
 
1813
    def _generate_tp_compare(self, code_sink):
 
1814
        """generates a tp_compare function, which compares the ->obj pointers"""
 
1815
 
 
1816
        tp_compare_function_name = "_wrap_%s__tp_compare" % (self.pystruct,)
 
1817
        self.slots.setdefault("tp_compare", tp_compare_function_name )
 
1818
 
 
1819
        code_sink.writeln('''
 
1820
 
 
1821
static int
 
1822
%s(%s *self, %s *other)
 
1823
{
 
1824
    if (self->obj == other->obj) return 0;
 
1825
    if (self->obj > other->obj)  return -1;
 
1826
    return 1;
 
1827
}
 
1828
 
 
1829
''' % (tp_compare_function_name, self.pystruct, self.pystruct))
 
1830
        
1641
1831
 
1642
1832
    def _generate_destructor(self, code_sink, have_constructor):
1643
1833
        """Generate a tp_dealloc function and register it in the type"""
1647
1837
            return
1648
1838
 
1649
1839
        tp_dealloc_function_name = "_wrap_%s__tp_dealloc" % (self.pystruct,)
 
1840
        code_sink.writeln(r'''
 
1841
static void
 
1842
%s(%s *self)
 
1843
{''' % (tp_dealloc_function_name, self.pystruct))
 
1844
        code_sink.indent()
 
1845
 
 
1846
        code_block = CodeBlock("PyErr_Print(); return;", DeclarationsScope())
 
1847
 
 
1848
        self.wrapper_registry.write_unregister_wrapper(code_block, 'self', 'self->obj')
1650
1849
 
1651
1850
        if self.allow_subclassing:
1652
 
            clear_code = "%s(self);" % self.slots["tp_clear"]
1653
 
            delete_code = ""
 
1851
            code_block.write_code("%s(self);" % self.slots["tp_clear"])
1654
1852
        else:
1655
 
            clear_code = ""
1656
 
            delete_code = self._get_delete_code()
1657
 
 
1658
 
        if have_constructor:
1659
 
            code_sink.writeln(r'''
1660
 
static void
1661
 
%s(%s *self)
1662
 
{
1663
 
    %s
1664
 
    %s
1665
 
    self->ob_type->tp_free((PyObject*)self);
1666
 
}
1667
 
''' % (tp_dealloc_function_name, self.pystruct,
1668
 
       delete_code, clear_code))
1669
 
 
1670
 
        else: # don't have constructor
1671
 
 
1672
 
            code_sink.writeln('''
1673
 
static void
1674
 
%s(%s *self)
1675
 
{
1676
 
    %s
1677
 
    %s
1678
 
    self->ob_type->tp_free((PyObject*)self);
1679
 
}
1680
 
''' % (tp_dealloc_function_name, self.pystruct,
1681
 
       clear_code, delete_code))
1682
 
        code_sink.writeln()
 
1853
            code_block.write_code(self._get_delete_code())
 
1854
 
 
1855
        code_block.write_code('self->ob_type->tp_free((PyObject*)self);')
 
1856
 
 
1857
        code_block.write_cleanup()
 
1858
        
 
1859
        code_block.declarations.get_code_sink().flush_to(code_sink)
 
1860
        code_block.sink.flush_to(code_sink)
 
1861
 
 
1862
        code_sink.unindent()
 
1863
        code_sink.writeln('}\n')
 
1864
 
1683
1865
        self.slots.setdefault("tp_dealloc", tp_dealloc_function_name )
1684
1866
 
1685
1867
 
1686
1868
    def _generate_tp_richcompare(self, code_sink):
1687
1869
        tp_richcompare_function_name = "_wrap_%s__tp_richcompare" % (self.pystruct,)
1688
1870
 
1689
 
        code_sink.writeln("static PyObject*\n%s (%s *self, PyObject *o2, int opid)"
1690
 
                          % (tp_richcompare_function_name, self.pystruct))
 
1871
        code_sink.writeln("static PyObject*\n%s (%s *self, %s *other, int opid)"
 
1872
                          % (tp_richcompare_function_name, self.pystruct, self.pystruct))
1691
1873
        code_sink.writeln("{")
1692
1874
        code_sink.indent()
1693
1875
 
1694
 
        ## TODO
1695
 
        code_sink.writeln('PyErr_SetString(PyExc_TypeError, "Comparison not defined or not yet implemented.");')
1696
 
        code_sink.writeln('return NULL;')
1697
 
 
1698
 
        #code_sink.writeln("Py_INCREF(Py_NotImplemented);")
1699
 
        #code_sink.writeln("return Py_NotImplemented;")
 
1876
        code_sink.writeln("""
 
1877
if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &%s)) {
 
1878
    Py_INCREF(Py_NotImplemented);
 
1879
    return Py_NotImplemented;
 
1880
}""" % self.pytypestruct)
 
1881
 
 
1882
        code_sink.writeln("switch (opid)\n{")
 
1883
 
 
1884
        def wrap_operator(name, opid_code):
 
1885
            code_sink.writeln("case %s:" % opid_code)
 
1886
            code_sink.indent()
 
1887
            if name in self.binary_comparison_operators:
 
1888
                code_sink.writeln("if (*self->obj %(OP)s *other->obj) {\n"
 
1889
                                  "    Py_INCREF(Py_True);\n"
 
1890
                                  "    return Py_True;\n"
 
1891
                                  "} else {\n"
 
1892
                                  "    Py_INCREF(Py_False);\n"
 
1893
                                  "    return Py_False;\n"
 
1894
                                  "}" % dict(OP=name))
 
1895
            else:
 
1896
                code_sink.writeln("Py_INCREF(Py_NotImplemented);\n"
 
1897
                                  "return Py_NotImplemented;")
 
1898
            code_sink.unindent()
 
1899
        
 
1900
        wrap_operator('<', 'Py_LT')
 
1901
        wrap_operator('<=', 'Py_LE')
 
1902
        wrap_operator('==', 'Py_EQ')
 
1903
        wrap_operator('!=', 'Py_NE')
 
1904
        wrap_operator('>=', 'Py_GE')
 
1905
        wrap_operator('>', 'Py_GT')
 
1906
 
 
1907
        code_sink.writeln("} /* closes switch (opid) */")
 
1908
 
 
1909
        code_sink.writeln("Py_INCREF(Py_NotImplemented);\n"
 
1910
                          "return Py_NotImplemented;")
1700
1911
 
1701
1912
        code_sink.unindent()
1702
1913
        code_sink.writeln("}\n")