~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_static_tuple_c.c

  • Committer: John Arbash Meinel
  • Date: 2009-10-02 20:32:50 UTC
  • mto: (4679.6.1 2.1-export-c-api)
  • mto: This revision was merged to the branch mainline in revision 4735.
  • Revision ID: john@arbash-meinel.com-20091002203250-q6iv6o2mwjqp4g53
Add __iter__ support.

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 "_static_tuple_c.h"
 
24
#include "_export_c_api.h"
 
25
 
 
26
#include "python-compat.h"
 
27
 
 
28
#if defined(__GNUC__)
 
29
#   define inline __inline__
 
30
#elif defined(_MSC_VER)
 
31
#   define inline __inline
 
32
#else
 
33
#   define inline
 
34
#endif
 
35
 
 
36
 
 
37
/* The one and only StaticTuple with no values */
 
38
static StaticTuple *_empty_tuple = NULL;
 
39
static PyObject *_interned_tuples = NULL;
 
40
 
 
41
 
 
42
static inline int
 
43
_StaticTuple_is_interned(StaticTuple *self)
 
44
{
 
45
    return self->flags & STATIC_TUPLE_INTERNED_FLAG;
 
46
}
 
47
 
 
48
 
 
49
 
 
50
static PyObject *
 
51
StaticTuple_as_tuple(StaticTuple *self)
 
52
{
 
53
    PyObject *tpl = NULL, *obj = NULL;
 
54
    int i, len;
 
55
 
 
56
    len = self->size;
 
57
    tpl = PyTuple_New(len);
 
58
    if (!tpl) {
 
59
        /* Malloc failure */
 
60
        return NULL;
 
61
    }
 
62
    for (i = 0; i < len; ++i) {
 
63
        obj = (PyObject *)self->items[i];
 
64
        Py_INCREF(obj);
 
65
        PyTuple_SET_ITEM(tpl, i, obj);
 
66
    }
 
67
    return tpl;
 
68
}
 
69
 
 
70
 
 
71
static char StaticTuple_as_tuple_doc[] = "as_tuple() => tuple";
 
72
 
 
73
static StaticTuple *
 
74
StaticTuple_Intern(StaticTuple *self)
 
75
{
 
76
    PyObject *unique_key = NULL;
 
77
 
 
78
    if (_interned_tuples == NULL) {
 
79
        Py_INCREF(self);
 
80
        return self;
 
81
    }
 
82
    if (_StaticTuple_is_interned(self)) {
 
83
        // Already interned
 
84
        Py_INCREF(self);
 
85
        return self;
 
86
    }
 
87
    unique_key = PyDict_GetItem((PyObject *)_interned_tuples, (PyObject *)self);
 
88
    if (unique_key) {
 
89
        // An entry already existed, return it, instead of self
 
90
        Py_INCREF(unique_key);
 
91
        return (StaticTuple *)unique_key;
 
92
    }
 
93
    // An entry did not exist, make 'self' the unique item
 
94
    if (PyDict_SetItem(_interned_tuples, (PyObject *)self, (PyObject *)self) < 0) {
 
95
        // Suppress an error
 
96
        PyErr_Clear();
 
97
        Py_INCREF(self);
 
98
        return self;
 
99
    }
 
100
    // self was added to the dict, return it.
 
101
    Py_INCREF(self);
 
102
    self->flags |= STATIC_TUPLE_INTERNED_FLAG;
 
103
    // The two references in the dict do not count, so that the StaticTuple object
 
104
    // does not become immortal just because it was interned.
 
105
    Py_REFCNT(self) -= 2;
 
106
    return self;
 
107
}
 
108
 
 
109
static char StaticTuple_Intern_doc[] = "intern() => unique StaticTuple\n"
 
110
    "Return a 'canonical' StaticTuple object.\n"
 
111
    "Similar to intern() for strings, this makes sure there\n"
 
112
    "is only one StaticTuple object for a given value\n."
 
113
    "Common usage is:\n"
 
114
    "  key = StaticTuple('foo', 'bar').intern()\n";
 
115
 
 
116
 
 
117
static void
 
