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