/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
4739.4.1 by John Arbash Meinel
Implement StaticTuple.from_sequence()
177
static StaticTuple *
178
StaticTuple_FromSequence(PyObject *sequence)
179
{
180
    StaticTuple *new;
181
    PyObject *item;
182
    Py_ssize_t i, size;
183
184
    if (StaticTuple_CheckExact(sequence)) {
185
        Py_INCREF(sequence);
186
        return (StaticTuple *)sequence;
187
    }
188
    if (!PySequence_Check(sequence)) {
189
        PyErr_Format(PyExc_TypeError, "Type %s is not a sequence type",
190
                     Py_TYPE(sequence)->tp_name);
191
        return NULL;
192
    }
193
    size = PySequence_Size(sequence);
194
    if (size == -1)
195
        return NULL;
196
    new = StaticTuple_New(size);
197
    if (new == NULL) {
198
        return NULL;
199
    }
200
    for (i = 0; i < size; ++i) {
201
        // This returns a new reference, which we then 'steal' with 
202
        // StaticTuple_SET_ITEM
203
        item = PySequence_GetItem(sequence, i);
204
        if (item == NULL) {
205
            Py_DECREF(new);
206
            return NULL;
207
        }
208
        StaticTuple_SET_ITEM(new, i, item);
209
    }
210
    return (StaticTuple *)new;
211
}
212
213
static StaticTuple *
214
StaticTuple_from_sequence(PyObject *self, PyObject *args, PyObject *kwargs)
215
{
216
    PyObject *sequence;
217
    if (!PyArg_ParseTuple(args, "O", &sequence))
218
        return NULL;
219
    return StaticTuple_FromSequence(sequence);
220
}
221
222
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
223
static PyObject *
4679.5.9 by John Arbash Meinel
NEWS entry for StaticTuple class.
224
StaticTuple_new_constructor(PyTypeObject *type, PyObject *args, PyObject *kwds)
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
225
{
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
226
    StaticTuple *self;
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
227
    PyObject *obj = NULL;
228
    Py_ssize_t i, len = 0;
229
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
230
    if (type != &StaticTuple_Type) {
231
        PyErr_SetString(PyExc_TypeError, "we only support creating StaticTuple");
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
232
        return NULL;
233
    }
234
    if (!PyTuple_CheckExact(args)) {
235
        PyErr_SetString(PyExc_TypeError, "args must be a tuple");
236
        return NULL;
237
    }
238
    len = PyTuple_GET_SIZE(args);
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
239
    if (len < 0 || len > 255) {
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
240
        /* Too big or too small */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
241
        PyErr_SetString(PyExc_ValueError, "StaticTuple.__init__(...)"
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
242
            " takes from 0 to 255 items");
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
243
        return NULL;
244
    }
4679.3.44 by John Arbash Meinel
Special case the empty tuple as a singleton.
245
    self = (StaticTuple *)StaticTuple_New(len);
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
246
    if (self == NULL) {
247
        return NULL;
248
    }
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
249
    for (i = 0; i < len; ++i) {
250
        obj = PyTuple_GET_ITEM(args, i);
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
251
        if (!PyString_CheckExact(obj)) {
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
252
            if (!StaticTuple_CheckExact(obj)) {
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
253
                PyErr_SetString(PyExc_TypeError, "StaticTuple.__init__(...)"
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
254
                    " requires that all items are strings or StaticTuple.");
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
255
                type->tp_dealloc((PyObject *)self);
256
                return NULL;
257
            }
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
258
        }
259
        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.
260
        self->items[i] = obj;
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
261
    }
262
    return (PyObject *)self;
263
}
264
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
265
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
266
StaticTuple_repr(StaticTuple *self)
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
267
{
4679.3.79 by John Arbash Meinel
Change the repr to print out 'StaticTuple'
268
    PyObject *as_tuple, *tuple_repr, *result;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
269
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
270
    as_tuple = StaticTuple_as_tuple(self);
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
271
    if (as_tuple == NULL) {
272
        return NULL;
273
    }
4679.3.79 by John Arbash Meinel
Change the repr to print out 'StaticTuple'
274
    tuple_repr = PyObject_Repr(as_tuple);
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
275
    Py_DECREF(as_tuple);
4679.3.79 by John Arbash Meinel
Change the repr to print out 'StaticTuple'
276
    if (tuple_repr == NULL) {
277
        return NULL;
278
    }
279
    result = PyString_FromFormat("%s%s", Py_TYPE(self)->tp_name,
280
                                         PyString_AsString(tuple_repr));
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
281
    return result;
282
}
283
284
static long
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
285
StaticTuple_hash(StaticTuple *self)
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
286
{
4679.3.22 by John Arbash Meinel
It seems that optimizing Keys_hash is not the way to go for 'bzr log' performance.
287
    /* adapted from tuplehash(), is the specific hash value considered
288
     * 'stable'?
289
     */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
290
    register long x, y;
291
    Py_ssize_t len = self->size;
292
    PyObject **p;
293
    long mult = 1000003L;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
294
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
295
#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.
296
    if (self->hash != -1) {
297
        return self->hash;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
298
    }
4679.3.28 by John Arbash Meinel
Add a KEY_HAS_HASH define.
299
#endif
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
300
    x = 0x345678L;
301
    p = self->items;
4679.3.77 by John Arbash Meinel
Some code cleanup passes.
302
    // 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.
303
    //       items are strings. I haven't seen a real-world benefit to that
304
    //       yet, though.
4679.3.77 by John Arbash Meinel
Some code cleanup passes.
305
    while (--len >= 0) {
306
        y = PyObject_Hash(*p++);
307
        if (y == -1) /* failure */
308
            return -1;
309
        x = (x ^ y) * mult;
310
        /* the cast might truncate len; that doesn't change hash stability */
311
        mult += (long)(82520L + len + len);
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
312
    }
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
313
    x += 97531L;
314
    if (x == -1)
315
        x = -2;
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
316
#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.
317
    self->hash = x;
4679.3.28 by John Arbash Meinel
Add a KEY_HAS_HASH define.
318
#endif
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
319
    return x;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
320
}
321
322
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
323
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.
324
{
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
325
    PyObject *vt;
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
326
    PyObject *result = NULL;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
327
    
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
328
    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.
329
    if (vt == NULL) {
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
330
        goto done;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
331
    }
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
332
    if (!PyTuple_Check(wt)) {
333
        PyErr_BadInternalCall();
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
334
        goto done;
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
335
    }
336
    /* Now we have 2 tuples to compare, do it */
337
    result = PyTuple_Type.tp_richcompare(vt, wt, op);
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
338
done:
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
339
    Py_XDECREF(vt);
4679.3.18 by John Arbash Meinel
Copy the hash and richcompare implementations, and add some tests.
340
    return result;
341
}
342
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
343
/** Compare two objects to determine if they are equivalent.
344
 * The basic flow is as follows
345
 *  1) First make sure that both objects are StaticTuple instances. If they
346
 *     aren't then cast self to a tuple, and have the tuple do the comparison.
347
 *  2) Special case comparison to Py_None, because it happens to occur fairly
348
 *     often in the test suite.
349
 *  3) Special case when v and w are the same pointer. As we know the answer to
350
 *     all queries without walking individual items.
351
 *  4) For all operations, we then walk the items to find the first paired
352
 *     items that are not equal.
353
 *  5) If all items found are equal, we then check the length of self and
354
 *     other to determine equality.
355
 *  6) If an item differs, then we apply "op" to those last two items. (eg.
356
 *     StaticTuple(A, B) > StaticTuple(A, C) iff B > C)
357
 */
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
358
359
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
360
StaticTuple_richcompare(PyObject *v, PyObject *w, int op)
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
361
{
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
362
    StaticTuple *v_st, *w_st;
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
363
    Py_ssize_t vlen, wlen, min_len, i;
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
364
    PyObject *v_obj, *w_obj;
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
365
    richcmpfunc string_richcompare;
366
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
367
    if (!StaticTuple_CheckExact(v)) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
368
        /* This has never triggered, according to python-dev it seems this
369
         * might trigger if '__op__' is defined but '__rop__' is not, sort of
370
         * case. Such as "None == StaticTuple()"
371
         */
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
372
        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.
373
        Py_INCREF(Py_NotImplemented);
374
        return Py_NotImplemented;
375
    }
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
376
    v_st = (StaticTuple *)v;
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
377
    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.
