/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
1
/* Copyright (C) 2009 Canonical Ltd
2
 * 
3
 * This program is free software; you can redistribute it and/or modify
4
 * it under the terms of the GNU General Public License as published by
5
 * the Free Software Foundation; either version 2 of the License, or
6
 * (at your option) any later version.
7
 *
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 * GNU General Public License for more details.
12
 *
13
 * You should have received a copy of the GNU General Public License
14
 * along with this program; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
4679.3.5 by John Arbash Meinel
Have a pure-python implementation that works as tuples of tuples of strings,
16
 */
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
17
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
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"
4679.5.11 by John Arbash Meinel
add a hack-around to handle differences between pyrex 0.9.6 and 0.9.8
25
26
/* Pyrex 0.9.6.4 exports _simple_set_pyx_api as
27
 * import__simple_set_pyx(), while Pyrex 0.9.8.5 and Cython 0.11.3 export them
28
 * as import_bzrlib___simple_set_pyx(). As such, we just #define one to be
29
 * equivalent to the other in our internal code.
30
 */
31
#define import__simple_set_pyx import_bzrlib___simple_set_pyx
4679.3.76 by John Arbash Meinel
Rename StaticTupleInterner => SimpleSet.
32
#include "_simple_set_pyx_api.h"
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
33
34
#include "python-compat.h"
35
36
#if defined(__GNUC__)
37
#   define inline __inline__
38
#elif defined(_MSC_VER)
39
#   define inline __inline
40
#else
41
#   define inline
42
#endif
43
44
4679.3.44 by John Arbash Meinel
Special case the empty tuple as a singleton.
45
/* The one and only StaticTuple with no values */
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
46
static StaticTuple *_empty_tuple = NULL;
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
47
static PyObject *_interned_tuples = NULL;
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
48
49
4679.3.33 by John Arbash Meinel
Change Key away from being a PyVarObject.
50
static inline int
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
51
_StaticTuple_is_interned(StaticTuple *self)
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
52
{
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
53
    return self->flags & STATIC_TUPLE_INTERNED_FLAG;
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
54
}
55
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
56
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
57
58
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
59
StaticTuple_as_tuple(StaticTuple *self)
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
60
{
61
    PyObject *tpl = NULL, *obj = NULL;
4679.3.33 by John Arbash Meinel
Change Key away from being a PyVarObject.
62
    int i, len;
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
63
4679.3.37 by John Arbash Meinel
Change the Key header a bit. It is simpler if you use unsigned char
64
    len = self->size;
4679.3.33 by John Arbash Meinel
Change Key away from being a PyVarObject.
65
    tpl = PyTuple_New(len);
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
66
    if (!tpl) {
67
        /* Malloc failure */
68
        return NULL;
69
    }
4679.3.33 by John Arbash Meinel
Change Key away from being a PyVarObject.
70
    for (i = 0; i < len; ++i) {
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
71
        obj = (PyObject *)self->items[i];
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
72
        Py_INCREF(obj);
73
        PyTuple_SET_ITEM(tpl, i, obj);
74
    }
75
    return tpl;
76
}
77
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
78
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
79
static char StaticTuple_as_tuple_doc[] = "as_tuple() => tuple";
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
80
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
81
static StaticTuple *
82
StaticTuple_Intern(StaticTuple *self)
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
83
{
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
84
    PyObject *canonical_tuple = NULL;
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
85
4679.3.81 by John Arbash Meinel
Fix up _simple_set_pyx.pyx to be compatible with pyrex again.
86
    if (_interned_tuples == NULL || _StaticTuple_is_interned(self)) {
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
87
        Py_INCREF(self);
88
        return self;
89
    }
4679.3.76 by John Arbash Meinel
Rename StaticTupleInterner => SimpleSet.
90
    /* SimpleSet_Add returns whatever object is present at self
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
91
     * or the new object if it needs to add it.
92
     */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
93
    canonical_tuple = SimpleSet_Add(_interned_tuples, (PyObject *)self);
94
    if (!canonical_tuple) {
95
        // Some sort of exception, propogate it.
96
        return NULL;
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
97
    }
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
98
    if (canonical_tuple != (PyObject *)self) {
99
        // There was already a tuple with that value
100
        return (StaticTuple *)canonical_tuple;
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
101
    }
102
    self->flags |= STATIC_TUPLE_INTERNED_FLAG;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
103
    // The two references in the dict do not count, so that the StaticTuple
104
    // object does not become immortal just because it was interned.
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
105
    Py_REFCNT(self) -= 1;
106
    return self;
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
107
}
108
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
109
static char StaticTuple_Intern_doc[] = "intern() => unique StaticTuple\n"
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
110
    "Return a 'canonical' StaticTuple object.\n"
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
111
    "Similar to intern() for strings, this makes sure there\n"
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
112
    "is only one StaticTuple object for a given value\n."
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
113
    "Common usage is:\n"
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
114
    "  key = StaticTuple('foo', 'bar').intern()\n";
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
115
116
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
117
static void
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
118
StaticTuple_dealloc(StaticTuple *self)
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
119
{
4679.3.33 by John Arbash Meinel
Change Key away from being a PyVarObject.
120
    int i, len;
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
121
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
122
    if (_StaticTuple_is_interned(self)) {
4679.3.81 by John Arbash Meinel
Fix up _simple_set_pyx.pyx to be compatible with pyrex again.
123
        /* revive dead object temporarily for Discard */
124
        Py_REFCNT(self) = 2;
4679.3.76 by John Arbash Meinel
Rename StaticTupleInterner => SimpleSet.
125
        if (SimpleSet_Discard(_interned_tuples, (PyObject*)self) != 1)
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
126
            Py_FatalError("deletion of interned StaticTuple failed");
4679.3.81 by John Arbash Meinel
Fix up _simple_set_pyx.pyx to be compatible with pyrex again.
127
        self->flags &= ~STATIC_TUPLE_INTERNED_FLAG;
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
128
    }
4679.3.37 by John Arbash Meinel
Change the Key header a bit. It is simpler if you use unsigned char
129
    len = self->size;
4679.3.33 by John Arbash Meinel
Change Key away from being a PyVarObject.
130
    for (i = 0; i < len; ++i) {
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
131
        Py_XDECREF(self->items[i]);
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
132
    }
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
133
    Py_TYPE(self)->tp_free((PyObject *)self);
134
}
135
136
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
137
/* Similar to PyTuple_New() */
138
static StaticTuple *
139
StaticTuple_New(Py_ssize_t size)
140
{
141
    StaticTuple *stuple;
142
    if (size < 0) {
143
        PyErr_BadInternalCall();
144
        return NULL;
145
    }
146
147
    if (size == 0 && _empty_tuple != NULL) {
148
        Py_INCREF(_empty_tuple);
149
        return _empty_tuple;
150
    }
151
    /* Note that we use PyObject_NewVar because we want to allocate a variable
152
     * width entry. However we *aren't* truly a PyVarObject because we don't
153
     * use a long for ob_size. Instead we use a plain 'size' that is an int,
154
     * and will be overloaded with flags in the future.
155
     * As such we do the alloc, and then have to clean up anything it does
156
     * incorrectly.
157
     */
158
    stuple = PyObject_NewVar(StaticTuple, &StaticTuple_Type, size);
159
    if (stuple == NULL) {
160
        return NULL;
161
    }
162
    stuple->size = size;
163
    stuple->flags = 0;
164
    stuple->_unused0 = 0;
165
    stuple->_unused1 = 0;
166
    if (size > 0) {
167
        memset(stuple->items, 0, sizeof(PyObject *) * size);
168
    }
169
#if STATIC_TUPLE_HAS_HASH
170
    stuple->hash = -1;
171
#endif
172
    return stuple;
173
}
174
175
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
176
static PyObject *
4679.5.9 by John Arbash Meinel
NEWS entry for StaticTuple class.
177
StaticTuple_new_constructor(PyTypeObject *type, PyObject *args, PyObject *kwds)
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
178
{
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
179
    StaticTuple *self;
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
180
    PyObject *obj = NULL;
181
    Py_ssize_t i, len = 0;
182
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
183
    if (type != &StaticTuple_Type) {
184
        PyErr_SetString(PyExc_TypeError, "we only support creating StaticTuple");
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
185
        return NULL;
186
    }
187
    if (!PyTuple_CheckExact(args)) {
188
        PyErr_SetString(PyExc_TypeError, "args must be a tuple");
189
        return NULL;
190
    }
191
    len = PyTuple_GET_SIZE(args);
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
192
    if (len < 0 || len > 255) {
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
193
        /* Too big or too small */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
194
        PyErr_SetString(PyExc_ValueError, "StaticTuple.__init__(...)"
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
195
            " takes from 0 to 255 items");
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
196
        return NULL;
197
    }
4679.3.44 by John Arbash Meinel
Special case the empty tuple as a singleton.
198
    self = (StaticTuple *)StaticTuple_New(len);
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
199
    if (self == NULL) {
200
        return NULL;
201
    }
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
202
    for (i = 0; i < len; ++i) {
203
        obj = PyTuple_GET_ITEM(args, i);
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
204
        if (!PyString_CheckExact(obj)) {
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
205
            if (!StaticTuple_CheckExact(obj)) {
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
206
                PyErr_SetString(PyExc_TypeError, "StaticTuple.__init__(...)"
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
207
                    " requires that all items are strings or StaticTuple.");
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
208
                type->tp_dealloc((PyObject *)self);
209
                return NULL;
210
            }
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
211
        }
212
        Py_INCREF(obj);
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
213
        self->items[i] = obj;
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
214
    }
215
    return (PyObject *)self;
216
}
217
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
218
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
219
StaticTuple_repr(StaticTuple *self)
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
220
{
4679.3.79 by John Arbash Meinel
Change the repr to print out 'StaticTuple'
221
    PyObject *as_tuple, *tuple_repr, *result;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
222
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
223
    as_tuple = StaticTuple_as_tuple(self);
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
224
    if (as_tuple == NULL) {
225
        return NULL;
226
    }
4679.3.79 by John Arbash Meinel
Change the repr to print out 'StaticTuple'
227
    tuple_repr = PyObject_Repr(as_tuple);
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
228
    Py_DECREF(as_tuple);
4679.3.79 by John Arbash Meinel
Change the repr to print out 'StaticTuple'
229
    if (tuple_repr == NULL) {
230
        return NULL;
231
    }
232
    result = PyString_FromFormat("%s%s", Py_TYPE(self)->tp_name,
233
                                         PyString_AsString(tuple_repr));
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
234
    return result;
235
}
236
237
static long
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
238
StaticTuple_hash(StaticTuple *self)
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
239
{
4679.3.22 by John Arbash Meinel
It seems that optimizing Keys_hash is not the way to go for 'bzr log' performance.
240
    /* adapted from tuplehash(), is the specific hash value considered
241
     * 'stable'?
242
     */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
243
    register long x, y;
244
    Py_ssize_t len = self->size;
245
    PyObject **p;
246
    long mult = 1000003L;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
247
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
248
#if STATIC_TUPLE_HAS_HASH
4679.3.22 by John Arbash Meinel
It seems that optimizing Keys_hash is not the way to go for 'bzr log' performance.
249
    if (self->hash != -1) {
250
        return self->hash;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
251
    }
4679.3.28 by John Arbash Meinel
Add a KEY_HAS_HASH define.
252
#endif
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
253
    x = 0x345678L;
254
    p = self->items;
4679.3.77 by John Arbash Meinel
Some code cleanup passes.
255
    // TODO: We could set specific flags if we know that, for example, all the
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
256
    //       items are strings. I haven't seen a real-world benefit to that
257
    //       yet, though.
4679.3.77 by John Arbash Meinel
Some code cleanup passes.
258
    while (--len >= 0) {
259
        y = PyObject_Hash(*p++);
260
        if (y == -1) /* failure */
261
            return -1;
262
        x = (x ^ y) * mult;
263
        /* the cast might truncate len; that doesn't change hash stability */
264
        mult += (long)(82520L + len + len);
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
265
    }
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
266
    x += 97531L;
267
    if (x == -1)
268
        x = -2;
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
269
#if STATIC_TUPLE_HAS_HASH
4679.3.22 by John Arbash Meinel
It seems that optimizing Keys_hash is not the way to go for 'bzr log' performance.
270
    self->hash = x;
4679.3.28 by John Arbash Meinel
Add a KEY_HAS_HASH define.
271
#endif
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
272
    return x;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
273
}
274
275
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
276
StaticTuple_richcompare_to_tuple(StaticTuple *v, PyObject *wt, int op)
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
277
{
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
278
    PyObject *vt;
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
279
    PyObject *result = NULL;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
280
    
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
281
    vt = StaticTuple_as_tuple((StaticTuple *)v);
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
282
    if (vt == NULL) {
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
283
        goto done;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
284
    }
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
285
    if (!PyTuple_Check(wt)) {
286
        PyErr_BadInternalCall();
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
287
        goto done;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
288
    }
289
    /* Now we have 2 tuples to compare, do it */
290
    result = PyTuple_Type.tp_richcompare(vt, wt, op);
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
291
done:
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
292
    Py_XDECREF(vt);
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
293
    return result;
294
}
295
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
296
/** Compare two objects to determine if they are equivalent.
297
 * The basic flow is as follows
298
 *  1) First make sure that both objects are StaticTuple instances. If they
299
 *     aren't then cast self to a tuple, and have the tuple do the comparison.
300
 *  2) Special case comparison to Py_None, because it happens to occur fairly
301
 *     often in the test suite.
302
 *  3) Special case when v and w are the same pointer. As we know the answer to
303
 *     all queries without walking individual items.
304
 *  4) For all operations, we then walk the items to find the first paired
305
 *     items that are not equal.
306
 *  5) If all items found are equal, we then check the length of self and
307
 *     other to determine equality.
308
 *  6) If an item differs, then we apply "op" to those last two items. (eg.
309
 *     StaticTuple(A, B) > StaticTuple(A, C) iff B > C)
310
 */
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
311
312
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
313
StaticTuple_richcompare(PyObject *v, PyObject *w, int op)
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
314
{
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
315
    StaticTuple *v_st, *w_st;
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
316
    Py_ssize_t vlen, wlen, min_len, i;
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
317
    PyObject *v_obj, *w_obj;
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
318
    richcmpfunc string_richcompare;
319
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
320
    if (!StaticTuple_CheckExact(v)) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
321
        /* This has never triggered, according to python-dev it seems this
322
         * might trigger if '__op__' is defined but '__rop__' is not, sort of
323
         * case. Such as "None == StaticTuple()"
324
         */
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
325
        fprintf(stderr, "self is not StaticTuple\n");
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
326
        Py_INCREF(Py_NotImplemented);
327
        return Py_NotImplemented;
328
    }
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
329
    v_st = (StaticTuple *)v;
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
330
    if (StaticTuple_CheckExact(w)) {
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
331
        /* The most common case */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
332
        w_st = (StaticTuple*)w;
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
333
    } else if (PyTuple_Check(w)) {
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
334
        /* One of v or w is a tuple, so we go the 'slow' route and cast up to
335
         * tuples to compare.
336
         */
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
337
        /* TODO: This seems to be triggering more than I thought it would...
338
         *       We probably want to optimize comparing self to other when
339
         *       other is a tuple.
340
         */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
341
        return StaticTuple_richcompare_to_tuple(v_st, w, op);
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
342
    } else if (w == Py_None) {
343
        // None is always less than the object
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
344
        switch (op) {
345
        case Py_NE:case Py_GT:case Py_GE:
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
346
            Py_INCREF(Py_True);
347
            return Py_True;
348
        case Py_EQ:case Py_LT:case Py_LE:
349
            Py_INCREF(Py_False);
350
            return Py_False;
4679.5.11 by John Arbash Meinel
add a hack-around to handle differences between pyrex 0.9.6 and 0.9.8
351
    default: // Should never happen
352
        return Py_NotImplemented;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
353
        }
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
354
    } else {
355
        /* We don't special case this comparison, we just let python handle
356
         * it.
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
357
         */
358
         Py_INCREF(Py_NotImplemented);
359
         return Py_NotImplemented;
360
    }
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
361
    /* Now we know that we have 2 StaticTuple objects, so let's compare them.
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
362
     * This code is inspired from tuplerichcompare, except we know our
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
363
     * objects are limited in scope, so we can inline some comparisons.
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
364
     */
