~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_static_tuple_c.c

Revert back to before I started trying to move to pyrex/cython code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 */
17
17
 
18
 
#include "Python.h"
19
 
#include "_static_tuple_type_c.h"
20
 
#include "_static_tuple_pyx_api.h"
 
18
/* Must be defined before importing _static_tuple_c.h so that we get the right
 
19
 * linkage.
 
20
 */
 
21
#define STATIC_TUPLE_MODULE
 
22
 
 
23
#include "_static_tuple_c.h"
 
24
#include "_export_c_api.h"
 
25
#include "_static_tuple_interned_pyx_api.h"
21
26
 
22
27
#include "python-compat.h"
23
28
 
31
36
 
32
37
 
33
38
/* The one and only StaticTuple with no values */
 
39
static StaticTuple *_empty_tuple = NULL;
34
40
static PyObject *_interned_tuples = NULL;
35
41
 
36
42
 
65
71
 
66
72
static char StaticTuple_as_tuple_doc[] = "as_tuple() => tuple";
67
73
 
68
 
static PyObject *
69
 
_StaticTuple_intern(StaticTuple *self)
 
74
static StaticTuple *
 
75
StaticTuple_Intern(StaticTuple *self)
70
76
{
71
 
    return (PyObject *)StaticTuple_Intern(self);
 
77
    PyObject *unique_key = NULL;
 
78
 
 
79
    if (_interned_tuples == NULL) {
 
80
        Py_INCREF(self);
 
81
        return self;
 
82
    }
 
83
    if (_StaticTuple_is_interned(self)) {
 
84
        // Already interned
 
85
        Py_INCREF(self);
 
86
        return self;
 
87
    }
 
88
    /* StaticTupleInterner_Add returns whatever object is present at self
 
89
     * or the new object if it needs to add it.
 
90
     */
 
91
    unique_key = StaticTupleInterner_Add(_interned_tuples, (PyObject *)self);
 
92
    if (!unique_key) {
 
93
        // Suppress any error and just return the object
 
94
        PyErr_Clear();
 
95
        return self;
 
96
    }
 
97
    if (unique_key != (PyObject *)self) {
 
98
        // There was already a key at that location
 
99
        return (StaticTuple *)unique_key;
 
100
    }
 
101
    self->flags |= STATIC_TUPLE_INTERNED_FLAG;
 
102
    // The two references in the dict do not count, so that the StaticTuple object
 
103
    // does not become immortal just because it was interned.
 
104
    Py_REFCNT(self) -= 1;
 
105
    return self;
72
106
}
73
107
 
74
 
static char StaticTuple_intern_doc[] = "intern() => unique StaticTuple\n"
 
108
static char StaticTuple_Intern_doc[] = "intern() => unique StaticTuple\n"
75
109
    "Return a 'canonical' StaticTuple object.\n"
76
110
    "Similar to intern() for strings, this makes sure there\n"
77
111
    "is only one StaticTuple object for a given value\n."
98
132
}
99
133
 
100
134
 
 
135
/* Similar to PyTuple_New() */
 
136
static StaticTuple *
 
137
StaticTuple_New(Py_ssize_t size)
 
138
{
 
139
    StaticTuple *stuple;
 
140
    if (size < 0) {
 
141
        PyErr_BadInternalCall();
 
142
        return NULL;
 
143
    }
 
144
 
 
145
    if (size == 0 && _empty_tuple != NULL) {
 
146
        Py_INCREF(_empty_tuple);
 
147
        return _empty_tuple;
 
148
    }
 
149
    /* Note that we use PyObject_NewVar because we want to allocate a variable
 
150
     * width entry. However we *aren't* truly a PyVarObject because we don't
 
151
     * use a long for ob_size. Instead we use a plain 'size' that is an int,
 
152
     * and will be overloaded with flags in the future.
 
153
     * As such we do the alloc, and then have to clean up anything it does
 
154
     * incorrectly.
 
155
     */
 
156
    stuple = PyObject_NewVar(StaticTuple, &StaticTuple_Type, size);
 
157
    if (stuple == NULL) {
 
158
        return NULL;
 
159
    }
 
160
    stuple->size = size;
 
161
    stuple->flags = 0;
 
162
    stuple->_unused0 = 0;
 
163
    stuple->_unused1 = 0;
 
164
    if (size > 0) {
 
165
        memset(stuple->items, 0, sizeof(PyObject *) * size);
 
166
    }
 
167
#if STATIC_TUPLE_HAS_HASH
 
168
    stuple->hash = -1;
 
169
#endif
 
170
    return stuple;
 
171
}
 