378
        /* The most common case */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
379
        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.
380
    } else if (PyTuple_Check(w)) {
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
381
        /* One of v or w is a tuple, so we go the 'slow' route and cast up to
382
         * tuples to compare.
383
         */
4679.3.23 by John Arbash Meinel
A bit more testing shows that we are comparing Key to tuples fairly often.
384
        /* TODO: This seems to be triggering more than I thought it would...
385
         *       We probably want to optimize comparing self to other when
386
         *       other is a tuple.
387
         */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
388
        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.
389
    } else if (w == Py_None) {
390
        // None is always less than the object
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
391
        switch (op) {
392
        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.
393
            Py_INCREF(Py_True);
394
            return Py_True;
395
        case Py_EQ:case Py_LT:case Py_LE:
396
            Py_INCREF(Py_False);
397
            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
398
    default: // Should never happen
399
        return Py_NotImplemented;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
400
        }
4679.3.45 by John Arbash Meinel
Do some work to handle comparison to object that aren't tuples or strings.
401
    } else {
402
        /* We don't special case this comparison, we just let python handle
403
         * it.
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
404
         */
405
         Py_INCREF(Py_NotImplemented);
406
         return Py_NotImplemented;
407
    }
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
408
    /* 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.
409
     * 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.
410
     * 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.
411
     */