365
    if (v == w) {
366
        /* Identical pointers, we can shortcut this easily. */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
367
        switch (op) {
368
        case Py_EQ:case Py_LE:case Py_GE:
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
369
            Py_INCREF(Py_True);
370
            return Py_True;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
371
        case Py_NE:case Py_LT:case Py_GT:
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
372
            Py_INCREF(Py_False);
373
            return Py_False;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
374
        }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
375
    }
4679.5.6 by John Arbash Meinel
Some comment cleanup, implement a special case for Py_EQ when both objects are intrened.
376
    if (op == Py_EQ
377
        && _StaticTuple_is_interned(v_st)
378
        && _StaticTuple_is_interned(w_st))
379
    {
380
        /* If both objects are interned, we know they are different if the
381
         * pointer is not the same, which would have been handled by the
382
         * previous if. No need to compare the entries.
383
         */
384
        Py_INCREF(Py_False);
385
        return Py_False;
386
    }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
387
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
388
    /* The only time we are likely to compare items of different lengths is in
389
     * something like the interned_keys set. However, the hash is good enough
390
     * that it is rare. Note that 'tuple_richcompare' also does not compare
391
     * lengths here.
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
392
     */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
393
    vlen = v_st->size;
394
    wlen = w_st->size;
395
    min_len = (vlen < wlen) ? vlen : wlen;
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
396
    string_richcompare = PyString_Type.tp_richcompare;