172
 
 
173
 
101
174
static PyObject *
102
175
StaticTuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
103
176
{
130
203
        obj = PyTuple_GET_ITEM(args, i);
131
204
        if (!PyString_CheckExact(obj)) {
132
205
            is_all_str = 0;
133
 
            if (!_StaticTuple_CheckExact(obj)) {
 
206
            if (!StaticTuple_CheckExact(obj)) {
134
207
                PyErr_SetString(PyExc_TypeError, "StaticTuple.__init__(...)"
135
208
                    " requires that all key bits are strings or StaticTuple.");
136
209
                /* TODO: What is the proper way to dealloc ? */
249
322
    PyObject *v_obj, *w_obj;
250
323
    richcmpfunc string_richcompare;
251
324
 
252
 
    if (!_StaticTuple_CheckExact(v)) {
 
325
    if (!StaticTuple_CheckExact(v)) {
253
326
        /* This has never triggered, according to python-dev it seems this
254
327
         * might trigger if '__op__' is defined but '__rop__' is not, sort of
255
328
         * case. Such as "None == StaticTuple()"
259
332
        return Py_NotImplemented;
260
333
    }
261
334
    vk = (StaticTuple *)v;
262
 
    if (_StaticTuple_CheckExact(w)) {
 
335
    if (StaticTuple_CheckExact(w)) {
263
336
        /* The most common case */
264
337
        wk = (StaticTuple*)w;
265
338
    } else if (PyTuple_Check(w)) {
323
396
        w_obj = StaticTuple_GET_ITEM(wk, i);
324
397
        if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) {
325
398
            result = string_richcompare(v_obj, w_obj, Py_EQ);
326
 
        } else if (_StaticTuple_CheckExact(v_obj) &&
327
 
                   _StaticTuple_CheckExact(w_obj))
 
399
        } else if (StaticTuple_CheckExact(v_obj) &&
 
400
                   StaticTuple_CheckExact(w_obj))
328
401
        {
329
402
            /* Both are StaticTuple types, so recurse */
330
403
            result = StaticTuple_richcompare(v_obj, w_obj, Py_EQ);
391
464
    if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj))
392
465
    {
393
466
        return string_richcompare(v_obj, w_obj, op);
394
 
    } else if (_StaticTuple_CheckExact(v_obj) &&
395
 
               _StaticTuple_CheckExact(w_obj))
 
467
    } else if (StaticTuple_CheckExact(v_obj) &&
 
468
               StaticTuple_CheckExact(w_obj))
396
469
    {
397
470
        /* Both are StaticTuple types, so recurse */
398
471
        return StaticTuple_richcompare(v_obj, w_obj, op);
470
543
 
471
544
static PyMethodDef StaticTuple_methods[] = {
472
545
    {"as_tuple", (PyCFunction)StaticTuple_as_tuple, METH_NOARGS, StaticTuple_as_tuple_doc},
473
 
    // set after loading _static_tuple_pyx
474
 
    {"intern", (PyCFunction)_StaticTuple_intern, METH_NOARGS, StaticTuple_intern_doc},
 
546
    {"intern", (PyCFunction)StaticTuple_Intern, METH_NOARGS, StaticTuple_Intern_doc},
475
547
    {"_is_interned", (PyCFunction)StaticTuple__is_interned, METH_NOARGS,
476
548
     StaticTuple__is_interned_doc},
477
549
    {NULL, NULL} /* sentinel */
540
612
};
541
613
 
542
614
 
 
615
static char KeyIntern_doc[] = "";
 
616
 
 
617
static PyMethodDef KeyIntern_methods[] = {
 
618
    // {"as_tuple", (PyCFunction)Keys_as_tuple, METH_NOARGS, Keys_as_tuple_doc},
 
619
    {NULL, NULL} /* sentinel */
 
620
};
 
621
 
 
622
// static PySequenceMethods KeyIntern_as_sequence = {
 
623
//     0, //(lenfunc)Keys_length,           /* sq_length */
 
624
//     0,                              /* sq_concat */
 
625
//     0,                              /* sq_repeat */
 
626
//     0, //(ssizeargfunc)Keys_item,        /* sq_item */
 
627
//     0,                              /* sq_slice */
 
628
//     0,                              /* sq_ass_item */
 
629
//     0,                              /* sq_ass_slice */
 
630
//     0,                              /* sq_contains */
 
631
// };
 
632
 
 
633
// static PyTypeObject KeyIntern_Type = {
 
634
//     PyObject_HEAD_INIT(NULL)
 
635
//     0,                                           /* ob_size */
 
636
//     "KeyIntern",                                 /* tp_name */
 
637
//     sizeof(KeyIntern) - sizeof(Key *),           /* tp_basicsize */
 
638
//     sizeof(Key *),                               /* tp_itemsize */
 
639
//     0, //(destructor)Keys_dealloc,               /* tp_dealloc */
 
640
//     0,                                           /* tp_print */
 
641
//     0,                                           /* tp_getattr */
 
642
//     0,                                           /* tp_setattr */
 
643
//     0,                                           /* tp_compare */
 
644
//     // TODO: implement repr() and possibly str()
 
645
//     0, //(reprfunc)Keys_repr,                         /* tp_repr */
 
646
//     0,                                           /* tp_as_number */
 
647
//     &KeyIntern_as_sequence,                      /* tp_as_sequence */
 
648
//     0,                                           /* tp_as_mapping */
 
649
//     0, //(hashfunc)Keys_hash,                         /* tp_hash */
 
650
//     0,                                           /* tp_call */
 
651
//     0,                                           /* tp_str */
 
652
//     PyObject_GenericGetAttr,                     /* tp_getattro */
 
653
//     0,                                           /* tp_setattro */
 
654
//     0,                                           /* tp_as_buffer */
 
655
//     Py_TPFLAGS_DEFAULT,                          /* tp_flags*/
 
656
//     0, // Keys_doc,                                    /* tp_doc */
 
657
//     /* See Key_traverse for why we have this, even though we aren't GC */
 
658
//     0, //(traverseproc)Keys_traverse,                 /* tp_traverse */
 
659
//     0,                                           /* tp_clear */
 
660
//     // TODO: implement richcompare, we should probably be able to compare vs an
 
661
//     //       tuple, as well as versus another Keys object.
 
662
//     0, //Keys_richcompare,                            /* tp_richcompare */
 
663
//     0,                                           /* tp_weaklistoffset */
 
664
//     // We could implement this as returning tuples of keys...
 
665
//     0,                                           /* tp_iter */
 
666
//     0,                                           /* tp_iternext */
 
667
//     KeyIntern_methods,                           /* tp_methods */
 
668
//     0,                                           /* tp_members */
 
669
//     0,                                           /* tp_getset */
 
670
//     0,                                           /* tp_base */
 
671
//     0,                                           /* tp_dict */
 
672
//     0,                                           /* tp_descr_get */
 
673
//     0,                                           /* tp_descr_set */
 
674
//     0,                                           /* tp_dictoffset */
 
675
//     0,                                           /* tp_init */
 
676
//     0,                                           /* tp_alloc */
 
677
//     0, //Keys_new,                                    /* tp_new */
 
678
// };
 
679
 
 
680
 
543
681
static PyMethodDef static_tuple_c_methods[] = {
544
682
//    {"unique_lcs_c", py_unique_lcs, METH_VARARGS},
545
683
//    {"recurse_matches_c", py_recurse_matches, METH_VARARGS},
558
696
}
559
697
 
560
698
 
 
699
static void
 
700
setup_empty_tuple(PyObject *m)
 
701
{
 
702
    StaticTuple *stuple;
 
703
    if (_interned_tuples == NULL) {
 
704
        fprintf(stderr, "You need to call setup_interned_tuples() before"
 
705
                " setup_empty_tuple, because we intern it.\n");
 
706
    }
 
707
    // We need to create the empty tuple
 
708
    stuple = (StaticTuple *)StaticTuple_New(0);
 
709
    stuple->flags = STATIC_TUPLE_ALL_STRING;
 
710
    _empty_tuple = StaticTuple_Intern(stuple);
 
711
    assert(_empty_tuple == stuple);
 
712
    // At this point, refcnt is 2: 1 from New(), and 1 from the return from
 
713
    // intern(). We will keep 1 for the _empty_tuple global, and use the other
 
714
    // for the module reference.
 
715
    PyModule_AddObject(m, "_empty_tuple", (PyObject *)_empty_tuple);
 
716
}
 
717
 
 
718
static int
 
719
_StaticTuple_CheckExact(PyObject *obj)
 
720
{
 
721
    return StaticTuple_CheckExact(obj);
 
722
}
 
723
 
 
724
static void
 
725
setup_c_api(PyObject *m)
 
726
{
 
727
    _export_function(m, "StaticTuple_New", StaticTuple_New,
 
728
        "StaticTuple *(Py_ssize_t)");
 
729
    _export_function(m, "StaticTuple_Intern", StaticTuple_Intern,
 
730
        "StaticTuple *(StaticTuple *)");
 
731
    _export_function(m, "_StaticTuple_CheckExact", _StaticTuple_CheckExact,
 
732
        "int(PyObject *)");
 
733
}
 
734
 
 
735
 
561
736
PyMODINIT_FUNC
562
 
init_static_tuple_type_c(void)
 
737
init_static_tuple_c(void)
563
738
{
564
739
    PyObject* m;
565
 
    fprintf(stderr, "init_static_tuple_type_c\n");
566
740
 
567
 
    if (PyType_Ready(&StaticTuple_Type) < 0) {
568
 
        fprintf(stderr, "StaticTuple_Type not ready\n");
 
741
    if (PyType_Ready(&StaticTuple_Type) < 0)
569
742
        return;
570
 
    }
571
 
    fprintf(stderr, "StaticTuple_Type ready\n");
572
743
 
573
 
    m = Py_InitModule3("_static_tuple_type_c", static_tuple_c_methods,
 
744
    m = Py_InitModule3("_static_tuple_c", static_tuple_c_methods,
574
745
                       "C implementation of a StaticTuple structure");
575
746
    if (m == NULL)
576
747
      return;
577
748
 
578
749
    Py_INCREF(&StaticTuple_Type);
579
750
    PyModule_AddObject(m, "StaticTuple", (PyObject *)&StaticTuple_Type);
580
 
    fprintf(stderr, "added the StaticTuple type, importing _static_tuple_pyx\n");
581
 
    if (import_bzrlib___static_tuple_pyx() == -1) {
582
 
        PyObject *m2;
583
 
        fprintf(stderr, "Failed to import_bzrlib___static_tuple_pyx.\n");
584
 
        // PyErr_SetString(PyExc_ImportError,
585
 
        //                 "Failed to import _static_tuple_pyx");
586
 
 
587
 
        // m2 = PyImport_ImportModule("bzrlib._static_tuple_pyx");
588
 
        // if (m2 == NULL) {
589
 
        //     fprintf(stderr, "Failed to import bzrlib._static_tuple_pyx\n");
590
 
        // }
591
 
        // Py_INCREF(&StaticTuple_Type);
592
 
        // if (PyModule_AddObject(m2, "StaticTuple", (PyObject
593
 
        //     *)&StaticTuple_Type) == -1) {
594
 
        //     fprintf(stderr, "Failed to add StaticTuple to bzrlib._static_tuple_pyx\n");
595
 
        // }
596
 
        return;
597
 
    }
598
 
    if (PyErr_Occurred()) {
599
 
        fprintf(stderr, "an exception has occurred\n");
600
 
    }
601
 
    fprintf(stderr, "imported successfully\n");
 
751
    import_bzrlib___static_tuple_interned_pyx();
 
752
    setup_interned_tuples(m);
 
753
    setup_empty_tuple(m);
 
754
    setup_c_api(m);
602
755
}