412
    if (v == w) {
413
        /* Identical pointers, we can shortcut this easily. */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
414
        switch (op) {
415
        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.
416
            Py_INCREF(Py_True);
417
            return Py_True;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
418
        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.
419
            Py_INCREF(Py_False);
420
            return Py_False;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
421
        }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
422
    }
4679.5.6 by John Arbash Meinel
Some comment cleanup, implement a special case for Py_EQ when both objects are intrened.
423
    if (op == Py_EQ
424
        && _StaticTuple_is_interned(v_st)
425
        && _StaticTuple_is_interned(w_st))
426
    {
427
        /* If both objects are interned, we know they are different if the
428
         * pointer is not the same, which would have been handled by the
429
         * previous if. No need to compare the entries.
430
         */
431
        Py_INCREF(Py_False);
432
        return Py_False;
433
    }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
434
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
435
    /* The only time we are likely to compare items of different lengths is in
436
     * something like the interned_keys set. However, the hash is good enough
437
     * that it is rare. Note that 'tuple_richcompare' also does not compare
438
     * lengths here.
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
439
     */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
440
    vlen = v_st->size;
441
    wlen = w_st->size;
442
    min_len = (vlen < wlen) ? vlen : wlen;
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
443
    string_richcompare = PyString_Type.tp_richcompare;
444
    for (i = 0; i < min_len; i++) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
445
        PyObject *result = NULL;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
446
        v_obj = StaticTuple_GET_ITEM(v_st, i);
447
        w_obj = StaticTuple_GET_ITEM(w_st, i);
4679.5.7 by John Arbash Meinel
Add a quick shortcut when comparing item-by-item.
448
        if (v_obj == w_obj) {
449
            /* Shortcut case, these must be identical */
450
            continue;
451
        }
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
452
        if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) {
453
            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.
454
        } else if (StaticTuple_CheckExact(v_obj) &&
455
                   StaticTuple_CheckExact(w_obj))
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
456
        {
457
            /* Both are StaticTuple types, so recurse */
458
            result = StaticTuple_richcompare(v_obj, w_obj, Py_EQ);
459
        } else {
460
            /* Not the same type, obviously they won't compare equal */
461
            break;
462
        }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
463
        if (result == NULL) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
464
            return NULL; /* There seems to be an error */
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
465
        }