397
    for (i = 0; i < min_len; i++) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
398
        PyObject *result = NULL;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
399
        v_obj = StaticTuple_GET_ITEM(v_st, i);
400
        w_obj = StaticTuple_GET_ITEM(w_st, i);
4679.5.7 by John Arbash Meinel
Add a quick shortcut when comparing item-by-item.
401
        if (v_obj == w_obj) {
402
            /* Shortcut case, these must be identical */
403
            continue;
404
        }
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
405
        if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) {
406
            result = string_richcompare(v_obj, w_obj, Py_EQ);
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
407
        } else if (StaticTuple_CheckExact(v_obj) &&
408
                   StaticTuple_CheckExact(w_obj))
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
409
        {
410
            /* Both are StaticTuple types, so recurse */
411
            result = StaticTuple_richcompare(v_obj, w_obj, Py_EQ);
412
        } else {
413
            /* Not the same type, obviously they won't compare equal */
414
            break;
415
        }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
416
        if (result == NULL) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
417
            return NULL; /* There seems to be an error */
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
418
        }
419
        if (result == Py_NotImplemented) {
420
            PyErr_BadInternalCall();
421
            Py_DECREF(result);
422
            return NULL;
423
        }
424
        if (result == Py_False) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
425
            /* This entry is not identical
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
426
             * Shortcut for Py_EQ
427
             */
