~bzr-pqm/bzr/bzr.dev

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