466
        if (result == Py_NotImplemented) {
467
            Py_DECREF(result);
4679.8.11 by John Arbash Meinel
Handle the case where the recursive call ends up returning NotImplemented.
468
            /* One side must have had a string and the other a StaticTuple.
469
             * This clearly means that they are not equal.
470
             */
471
            if (op == Py_EQ) {
472
                Py_INCREF(Py_False);
473
                return Py_False;
474
            }
475
            result = PyObject_RichCompare(v_obj, w_obj, Py_EQ);
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
476
        }
477
        if (result == Py_False) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
478
            /* This entry is not identical
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
479
             * Shortcut for Py_EQ
480
             */
481
            if (op == Py_EQ) {
482
                return result;
483
            }
484
            Py_DECREF(result);
485
            break;
486
        }
487
        if (result != Py_True) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
488
            /* We don't know *what* richcompare is returning, but it
489
             * isn't something we recognize
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
490
             */
491
            PyErr_BadInternalCall();
492
            Py_DECREF(result);
493
            return NULL;
494
        }
495
        Py_DECREF(result);
496
    }
4679.5.11 by John Arbash Meinel
add a hack-around to handle differences between pyrex 0.9.6 and 0.9.8
497
    if (i >= min_len) {
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
498
        /* We walked off one of the lists, but everything compared equal so
499
         * far. Just compare the size.
500
         */
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
501
        int cmp;
502
        PyObject *res;
503
        switch (op) {
504
        case Py_LT: cmp = vlen <  wlen; break;
505
        case Py_LE: cmp = vlen <= wlen; break;
506
        case Py_EQ: cmp = vlen == wlen; break;
507
        case Py_NE: cmp = vlen != wlen; break;
508
        case Py_GT: cmp = vlen >  wlen; break;
509
        case Py_GE: cmp = vlen >= wlen; break;
510
        default: return NULL; /* cannot happen */
511
        }
512
        if (cmp)
513
            res = Py_True;
514
        else
515
            res = Py_False;
516
        Py_INCREF(res);
517
        return res;
518
    }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
519
    /* The last item differs, shortcut the Py_NE case */
520
    if (op == Py_NE) {
521
        Py_INCREF(Py_True);
522
        return Py_True;
523
    }
524
    /* 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.
525
    if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj))
526
    {
527
        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.
528
    } else if (StaticTuple_CheckExact(v_obj) &&
529
               StaticTuple_CheckExact(w_obj))
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
530
    {
531
        /* Both are StaticTuple types, so recurse */
532
        return StaticTuple_richcompare(v_obj, w_obj, op);
533
    } else {
534
        Py_INCREF(Py_NotImplemented);
535
        return Py_NotImplemented;
536
    }
4679.3.21 by John Arbash Meinel
Implement Key_richcompare directly, rather than thunking to tuples.
537
}
538
539
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
540
static Py_ssize_t
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
541
StaticTuple_length(StaticTuple *self)
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
542
{
4679.3.37 by John Arbash Meinel
Change the Key header a bit. It is simpler if you use unsigned char
543
    return self->size;
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
544
}
545
546
547
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
548
StaticTuple__is_interned(StaticTuple *self)
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
549
{
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
550
    if (_StaticTuple_is_interned(self)) {
4679.3.35 by John Arbash Meinel
Work on making intern() not generate immortal Key objects.
551
        Py_INCREF(Py_True);
552
        return Py_True;
553
    }
554
    Py_INCREF(Py_False);
555
    return Py_False;
556
}
557
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
558
static char StaticTuple__is_interned_doc[] = "_is_interned() => True/False\n"
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
559
    "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.