428
            if (op == Py_EQ) {
429
                return result;
430
            }
431
            Py_DECREF(result);
432
            break;
433
        }
434
        if (result != Py_True) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
435
            /* We don't know *what* richcompare is returning, but it
436
             * isn't something we recognize
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
437
             */
438
            PyErr_BadInternalCall();
439
            Py_DECREF(result);
440
            return NULL;
441
        }
442
        Py_DECREF(result);
443
    }
4679.5.11 by John Arbash Meinel
add a hack-around to handle differences between pyrex 0.9.6 and 0.9.8
444
    if (i >= min_len) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
445
        /* We walked off one of the lists, but everything compared equal so
446
         * far. Just compare the size.
447
         */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
448
        int cmp;
449
        PyObject *res;
450
        switch (op) {
451
        case Py_LT: cmp = vlen <  wlen; break;
452
        case Py_LE: cmp = vlen <= wlen; break;
453
        case Py_EQ: cmp = vlen == wlen; break;
454
        case Py_NE: cmp = vlen != wlen; break;
455
        case Py_GT: cmp = vlen >  wlen; break;
456
        case Py_GE: cmp = vlen >= wlen; break;
457
        default: return NULL; /* cannot happen */
458
        }
459
        if (cmp)
460
            res = Py_True;
461
        else