118
StaticTuple_dealloc(StaticTuple *self)
 
119
{
 
120
    int i, len;
 
121
 
 
122
    if (_StaticTuple_is_interned(self)) {
 
123
        /* revive dead object temporarily for DelItem */
 
124
        Py_REFCNT(self) = 3;
 
125
        if (PyDict_DelItem(_interned_tuples, (PyObject *)self) != 0) {
 
126
            Py_FatalError("deletion of interned StaticTuple failed");
 
127
        }
 
128
    }
 
129
    len = self->size;
 
130
    for (i = 0; i < len; ++i) {
 
131
        Py_XDECREF(self->items[i]);
 
132
    }
 
133
    Py_TYPE(self)->tp_free((PyObject *)self);
 
134
}
 
135
 
 
136
 
 
137
/* Similar to PyTuple_New() */
 
138
static StaticTuple *
 
139
StaticTuple_New(Py_ssize_t size)
 
140
{
 
141
    StaticTuple *stuple;
 
142
    if (size < 0) {
 
143
        PyErr_BadInternalCall();
 
144
        return NULL;
 
145
    }
 
146
 
 
147
    if (size == 0 && _empty_tuple != NULL) {
 
148
        Py_INCREF(_empty_tuple);
 
149
        return _empty_tuple;
 
150
    }
 
151
    /* Note that we use PyObject_NewVar because we want to allocate a variable
 
152
     * width entry. However we *aren't* truly a PyVarObject because we don't
 
153
     * use a long for ob_size. Instead we use a plain 'size' that is an int,
 
154
     * and will be overloaded with flags in the future.
 
155
     * As such we do the alloc, and then have to clean up anything it does
 
156
     * incorrectly.
 
157
     */
 
158
    stuple = PyObject_NewVar(StaticTuple, &StaticTuple_Type, size);
 
159
    if (stuple == NULL) {
 
160
        return NULL;
 
161
    }
 
162
    stuple->size = size;
 
163
    stuple->flags = 0;
 
164
    stuple->_unused0 = 0;
 
165
    stuple->_unused1 = 0;
 
166
    if (size > 0) {
 
167
        memset(stuple->items, 0, sizeof(PyObject *) * size);
 
168
    }
 
169
#if STATIC_TUPLE_HAS_HASH
 
170
    stuple->hash = -1;
 
171
#endif
 
172
    return stuple;
 
173
}
 
174
 
 
175
 
 
176
static PyObject *
 
177
StaticTuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
178
{
 
179
    StaticTuple *self;
 
180
    PyObject *obj = NULL;
 
181
    Py_ssize_t i, len = 0;
 
182
    int is_all_str;
 
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 key bits");
 
197
        return NULL;
 
198
    }
 
199
    self = (StaticTuple *)StaticTuple_New(len);
 
200
    if (self == NULL) {
 
201
        return NULL;
 
202
    }
 
203
    is_all_str = 1;
 
204
    for (i = 0; i < len; ++i) {
 
205
        obj = PyTuple_GET_ITEM(args, i);
 
206
        if (!PyString_CheckExact(obj)) {
 
207
            is_all_str = 0;
 
208
            if (!StaticTuple_CheckExact(obj)) {
 
209
                PyErr_SetString(PyExc_TypeError, "StaticTuple.__init__(...)"
 
210
                    " requires that all key bits are strings or StaticTuple.");
 
211
                /* TODO: What is the proper way to dealloc ? */
 
212
                type->tp_dealloc((PyObject *)self);
 
213
                return NULL;
 
214
            }
 
215
        }
 
216
        Py_INCREF(obj);
 
217
        self->items[i] = obj;
 
218
    }
 
219
    if (is_all_str) {
 
220
        self->flags |= STATIC_TUPLE_ALL_STRING;
 
221
    }
 
222
    return (PyObject *)self;
 
223
}
 
224
 
 
225
static PyObject *
 
226
StaticTuple_repr(StaticTuple *self)
 