560
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
561
4759.2.1 by Andrew Bennetts
Implement number.add and coerce to allow concatenation with tuples.
562
int
563
StaticTuple_coerce(PyObject **v, PyObject **w)
564
{
565
	StaticTuple *st;
566
	if (PyTuple_Check(*v)) {
567
		st = (StaticTuple*) StaticTuple_new_constructor(
568
				&StaticTuple_Type, *v, NULL);
569
		if (!st)
570
			return -1;
571
		Py_INCREF(st);
572
		*v = (PyObject*)st;
573
	} else if (StaticTuple_CheckExact(*v))
574
		Py_INCREF(*v);
575
	else
576
		return 1;
577
578
	if (PyTuple_Check(*w)) {
579
		st = (StaticTuple*) StaticTuple_new_constructor(
580
				&StaticTuple_Type, *w, NULL);
581
		if (!st)
582
			return -1;
583
		Py_INCREF(st);
584
		*w = (PyObject*)st;
585
	} else if (StaticTuple_CheckExact(*w))
586
		Py_INCREF(*w);
587
	else
588
		return 1;
589
	return 0;
590
}
591
592
static PyObject *
593
StaticTuple_add(PyObject *v, PyObject *w)
594
{
595
	PyObject *v_t = NULL, *w_t = NULL;
596
	PyObject *tmp_tuple, *result;
597
	 /* StaticTuples and plain tuples may be added (concatenated) to
598
	  * StaticTuples.
599
	  */
600
	if (StaticTuple_CheckExact(v)) {
601
		v_t = StaticTuple_as_tuple((StaticTuple*)v);
602
		if (!v_t)
603
			goto fail;
604
	} else if (PyTuple_Check(v))
605
		v_t = v;
606
	else
607
		goto not_imp;
608
609
	if (StaticTuple_CheckExact(w)) {
610
		w_t = StaticTuple_as_tuple((StaticTuple*)w);
611
		if (!w_t)
612
			goto fail;
613
	} else if (PyTuple_Check(w))
614
		w_t = w;
615
	else
616
		goto not_imp;
617
618
	tmp_tuple = PySequence_Concat(v_t, w_t);
619
	result = StaticTuple_new_constructor(&StaticTuple_Type, tmp_tuple, NULL);
620
	Py_DECREF(tmp_tuple);
621
	Py_INCREF(result);
622
	return result;
623
624
not_imp:
625
	Py_XDECREF(v_t);
626
	Py_XDECREF(w_t);
627
	return Py_NotImplemented;
628
fail:
629
	Py_XDECREF(v_t);
630
	Py_XDECREF(w_t);
631
	return NULL;
632
}
633
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
634
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
635
StaticTuple_item(StaticTuple *self, Py_ssize_t offset)
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
636
{
637
    PyObject *obj;
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
638
    /* We cast to (int) to avoid worrying about whether Py_ssize_t is a
639
     * long long, etc. offsets should never be >2**31 anyway.
640
     */
641
    if (offset < 0) {
642
        PyErr_Format(PyExc_IndexError, "StaticTuple_item does not support"
643
            " negative indices: %d\n", (int)offset);
644
    } else if (offset >= self->size) {
645
        PyErr_Format(PyExc_IndexError, "StaticTuple index out of range"
646
            " %d >= %d", (int)offset, (int)self->size);
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
647
        return NULL;
648
    }
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
649
    obj = (PyObject *)self->items[offset];
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
650
    Py_INCREF(obj);
651
    return obj;
652
}
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
653
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
654
static PyObject *
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
655
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.
656
{
657
    PyObject *as_tuple, *result;
658
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
659
    as_tuple = StaticTuple_as_tuple(self);
4679.3.19 by John Arbash Meinel
implement slicing as a tuple thunk.
660
    if (as_tuple == NULL) {
661
        return NULL;
662
    }
663
    result = PyTuple_Type.tp_as_sequence->sq_slice(as_tuple, ilow, ihigh);
664
    Py_DECREF(as_tuple);
665
    return result;
666
}
667
4679.3.20 by John Arbash Meinel
Implement tp_traverse, and add a soft dependency on meliae to test it.
668
static int
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
669
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.
670
{
671
    Py_ssize_t i;
4679.3.46 by John Arbash Meinel
Play around a bit with changing the hash function.
672
    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.
673
        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.
674
    }
675
    return 0;
676
}
677
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
678
static char StaticTuple_doc[] =
679
    "C implementation of a StaticTuple structure."
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
680
    "\n This is used as StaticTuple(item1, item2, item3)"
681
    "\n This is similar to tuple, less flexible in what it"
682
    "\n supports, but also lighter memory consumption."
683
    "\n Note that the constructor mimics the () form of tuples"