462
            res = Py_False;
463
        Py_INCREF(res);
464
        return res;
465
    }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
466
    /* The last item differs, shortcut the Py_NE case */
467
    if (op == Py_NE) {
468
        Py_INCREF(Py_True);
469
        return Py_True;
470
    }
471
    /* It is some other comparison, go ahead and do the real check. */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
472
    if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj))
473
    {
474
        return string_richcompare(v_obj, w_obj, op);
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
475
    } else if (StaticTuple_CheckExact(v_obj) &&
476
               StaticTuple_CheckExact(w_obj))
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
477
    {
478
        /* Both are StaticTuple types, so recurse */
479
        return StaticTuple_richcompare(v_obj, w_obj, op);
480
    } else {
481
        Py_INCREF(Py_NotImplemented);
482
        return Py_NotImplemented;
483
    }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
484
}
485
486
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
487
static Py_ssize_t
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
488
StaticTuple_length(StaticTuple *self)
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
489
{
4679.3.37 by John Arbash Meinel
Change the Key header a bit. It is simpler if you use unsigned char
490
    return self->size;
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
491
}
492
493
494
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
495
StaticTuple__is_interned(StaticTuple *self)
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
496
{
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
497
    if (_StaticTuple_is_interned(self)) {
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
498
        Py_INCREF(Py_True);
499
        return Py_True;
500
    }
501
    Py_INCREF(Py_False);
502
    return Py_False;
503
}
504
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
505
static char StaticTuple__is_interned_doc[] = "_is_interned() => True/False\n"
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
506
    "Check to see if this tuple has been interned.\n";
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
507
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
508
509
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
510
StaticTuple_item(StaticTuple *self, Py_ssize_t offset)
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
511
{
512
    PyObject *obj;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
513
    /* We cast to (int) to avoid worrying about whether Py_ssize_t is a
514
     * long long, etc. offsets should never be >2**31 anyway.
515
     */
516
    if (offset < 0) {
517
        PyErr_Format(PyExc_IndexError, "StaticTuple_item does not support"
518
            " negative indices: %d\n", (int)offset);
519
    } else if (offset >= self->size) {
520
        PyErr_Format(PyExc_IndexError, "StaticTuple index out of range"
521
            " %d >= %d", (int)offset, (int)self->size);
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
522
        return NULL;
523
    }
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
524
    obj = (PyObject *)self->items[offset];
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
525
    Py_INCREF(obj);
526
    return obj;
527
}
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
528
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
529
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
530
StaticTuple_slice(StaticTuple *self, Py_ssize_t ilow, Py_ssize_t ihigh)
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
531
{
532
    PyObject *as_tuple, *result;
533
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
534
    as_tuple = StaticTuple_as_tuple(self);
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
535
    if (as_tuple == NULL) {
536
        return NULL;
537
    }
538
    result = PyTuple_Type.tp_as_sequence->sq_slice(as_tuple, ilow, ihigh);
539
    Py_DECREF(as_tuple);
540
    return result;
541
}
542
4679.3.20 by John Arbash Meinel
Implement tp_traverse, and add a soft dependency on meliae to test it.
543
static int
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
544
StaticTuple_traverse(StaticTuple *self, visitproc visit, void *arg)
4679.3.20 by John Arbash Meinel
Implement tp_traverse, and add a soft dependency on meliae to test it.
545
{
546
    Py_ssize_t i;
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
547
    for (i = self->size; --i >= 0;) {
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
548
        Py_VISIT(self->items[i]);
4679.3.20 by John Arbash Meinel
Implement tp_traverse, and add a soft dependency on meliae to test it.
549
    }
550
    return 0;
551
}
552
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
553
static char StaticTuple_doc[] =
554
    "C implementation of a StaticTuple structure."
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
555
    "\n This is used as StaticTuple(item1, item2, item3)"