227
{
 
228
    PyObject *as_tuple, *result;
 
229
 
 
230
    as_tuple = StaticTuple_as_tuple(self);
 
231
    if (as_tuple == NULL) {
 
232
        return NULL;
 
233
    }
 
234
    result = PyObject_Repr(as_tuple);
 
235
    Py_DECREF(as_tuple);
 
236
    return result;
 
237
}
 
238
 
 
239
static long
 
240
StaticTuple_hash(StaticTuple *self)
 
241
{
 
242
    /* adapted from tuplehash(), is the specific hash value considered
 
243
     * 'stable'?
 
244
     */
 
245
        register long x, y;
 
246
        Py_ssize_t len = self->size;
 
247
        PyObject **p;
 
248
        long mult = 1000003L;
 
249
 
 
250
#if STATIC_TUPLE_HAS_HASH
 
251
    if (self->hash != -1) {
 
252
        return self->hash;
 
253
    }
 
254
#endif
 
255
        x = 0x345678L;
 
256
        p = self->items;
 
257
    if (self->flags & STATIC_TUPLE_ALL_STRING
 
258
        && self->flags & STATIC_TUPLE_DID_HASH) {
 
259
        /* If we know that we only reference strings, and we've already
 
260
         * computed the hash one time before, then we know all the strings will
 
261
         * have valid hash entries, and we can just compute, no branching
 
262
         * logic.
 
263
         */
 
264
        while (--len >= 0) {
 
265
            y = ((PyStringObject*)(*p))->ob_shash;
 
266
            x = (x ^ y) * mult;
 
267
            /* the cast might truncate len; that doesn't change hash stability */
 
268
            mult += (long)(82520L + len + len);
 
269
            p++;
 
270
        }
 
271
    } else {
 
272
        while (--len >= 0) {
 
273
            y = PyObject_Hash(*p++);
 
274
            if (y == -1) /* failure */
 
275
                return -1;
 
276
            x = (x ^ y) * mult;
 
277
            /* the cast might truncate len; that doesn't change hash stability */
 
278
            mult += (long)(82520L + len + len);
 
279
        }
 
280
    }
 
281
        x += 97531L;
 
282
        if (x == -1)
 
283
                x = -2;
 
284
#if STATIC_TUPLE_HAS_HASH
 
285
    if (self->hash != -1) {
 
286
        if (self->hash != x) {
 
287
            fprintf(stderr, "hash changed: %d => %d\n", self->hash, x);
 
288
        }
 
289
    }
 
290
    self->hash = x;
 
291
#endif
 
292
    self->flags |= STATIC_TUPLE_DID_HASH;
 
293
        return x;
 
294
}
 
295
 
 
296
static PyObject *
 
297
StaticTuple_richcompare_to_tuple(StaticTuple *v, PyObject *wt, int op)
 
298
{
 
299
    PyObject *vt;
 
300
    PyObject *result = NULL;
 
301
    
 
302
    vt = StaticTuple_as_tuple((StaticTuple *)v);
 
303
    if (vt == NULL) {
 
304
        goto Done;
 
305
    }
 
306
    if (!PyTuple_Check(wt)) {
 
307
        PyErr_BadInternalCall();
 
308
        result = NULL;
 
309
        goto Done;
 
310
    }
 
311
    /* Now we have 2 tuples to compare, do it */
 
312
    result = PyTuple_Type.tp_richcompare(vt, wt, op);
 
313
Done:
 
314
    Py_XDECREF(vt);
 
315
    return result;
 
316
}
 
317
 
 
318
 
 
319
static PyObject *
 
320
StaticTuple_richcompare(PyObject *v, PyObject *w, int op)
 
