/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/_static_tuple_c.c

MergeĀ lp:bzr.

Show diffs side-by-side

added added

removed removed

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