556
    "\n This is similar to tuple, less flexible in what it"
557
    "\n supports, but also lighter memory consumption."
558
    "\n Note that the constructor mimics the () form of tuples"
559
    "\n Rather than the 'tuple()' constructor."
560
    "\n  eg. StaticTuple(a, b) == (a, b) == tuple((a, b))";
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
561
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
562
static PyMethodDef StaticTuple_methods[] = {
563
    {"as_tuple", (PyCFunction)StaticTuple_as_tuple, METH_NOARGS, StaticTuple_as_tuple_doc},
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
564
    {"intern", (PyCFunction)StaticTuple_Intern, METH_NOARGS, StaticTuple_Intern_doc},
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
565
    {"_is_interned", (PyCFunction)StaticTuple__is_interned, METH_NOARGS,
566
     StaticTuple__is_interned_doc},
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
567
    {NULL, NULL} /* sentinel */
568
};
569
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
570
static PySequenceMethods StaticTuple_as_sequence = {
571
    (lenfunc)StaticTuple_length,            /* sq_length */
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
572
    0,                              /* sq_concat */
573
    0,                              /* sq_repeat */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
574
    (ssizeargfunc)StaticTuple_item,         /* sq_item */
575
    (ssizessizeargfunc)StaticTuple_slice,   /* sq_slice */
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
576
    0,                              /* sq_ass_item */
577
    0,                              /* sq_ass_slice */
578
    0,                              /* sq_contains */
579
};
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
580
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
581
/* TODO: Implement StaticTuple_as_mapping.
4679.5.6 by John Arbash Meinel
Some comment cleanup, implement a special case for Py_EQ when both objects are intrened.
582
 *       The only thing we really want to support from there is mp_subscript,
583
 *       so that we could support extended slicing (foo[::2]). Not worth it
584
 *       yet, though.
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
585
 */