321
{
 
322
    StaticTuple *vk, *wk;
 
323
    Py_ssize_t vlen, wlen, min_len, i;
 
324
    PyObject *v_obj, *w_obj;
 
325
    richcmpfunc string_richcompare;
 
326
 
 
327
    if (!StaticTuple_CheckExact(v)) {
 
328
        /* This has never triggered, according to python-dev it seems this
 
329
         * might trigger if '__op__' is defined but '__rop__' is not, sort of
 
330
         * case. Such as "None == StaticTuple()"
 
331
         */
 
332
        fprintf(stderr, "self is not StaticTuple\n");
 
333
        Py_INCREF(Py_NotImplemented);
 
334
        return Py_NotImplemented;
 
335
    }
 
336
    vk = (StaticTuple *)v;
 
337
    if (StaticTuple_CheckExact(w)) {
 
338
        /* The most common case */
 
339
        wk = (StaticTuple*)w;
 
340
    } else if (PyTuple_Check(w)) {
 
341
        /* One of v or w is a tuple, so we go the 'slow' route and cast up to
 
342
         * tuples to compare.
 
343
         */
 
344
        /* TODO: This seems to be triggering more than I thought it would...
 
345
         *       We probably want to optimize comparing self to other when
 
346
         *       other is a tuple.
 
347
         */
 
348
        return StaticTuple_richcompare_to_tuple(vk, w, op);
 
349
    } else if (w == Py_None) {
 
350
        // None is always less than the object
 
351
                switch (op) {
 
352
                case Py_NE:case Py_GT:case Py_GE:
 
353
            Py_INCREF(Py_True);
 
354
            return Py_True;
 
355
        case Py_EQ:case Py_LT:case Py_LE:
 
356
            Py_INCREF(Py_False);
 
357
            return Py_False;
 
358
                }
 
359
    } else {
 
360
        /* We don't special case this comparison, we just let python handle
 
361
         * it.
 
362
         */
 
363
         Py_INCREF(Py_NotImplemented);
 
364
         return Py_NotImplemented;
 
365
    }
 
366
    /* Now we know that we have 2 StaticTuple objects, so let's compare them.
 
367
     * This code is somewhat borrowed from tuplerichcompare, except we know our
 
368
     * objects are limited in scope, so we can inline some comparisons.
 
369
     */
 
370
    if (v == w) {
 
371
        /* Identical pointers, we can shortcut this easily. */
 
372
                switch (op) {
 
373
                case Py_EQ:case Py_LE:case Py_GE:
 
374
            Py_INCREF(Py_True);
 
375
            return Py_True;
 
376
                case Py_NE:case Py_LT:case Py_GT:
 
377
            Py_INCREF(Py_False);
 
378
            return Py_False;
 
379
                }
 
380
    }
 
381
    /* TODO: if STATIC_TUPLE_INTERNED_FLAG is set on both objects and they are
 
382
     *       not the same pointer, then we know they aren't the same object
 
383
     *       without having to do sub-by-sub comparison.
 
384
     */
 
385
 
 
386
    /* It will be rare that we compare tuples of different lengths, so we don't
 
387
     * start by optimizing the length comparision, same as the tuple code
 
388
     * TODO: Interning may change this, because we'll be comparing lots of
 
389
     *       different StaticTuple objects in the intern dict
 
390
     */
 
391
    vlen = vk->size;
 
392
    wlen = wk->size;
 
393
        min_len = (vlen < wlen) ? vlen : wlen;
 
394
    string_richcompare = PyString_Type.tp_richcompare;
 
395
    for (i = 0; i < min_len; i++) {
 
396
        PyObject *result = NULL;
 
397
        v_obj = StaticTuple_GET_ITEM(vk, i);
 
398
        w_obj = StaticTuple_GET_ITEM(wk, i);
 
399
        if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) {
 
400
            result = string_richcompare(v_obj, w_obj, Py_EQ);
 
401
        } else if (StaticTuple_CheckExact(v_obj) &&
 
402
                   StaticTuple_CheckExact(w_obj))
 
403
        {
 
404
            /* Both are StaticTuple types, so recurse */
 
405
            result = StaticTuple_richcompare(v_obj, w_obj, Py_EQ);
 
406
        } else {
 
407
            /* Not the same type, obviously they won't compare equal */
 
408
            break;
 
409
        }
 
410
        if (result == NULL) {
 
411
            return NULL; /* There seems to be an error */
 
412
        }
 
413
        if (result == Py_NotImplemented) {
 
414
            PyErr_BadInternalCall();
 
415
            Py_DECREF(result);
 
416
            return NULL;
 
417
        }
 
418
        if (result == Py_False) {
 
419
            /* This entry is not identical
 
420
             * Shortcut for Py_EQ
 
421
             */
 
422
            if (op == Py_EQ) {
 
423
                return result;
 
424
            }
 
425
            Py_DECREF(result);
 
426
            break;
 
427
        }
 
428
        if (result != Py_True) {
 
429
            /* We don't know *what* richcompare is returning, but it
 
430
             * isn't something we recognize
 
431
             */
 
432
            PyErr_BadInternalCall();
 
433
            Py_DECREF(result);
 
434
            return NULL;
 
435
        }
 
436
        Py_DECREF(result);
 
437
    }
 
