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