586
4679.4.1 by John Arbash Meinel
Handle some issues with static/etc to get things to build on babune.
587
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
588
PyTypeObject StaticTuple_Type = {
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
589
    PyObject_HEAD_INIT(NULL)
590
    0,                                           /* ob_size */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
591
    "StaticTuple",                               /* tp_name */
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
592
    sizeof(StaticTuple),                         /* tp_basicsize */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
593
    sizeof(PyObject *),                          /* tp_itemsize */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
594
    (destructor)StaticTuple_dealloc,             /* tp_dealloc */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
595
    0,                                           /* tp_print */
596
    0,                                           /* tp_getattr */
597
    0,                                           /* tp_setattr */
598
    0,                                           /* tp_compare */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
599
    (reprfunc)StaticTuple_repr,                  /* tp_repr */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
600
    0,                                           /* tp_as_number */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
601
    &StaticTuple_as_sequence,                    /* tp_as_sequence */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
602
    0,                                           /* tp_as_mapping */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
603
    (hashfunc)StaticTuple_hash,                  /* tp_hash */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
604
    0,                                           /* tp_call */
605
    0,                                           /* tp_str */
606
    PyObject_GenericGetAttr,                     /* tp_getattro */
607
    0,                                           /* tp_setattro */
608
    0,                                           /* tp_as_buffer */
609
    Py_TPFLAGS_DEFAULT,                          /* tp_flags*/
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
610
    StaticTuple_doc,                             /* tp_doc */
4679.3.20 by John Arbash Meinel
Implement tp_traverse, and add a soft dependency on meliae to test it.
611
    /* gc.get_referents checks the IS_GC flag before it calls tp_traverse
612
     * And we don't include this object in the garbage collector because we
613
     * know it doesn't create cycles. However, 'meliae' will follow
614
     * tp_traverse, even if the object isn't GC, and we want that.
615
     */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
616
    (traverseproc)StaticTuple_traverse,          /* tp_traverse */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
617
    0,                                           /* tp_clear */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
618
    StaticTuple_richcompare,                     /* tp_richcompare */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
619
    0,                                           /* tp_weaklistoffset */
4679.3.76 by John Arbash Meinel
Rename StaticTupleInterner => SimpleSet.
620
    // without implementing tp_iter, Python will fall back to PySequence*
621
    // which seems to work ok, we may need something faster/lighter in the
622
    // future.
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
623
    0,                                           /* tp_iter */
624
    0,                                           /* tp_iternext */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
625
    StaticTuple_methods,                         /* tp_methods */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
626
    0,                                           /* tp_members */
627
    0,                                           /* tp_getset */
628
    0,                                           /* tp_base */
629
    0,                                           /* tp_dict */
630
    0,                                           /* tp_descr_get */
631
    0,                                           /* tp_descr_set */
632
    0,                                           /* tp_dictoffset */
633
    0,                                           /* tp_init */
634
    0,                                           /* tp_alloc */
4679.5.9 by John Arbash Meinel
NEWS entry for StaticTuple class.
635
    StaticTuple_new_constructor,                 /* tp_new */
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
636
};
637
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
638
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
639
static PyMethodDef static_tuple_c_methods[] = {
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
640
    {NULL, NULL}
641
};
642
643
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
644
static void
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
645
setup_interned_tuples(PyObject *m)
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
646
{
4679.3.76 by John Arbash Meinel
Rename StaticTupleInterner => SimpleSet.
647
    _interned_tuples = (PyObject *)SimpleSet_New();
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
648
    if (_interned_tuples != NULL) {
649
        Py_INCREF(_interned_tuples);
650
        PyModule_AddObject(m, "_interned_tuples", _interned_tuples);
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
651
    }
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
652
}
653
654
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
655
static void
656
setup_empty_tuple(PyObject *m)
657
{
658
    StaticTuple *stuple;
659
    if (_interned_tuples == NULL) {
660
        fprintf(stderr, "You need to call setup_interned_tuples() before"
661
                " setup_empty_tuple, because we intern it.\n");
662
    }
663
    // We need to create the empty tuple
664
    stuple = (StaticTuple *)StaticTuple_New(0);
665
    _empty_tuple = StaticTuple_Intern(stuple);
666
    assert(_empty_tuple == stuple);
667
    // At this point, refcnt is 2: 1 from New(), and 1 from the return from
668
    // intern(). We will keep 1 for the _empty_tuple global, and use the other
669
    // for the module reference.
670
    PyModule_AddObject(m, "_empty_tuple", (PyObject *)_empty_tuple);
671
}
672
673
static int
674
_StaticTuple_CheckExact(PyObject *obj)
675
{
676
    return StaticTuple_CheckExact(obj);
677
}
678
679
static void
680
setup_c_api(PyObject *m)
681
{
682
    _export_function(m, "StaticTuple_New", StaticTuple_New,
683
        "StaticTuple *(Py_ssize_t)");
684
    _export_function(m, "StaticTuple_Intern", StaticTuple_Intern,
685
        "StaticTuple *(StaticTuple *)");
686
    _export_function(m, "_StaticTuple_CheckExact", _StaticTuple_CheckExact,
687
        "int(PyObject *)");
688
}
689
690
4679.5.11 by John Arbash Meinel
add a hack-around to handle differences between pyrex 0.9.6 and 0.9.8
691
static int
692
_workaround_pyrex_096()
693
{
694
    /* Work around an incompatibility in how pyrex 0.9.6 exports a module,
695
     * versus how pyrex 0.9.8 and cython 0.11 export it.
696
     * Namely 0.9.6 exports import__simple_set_pyx and tries to
697
     * "import _simple_set_pyx" but it is available only as
698
     * "import bzrlib._simple_set_pyx"
699
     * It is a shame to hack up sys.modules, but that is what we've got to do.
700
     */
701
    PyObject *sys_module = NULL, *modules = NULL, *set_module = NULL;
702
    int retval = -1;
703
704
    /* Clear out the current ImportError exception, and try again. */
705
    PyErr_Clear();
706
    /* Note that this only seems to work if somewhere else imports
707
     * bzrlib._simple_set_pyx before importing bzrlib._static_tuple_c
708
     */
709
    set_module = PyImport_ImportModule("bzrlib._simple_set_pyx");
710
    if (set_module == NULL) {
711
	// fprintf(stderr, "Failed to import bzrlib._simple_set_pyx\n");
712
        goto end;
713
    }
714
    /* Add the _simple_set_pyx into sys.modules at the appropriate location. */
715
    sys_module = PyImport_ImportModule("sys");
716
    if (sys_module == NULL) {
717
    	// fprintf(stderr, "Failed to import sys\n");
718
        goto end;
719
    }
720
    modules = PyObject_GetAttrString(sys_module, "modules");
721
    if (modules == NULL || !PyDict_Check(modules)) {
722
    	// fprintf(stderr, "Failed to find sys.modules\n");
723
        goto end;
724
    }
725
    PyDict_SetItemString(modules, "_simple_set_pyx", set_module);
726
    /* Now that we have hacked it in, try the import again. */
727
    retval = import_bzrlib___simple_set_pyx();
728
end:
729
    Py_XDECREF(set_module);
730
    Py_XDECREF(sys_module);
731
    Py_XDECREF(modules);
732
    return retval;
733
}
734
735
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
736
PyMODINIT_FUNC
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
737
init_static_tuple_c(void)
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
738
{
739
    PyObject* m;
740
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
741
    if (PyType_Ready(&StaticTuple_Type) < 0)
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
742
        return;
743
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
744
    m = Py_InitModule3("_static_tuple_c", static_tuple_c_methods,
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
745
                       "C implementation of a StaticTuple structure");
746
    if (m == NULL)
747
      return;
748
749
    Py_INCREF(&StaticTuple_Type);
750
    PyModule_AddObject(m, "StaticTuple", (PyObject *)&StaticTuple_Type);
4679.5.11 by John Arbash Meinel
add a hack-around to handle differences between pyrex 0.9.6 and 0.9.8
751
    if (import_bzrlib___simple_set_pyx() == -1
752
        && _workaround_pyrex_096() == -1)
753
    {
4679.3.81 by John Arbash Meinel
Fix up _simple_set_pyx.pyx to be compatible with pyrex again.
754
        return;
755
    }
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
756
    setup_interned_tuples(m);
757
    setup_empty_tuple(m);
758
    setup_c_api(m);
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
759
}