438
        if (i >= vlen || i >= wlen) {
 
439
        /* We walked off one of the lists, but everything compared equal so
 
440
         * far. Just compare the size.
 
441
         */
 
442
                int cmp;
 
443
                PyObject *res;
 
444
                switch (op) {
 
445
                case Py_LT: cmp = vlen <  wlen; break;
 
446
                case Py_LE: cmp = vlen <= wlen; break;
 
447
                case Py_EQ: cmp = vlen == wlen; break;
 
448
                case Py_NE: cmp = vlen != wlen; break;
 
449
                case Py_GT: cmp = vlen >  wlen; break;
 
450
                case Py_GE: cmp = vlen >= wlen; break;
 
451
                default: return NULL; /* cannot happen */
 
452
                }
 
453
                if (cmp)
 
454
                        res = Py_True;
 
455
                else
 
456
                        res = Py_False;
 
457
                Py_INCREF(res);
 
458
                return res;
 
459
        }
 
460
    /* The last item differs, shortcut the Py_NE case */
 
461
    if (op == Py_NE) {
 
462
        Py_INCREF(Py_True);
 
463
        return Py_True;
 
464
    }
 
465
    /* It is some other comparison, go ahead and do the real check. */
 
466
    if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj))
 
467
    {
 
468
        return string_richcompare(v_obj, w_obj, op);
 
469
    } else if (StaticTuple_CheckExact(v_obj) &&
 
470
               StaticTuple_CheckExact(w_obj))
 
471
    {
 
472
        /* Both are StaticTuple types, so recurse */
 
473
        return StaticTuple_richcompare(v_obj, w_obj, op);
 
474
    } else {
 
475
        Py_INCREF(Py_NotImplemented);
 
476
        return Py_NotImplemented;
 
477
    }
 
478
}
 
479
 
 
480
 
 
481
static Py_ssize_t
 
482
StaticTuple_length(StaticTuple *self)
 
483
{
 
484
    return self->size;
 
485
}
 
486
 
 
487
 
 
488
static PyObject *
 
489
StaticTuple__is_interned(StaticTuple *self)
 
490
{
 
491
    if (_StaticTuple_is_interned(self)) {
 
492
        Py_INCREF(Py_True);
 
493
        return Py_True;
 
494
    }
 
495
    Py_INCREF(Py_False);
 
496
    return Py_False;
 
497
}
 
498
 
 
499
static char StaticTuple__is_interned_doc[] = "_is_interned() => True/False\n"
 
500
    "Check to see if this key has been interned.\n";
 
501
 
 
502
 
 
503
static PyObject *
 
504
StaticTuple_item(StaticTuple *self, Py_ssize_t offset)
 
505
{
 
506
    PyObject *obj;
 
507
    if (offset < 0 || offset >= self->size) {
 
508
        PyErr_SetString(PyExc_IndexError, "StaticTuple index out of range");
 
509
        return NULL;
 
510
    }
 
511
    obj = (PyObject *)self->items[offset];
 
512
    Py_INCREF(obj);
 
513
    return obj;
 
514
}
 
515
 
 
516
static PyObject *
 
517
StaticTuple_slice(StaticTuple *self, Py_ssize_t ilow, Py_ssize_t ihigh)
 
518
{
 
519
    PyObject *as_tuple, *result;
 
520
 
 
521
    as_tuple = StaticTuple_as_tuple(self);
 
522
    if (as_tuple == NULL) {
 
523
        return NULL;
 
524
    }
 
525
    result = PyTuple_Type.tp_as_sequence->sq_slice(as_tuple, ilow, ihigh);
 
526
    Py_DECREF(as_tuple);
 
527
    return result;
 
528
}
 