684
    "\n Rather than the 'tuple()' constructor."
685
    "\n  eg. StaticTuple(a, b) == (a, b) == tuple((a, b))";
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
686
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
687
static PyMethodDef StaticTuple_methods[] = {
688
    {"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.
689
    {"intern", (PyCFunction)StaticTuple_Intern, METH_NOARGS, StaticTuple_Intern_doc},
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
690
    {"_is_interned", (PyCFunction)StaticTuple__is_interned, METH_NOARGS,
691
     StaticTuple__is_interned_doc},
4739.4.1 by John Arbash Meinel
Implement StaticTuple.from_sequence()
692
    {"from_sequence", (PyCFunction)StaticTuple_from_sequence,
693
     METH_STATIC | METH_VARARGS,
694
     "Create a StaticTuple from a given sequence. This functions"
695
     " the same as the tuple() constructor."},
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
696
    {NULL, NULL} /* sentinel */
697
};
698
4759.2.1 by Andrew Bennetts
Implement number.add and coerce to allow concatenation with tuples.
699
700
static PyNumberMethods StaticTuple_as_number = {
701
	(binaryfunc) StaticTuple_add,	/* nb_add */
702
	0, 		/* nb_subtract */
703
	0, 		/* nb_multiply */
704
	0,	/* nb_divide */
705
	0,		/* nb_remainder */
706
	0,		/* nb_divmod */
707
	0,		/* nb_power */
708
	0,			/* nb_negative */
709
	0,			/* nb_positive */
710
	0,			/* nb_absolute */
711
	0,		/* nb_nonzero */
712
	0,					/* nb_invert */
713
	0,					/* nb_lshift */
714
	0,					/* nb_rshift */
715
	0,					/* nb_and */
716
	0,					/* nb_xor */
717
	0,					/* nb_or */
718
	StaticTuple_coerce,				/* nb_coerce */
719
};
720
	
721
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
722
static PySequenceMethods StaticTuple_as_sequence = {
723
    (lenfunc)StaticTuple_length,            /* sq_length */
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
724
    0,                              /* sq_concat */
725
    0,                              /* sq_repeat */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
726
    (ssizeargfunc)StaticTuple_item,         /* sq_item */
727
    (ssizessizeargfunc)StaticTuple_slice,   /* sq_slice */
4679.3.17 by John Arbash Meinel
Implement some of the sequence items.
728
    0,                              /* sq_ass_item */
729
    0,                              /* sq_ass_slice */
730
    0,                              /* sq_contains */
731
};
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
732
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
733
/* 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.
734
 *       The only thing we really want to support from there is mp_subscript,
735
 *       so that we could support extended slicing (foo[::2]). Not worth it
736
 *       yet, though.
4679.5.5 by John Arbash Meinel
Review feedback from Andrew Bennetts.
737
 */
738
4679.4.1 by John Arbash Meinel
Handle some issues with static/etc to get things to build on babune.
739
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
740
PyTypeObject StaticTuple_Type = {
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
741
    PyObject_HEAD_INIT(NULL)
742
    0,                                           /* ob_size */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
743
    "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.
744
    sizeof(StaticTuple),                         /* tp_basicsize */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
745
    sizeof(PyObject *),                          /* tp_itemsize */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
746
    (destructor)StaticTuple_dealloc,             /* tp_dealloc */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
747
    0,                                           /* tp_print */
748
    0,                                           /* tp_getattr */
749
    0,                                           /* tp_setattr */
750
    0,                                           /* tp_compare */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
751
    (reprfunc)StaticTuple_repr,                  /* tp_repr */
4759.2.1 by Andrew Bennetts
Implement number.add and coerce to allow concatenation with tuples.
752
    &StaticTuple_as_number,                      /* tp_as_number */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
753
    &StaticTuple_as_sequence,                    /* tp_as_sequence */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
754
    0,                                           /* tp_as_mapping */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
755
    (hashfunc)StaticTuple_hash,                  /* tp_hash */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
756
    0,                                           /* tp_call */
757
    0,                                           /* tp_str */
4747.1.1 by John Arbash Meinel
On Windows w/ Python2.5 PyObject_GenericGetAttr is an external DLL function,
758
    0,                                           /* tp_getattro */
4679.3.16 by John Arbash Meinel
Initial work for a Key class.
759
    0,                                           /* tp_setattro */
760
    0,                                           /* tp_as_buffer */
761
    Py_TPFLAGS_DEFAULT,                          /* tp_flags*/
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
762
    StaticTuple_doc,                             /* tp_doc */
4679.3.20 by John Arbash Meinel
Implement tp_traverse, and add a soft dependency on meliae to test it.
763
    /* gc.get_referents checks the IS_GC flag before it calls tp_traverse
764
     * And we don't include this object in the garbage collector because we
765
     * know it doesn't create cycles. However, 'meliae' will follow
766
     * tp_traverse, even if the object isn't GC, and we want that.
767
     */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
768
    (traverseproc)StaticTuple_traverse,          /* tp_traverse */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
769
    0,                                           /* tp_clear */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
770
    StaticTuple_richcompare,                     /* tp_richcompare */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
771
    0,                                           /* tp_weaklistoffset */
4679.3.76 by John Arbash Meinel
Rename StaticTupleInterner => SimpleSet.
772
    // without implementing tp_iter, Python will fall back to PySequence*
773
    // which seems to work ok, we may need something faster/lighter in the
774
    // future.
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
775
    0,                                           /* tp_iter */
776
    0,                                           /* tp_iternext */
4679.3.42 by John Arbash Meinel
Implement comparison support when using nested StaticTuple objects.
777
    StaticTuple_methods,                         /* tp_methods */
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
778
    0,                                           /* tp_members */
779
    0,                                           /* tp_getset */
780
    0,                                           /* tp_base */
781
    0,                                           /* tp_dict */
782
    0,                                           /* tp_descr_get */
783
    0,                                           /* tp_descr_set */
784
    0,                                           /* tp_dictoffset */
785
    0,                                           /* tp_init */
786
    0,                                           /* tp_alloc */
4679.5.9 by John Arbash Meinel
NEWS entry for StaticTuple class.
787
    StaticTuple_new_constructor,                 /* tp_new */
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
788
};
789
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
790
4679.3.41 by John Arbash Meinel
Finish switching the naming to StaticTuple.
791
static PyMethodDef static_tuple_c_methods[] = {
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
792
    {NULL, NULL}
793
};
794
795
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
796
static void
4679.3.51 by John Arbash Meinel
Add a _static_tuple_c.pxd file to define the C api to pyrex code.
797
setup_interned_tuples(PyObject *m)
4679.3.1 by John Arbash Meinel
Start working on a Keys type.
798
{
4679.3.76 by John Arbash Meinel
Rename StaticTupleInterner => SimpleSet.
799
    _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.
800
    if (_interned_tuples != NULL) {
801
        Py_INCREF(_interned_tuples);
802
        PyModule_AddObject(m, "_interned_tuples", _interned_tuples);
4679.3.29 by John Arbash Meinel
Start work on implementing a Key.intern() function.
803
    }
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
804
}
805
806
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
807
static void
808
setup_empty_tuple(PyObject *m)
809
{
810
    StaticTuple *stuple;
811
    if (_interned_tuples == NULL) {
812
        fprintf(stderr, "You need to call setup_interned_tuples() before"
813
                " setup_empty_tuple, because we intern it.\n");
814
    }
815
    // We need to create the empty tuple
816
    stuple = (StaticTuple *)StaticTuple_New(0);
817
    _empty_tuple = StaticTuple_Intern(stuple);
818
    assert(_empty_tuple == stuple);
819
    // At this point, refcnt is 2: 1 from New(), and 1 from the return from
820
    // intern(). We will keep 1 for the _empty_tuple global, and use the other
821
    // for the module reference.
822
    PyModule_AddObject(m, "_empty_tuple", (PyObject *)_empty_tuple);
823
}
824
825
static int
826
_StaticTuple_CheckExact(PyObject *obj)
827
{
828
    return StaticTuple_CheckExact(obj);
829
}
830
831
static void
832
setup_c_api(PyObject *m)
833
{
834
    _export_function(m, "StaticTuple_New", StaticTuple_New,
835
        "StaticTuple *(Py_ssize_t)");
836
    _export_function(m, "StaticTuple_Intern", StaticTuple_Intern,
837
        "StaticTuple *(StaticTuple *)");
4739.4.1 by John Arbash Meinel
Implement StaticTuple.from_sequence()
838
    _export_function(m, "StaticTuple_FromSequence", StaticTuple_FromSequence,
839
        "StaticTuple *(PyObject *)");
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
840
    _export_function(m, "_StaticTuple_CheckExact", _StaticTuple_CheckExact,
841
        "int(PyObject *)");
842
}
843
844
4679.5.11 by John Arbash Meinel
add a hack-around to handle differences between pyrex 0.9.6 and 0.9.8
845
static int
4736.1.1 by John Arbash Meinel
Py_ssize_t and its associated function typedefs are not available w/ python 2.4
846
_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
847
{
848
    /* Work around an incompatibility in how pyrex 0.9.6 exports a module,
849
     * versus how pyrex 0.9.8 and cython 0.11 export it.
850
     * Namely 0.9.6 exports import__simple_set_pyx and tries to
851
     * "import _simple_set_pyx" but it is available only as
852
     * "import bzrlib._simple_set_pyx"
853
     * It is a shame to hack up sys.modules, but that is what we've got to do.
854
     */
855
    PyObject *sys_module = NULL, *modules = NULL, *set_module = NULL;
856
    int retval = -1;
857
858
    /* Clear out the current ImportError exception, and try again. */
859
    PyErr_Clear();
860
    /* Note that this only seems to work if somewhere else imports
861
     * bzrlib._simple_set_pyx before importing bzrlib._static_tuple_c
862
     */
863
    set_module = PyImport_ImportModule("bzrlib._simple_set_pyx");
864
    if (set_module == NULL) {
865
	// fprintf(stderr, "Failed to import bzrlib._simple_set_pyx\n");
866
        goto end;
867
    }
868
    /* Add the _simple_set_pyx into sys.modules at the appropriate location. */
869
    sys_module = PyImport_ImportModule("sys");
870
    if (sys_module == NULL) {
871
    	// fprintf(stderr, "Failed to import sys\n");
872
        goto end;
873
    }
874
    modules = PyObject_GetAttrString(sys_module, "modules");
875
    if (modules == NULL || !PyDict_Check(modules)) {
876
    	// fprintf(stderr, "Failed to find sys.modules\n");
877
        goto end;
878
    }
879
    PyDict_SetItemString(modules, "_simple_set_pyx", set_module);
880
    /* Now that we have hacked it in, try the import again. */
881
    retval = import_bzrlib___simple_set_pyx();
882
end:
883
    Py_XDECREF(set_module);
884
    Py_XDECREF(sys_module);
885
    Py_XDECREF(modules);
886
    return retval;
887
}
888
889
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
890
PyMODINIT_FUNC
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
891
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.
892
{
893
    PyObject* m;
894
4747.1.1 by John Arbash Meinel
On Windows w/ Python2.5 PyObject_GenericGetAttr is an external DLL function,
895
    StaticTuple_Type.tp_getattro = PyObject_GenericGetAttr;
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
896
    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.
897
        return;
898
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
899
    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.
900
                       "C implementation of a StaticTuple structure");
901
    if (m == NULL)
902
      return;
903
904
    Py_INCREF(&StaticTuple_Type);
905
    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
906
    if (import_bzrlib___simple_set_pyx() == -1
907
        && _workaround_pyrex_096() == -1)
908
    {
4679.3.81 by John Arbash Meinel
Fix up _simple_set_pyx.pyx to be compatible with pyrex again.
909
        return;
910
    }
4679.3.74 by John Arbash Meinel
Revert back to before I started trying to move to pyrex/cython code.
911
    setup_interned_tuples(m);
912
    setup_empty_tuple(m);
913
    setup_c_api(m);
4679.3.47 by John Arbash Meinel
Work out how to expose the C api using the Python PyCObject interface.
914
}