529
 
 
530
static int
 
531
StaticTuple_traverse(StaticTuple *self, visitproc visit, void *arg)
 
532
{
 
533
    Py_ssize_t i;
 
534
    for (i = self->size; --i >= 0;) {
 
535
        Py_VISIT(self->items[i]);
 
536
    }
 
537
    return 0;
 
538
}
 
539
 
 
540
static char StaticTuple_doc[] =
 
541
    "C implementation of a StaticTuple structure."
 
542
    "\n This is used as StaticTuple(key_bit_1, key_bit_2, key_bit_3, ...)"
 
543
    "\n This is similar to tuple, just less flexible in what it"
 
544
    "\n supports, but also lighter memory consumption.";
 
545
 
 
546
static PyMethodDef StaticTuple_methods[] = {
 
547
    {"as_tuple", (PyCFunction)StaticTuple_as_tuple, METH_NOARGS, StaticTuple_as_tuple_doc},
 
548
    {"intern", (PyCFunction)StaticTuple_Intern, METH_NOARGS, StaticTuple_Intern_doc},
 
549
    {"_is_interned", (PyCFunction)StaticTuple__is_interned, METH_NOARGS,
 
550
     StaticTuple__is_interned_doc},
 
551
    {NULL, NULL} /* sentinel */
 
552
};
 
553
 
 
554
static PySequenceMethods StaticTuple_as_sequence = {
 
555
    (lenfunc)StaticTuple_length,            /* sq_length */
 
556
    0,                              /* sq_concat */
 
557
    0,                              /* sq_repeat */
 
558
    (ssizeargfunc)StaticTuple_item,         /* sq_item */
 
559
    (ssizessizeargfunc)StaticTuple_slice,   /* sq_slice */
 
560
    0,                              /* sq_ass_item */
 
561
    0,                              /* sq_ass_slice */
 
562
    0,                              /* sq_contains */
 
563
};
 
564
 
 
565
 
 
566
PyTypeObject StaticTuple_Type = {
 
567
    PyObject_HEAD_INIT(NULL)
 
568
    0,                                           /* ob_size */
 
569
    "StaticTuple",                               /* tp_name */
 
570
    sizeof(StaticTuple),                         /* tp_basicsize */
 
571
    sizeof(PyObject *),                          /* tp_itemsize */
 
572
    (destructor)StaticTuple_dealloc,             /* tp_dealloc */
 
573
    0,                                           /* tp_print */
 
574
    0,                                           /* tp_getattr */
 
575
    0,                                           /* tp_setattr */
 
576
    0,                                           /* tp_compare */
 
577
    (reprfunc)StaticTuple_repr,                  /* tp_repr */
 
578
    0,                                           /* tp_as_number */
 
579
    &StaticTuple_as_sequence,                    /* tp_as_sequence */
 
580
    0,                                           /* tp_as_mapping */
 
581
    (hashfunc)StaticTuple_hash,                  /* tp_hash */
 
582
    0,                                           /* tp_call */
 
583
    0,                                           /* tp_str */
 
584
    PyObject_GenericGetAttr,                     /* tp_getattro */
 
585
    0,                                           /* tp_setattro */
 
586
    0,                                           /* tp_as_buffer */
 
587
    Py_TPFLAGS_DEFAULT,                          /* tp_flags*/
 
588
    StaticTuple_doc,                             /* tp_doc */
 
589
    /* gc.get_referents checks the IS_GC flag before it calls tp_traverse
 
590
     * And we don't include this object in the garbage collector because we
 
591
     * know it doesn't create cycles. However, 'meliae' will follow
 
592
     * tp_traverse, even if the object isn't GC, and we want that.
 
593
     */
 
594
    (traverseproc)StaticTuple_traverse,          /* tp_traverse */
 
595
    0,                                           /* tp_clear */
 
596
    // TODO: implement richcompare, we should probably be able to compare vs an
 
597
    //       tuple, as well as versus another StaticTuples object.
 
598
    StaticTuple_richcompare,                     /* tp_richcompare */
 
599
    0,                                           /* tp_weaklistoffset */
 
600
    // We could implement this as returning tuples of keys...
 
601
    0,                                           /* tp_iter */
 
602
    0,                                           /* tp_iternext */
 
603
    StaticTuple_methods,                         /* tp_methods */
 
604
    0,                                           /* tp_members */
 
605
    0,                                           /* tp_getset */
 
606
    0,                                           /* tp_base */
 
607
    0,                                           /* tp_dict */
 
608
    0,                                           /* tp_descr_get */
 
609
    0,                                           /* tp_descr_set */
 
610
    0,                                           /* tp_dictoffset */
 
611
    0,                                           /* tp_init */
 
612
    0,                                           /* tp_alloc */
 
613
    StaticTuple_new,                             /* tp_new */
 
614
};
 
615
 
 
616
 
 
617
static char KeyIntern_doc[] = "";
 
618
 
 
619
static PyMethodDef KeyIntern_methods[] = {
 
620
    // {"as_tuple", (PyCFunction)Keys_as_tuple, METH_NOARGS, Keys_as_tuple_doc},
 
621
    {NULL, NULL} /* sentinel */
 
622
};
 
623
 
 
624
// static PySequenceMethods KeyIntern_as_sequence = {
 
625
//     0, //(lenfunc)Keys_length,           /* sq_length */
 
626
//     0,                              /* sq_concat */
 
627
//     0,                              /* sq_repeat */
 
628
//     0, //(ssizeargfunc)Keys_item,        /* sq_item */
 
629
//     0,                              /* sq_slice */
 
630
//     0,                              /* sq_ass_item */
 
631
//     0,                              /* sq_ass_slice */
 
632
//     0,                              /* sq_contains */
 
633
// };
 
634
 
 
635
// static PyTypeObject KeyIntern_Type = {
 
636
//     PyObject_HEAD_INIT(NULL)
 
637
//     0,                                           /* ob_size */
 
638
//     "KeyIntern",                                 /* tp_name */
 
639
//     sizeof(KeyIntern) - sizeof(Key *),           /* tp_basicsize */
 
640
//     sizeof(Key *),                               /* tp_itemsize */
 
641
//     0, //(destructor)Keys_dealloc,               /* tp_dealloc */
 
642
//     0,                                           /* tp_print */
 
643
//     0,                                           /* tp_getattr */
 
644
//     0,                                           /* tp_setattr */
 
645
//     0,                                           /* tp_compare */
 
646
//     // TODO: implement repr() and possibly str()
 
647
//     0, //(reprfunc)Keys_repr,                         /* tp_repr */
 
648
//     0,                                           /* tp_as_number */
 
649
//     &KeyIntern_as_sequence,                      /* tp_as_sequence */
 
650
//     0,                                           /* tp_as_mapping */
 
651
//     0, //(hashfunc)Keys_hash,                         /* tp_hash */
 
652
//     0,                                           /* tp_call */
 
653
//     0,                                           /* tp_str */
 
654
//     PyObject_GenericGetAttr,                     /* tp_getattro */
 
655
//     0,                                           /* tp_setattro */
 
656
//     0,                                           /* tp_as_buffer */
 
657
//     Py_TPFLAGS_DEFAULT,                          /* tp_flags*/
 
658
//     0, // Keys_doc,                                    /* tp_doc */
 
659
//     /* See Key_traverse for why we have this, even though we aren't GC */
 
660
//     0, //(traverseproc)Keys_traverse,                 /* tp_traverse */
 
661
//     0,                                           /* tp_clear */
 
662
//     // TODO: implement richcompare, we should probably be able to compare vs an
 
663
//     //       tuple, as well as versus another Keys object.
 
664
//     0, //Keys_richcompare,                            /* tp_richcompare */
 
665
//     0,                                           /* tp_weaklistoffset */
 
666
//     // We could implement this as returning tuples of keys...
 
667
//     0,                                           /* tp_iter */
 
668
//     0,                                           /* tp_iternext */
 
669
//     KeyIntern_methods,                           /* tp_methods */
 
670
//     0,                                           /* tp_members */
 
671
//     0,                                           /* tp_getset */
 
672
//     0,                                           /* tp_base */
 
673
//     0,                                           /* tp_dict */
 
674
//     0,                                           /* tp_descr_get */
 
675
//     0,                                           /* tp_descr_set */
 
676
//     0,                                           /* tp_dictoffset */
 
677
//     0,                                           /* tp_init */
 
678
//     0,                                           /* tp_alloc */
 
679
//     0, //Keys_new,                                    /* tp_new */
 
680
// };
 
681
 
 
682
 
 
683
static PyMethodDef static_tuple_c_methods[] = {
 
684
//    {"unique_lcs_c", py_unique_lcs, METH_VARARGS},
 
685
//    {"recurse_matches_c", py_recurse_matches, METH_VARARGS},
 
686
    {NULL, NULL}
 
687
};
 
688
 
 
689
 
 
690
static void
 
691
setup_interned_tuples(PyObject *m)
 
692
{
 
693
    _interned_tuples = PyDict_New();
 
694
    if (_interned_tuples != NULL) {
 
695
        Py_INCREF(_interned_tuples);
 
696
        PyModule_AddObject(m, "_interned_tuples", _interned_tuples);
 
697
    }
 
698
}
 
699
 
 
700
 
 
701
static void
 
702
setup_empty_tuple(PyObject *m)
 
703
{
 
704
    StaticTuple *stuple;
 
705
    if (_interned_tuples == NULL) {
 
706
        fprintf(stderr, "You need to call setup_interned_tuples() before"
 
707
                " setup_empty_tuple, because we intern it.\n");
 
708
    }
 
709
    // We need to create the empty tuple
 
710
    stuple = (StaticTuple *)StaticTuple_New(0);
 
711
    stuple->flags = STATIC_TUPLE_ALL_STRING;
 
712
    _empty_tuple = StaticTuple_Intern(stuple);
 
713
    assert(_empty_tuple == stuple);
 
714
    // At this point, refcnt is 2: 1 from New(), and 1 from the return from
 
715
    // intern(). We will keep 1 for the _empty_tuple global, and use the other
 
716
    // for the module reference.
 
717
    PyModule_AddObject(m, "_empty_tuple", (PyObject *)_empty_tuple);
 
718
}
 
719
 
 
720
static int
 
721
_StaticTuple_CheckExact(PyObject *obj)
 
722
{
 
723
    return StaticTuple_CheckExact(obj);
 
724
}
 
725
 
 
726
static void
 
727
setup_c_api(PyObject *m)
 
728
{
 
729
    _export_function(m, "StaticTuple_New", StaticTuple_New,
 
730
        "StaticTuple *(Py_ssize_t)");
 
731
    _export_function(m, "StaticTuple_Intern", StaticTuple_Intern,
 
732
        "StaticTuple *(StaticTuple *)");
 
733
    _export_function(m, "_StaticTuple_CheckExact", _StaticTuple_CheckExact,
 
734
        "int(PyObject *)");
 
735
}
 
736
 
 
737
 
 
738
PyMODINIT_FUNC
 
739
init_static_tuple_c(void)
 
740
{
 
741
    PyObject* m;
 
742
 
 
743
    if (PyType_Ready(&StaticTuple_Type) < 0)
 
744
        return;
 
745
    //if (PyType_Ready(&KeyIntern_Type) < 0)
 
746
    //    return;
 
747
 
 
748
    m = Py_InitModule3("_static_tuple_c", static_tuple_c_methods,
 
749
                       "C implementation of a StaticTuple structure");
 
750
    if (m == NULL)
 
751
      return;
 
752
 
 
753
    Py_INCREF(&StaticTuple_Type);
 
754
    PyModule_AddObject(m, "StaticTuple", (PyObject *)&StaticTuple_Type);
 
755
    setup_interned_tuples(m);
 
756
    setup_empty_tuple(m);
 
757
    setup_c_api(m);
 
758
}