~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_static_tuple_c.c

Implement comparison support when using nested StaticTuple objects.

Show diffs side-by-side

added added

removed removed

Lines of Context:
156
156
    key->flags = 0;
157
157
    key->_unused0 = 0;
158
158
    key->_unused1 = 0;
159
 
    memset(key->key_bits, 0, sizeof(PyStringObject *) * size);
 
159
    memset(key->key_bits, 0, sizeof(PyObject *) * size);
160
160
#if STATIC_TUPLE_HAS_HASH
161
161
    key->hash = -1;
162
162
#endif
180
180
        return NULL;
181
181
    }
182
182
    len = PyTuple_GET_SIZE(args);
183
 
    if (len <= 0 || len > 256) {
 
183
    if (len < 0 || len > 255) {
184
184
        /* Too big or too small */
185
185
        PyErr_SetString(PyExc_ValueError, "StaticTuple.__init__(...)"
186
 
            " takes from 1 to 256 key bits");
 
186
            " takes from 0 to 255 key bits");
187
187
        return NULL;
188
188
    }
189
189
    self = (StaticTuple *)(type->tp_alloc(type, len));
199
199
#endif
200
200
    for (i = 0; i < len; ++i) {
201
201
        obj = PyTuple_GET_ITEM(args, i);
202
 
        if (!PyString_CheckExact(obj)) {
 
202
        if (!PyString_CheckExact(obj) && !StaticTuple_CheckExact(obj)) {
203
203
            PyErr_SetString(PyExc_TypeError, "StaticTuple.__init__(...)"
204
 
                " requires that all key bits are strings.");
 
204
                " requires that all key bits are strings or StaticTuple.");
205
205
            /* TODO: What is the proper way to dealloc ? */
206
206
            type->tp_dealloc((PyObject *)self);
207
207
            return NULL;
296
296
{
297
297
    StaticTuple *vk, *wk;
298
298
    Py_ssize_t vlen, wlen, min_len, i;
 
299
    PyObject *v_obj, *w_obj;
299
300
    richcmpfunc string_richcompare;
300
301
 
301
302
    if (!StaticTuple_CheckExact(v)) {
302
 
        /* This has never triggered */
 
303
        /* This has never triggered, according to python-dev it seems this
 
304
         * might trigger if '__op__' is defined but '__rop__' is not, sort of
 
305
         * case. Such as "None == StaticTuple()"
 
306
         */
303
307
        fprintf(stderr, "self is tuple\n");
304
308
        Py_INCREF(Py_NotImplemented);
305
309
        return Py_NotImplemented;
315
319
         */
316
320
        return StaticTuple_richcompare_to_tuple(vk, w, op);
317
321
    }
 
322
    /* TODO: Py_None is one of the other common cases here, we should probably
 
323
     *       directly support it.
 
324
     */
318
325
    if (!StaticTuple_CheckExact(w)) {
319
326
        /* Both are not StaticTuple objects, and they aren't Tuple objects or the
320
327
         * previous path would have been taken. We don't support comparing with
326
333
    }
327
334
    /* Now we know that we have 2 StaticTuple objects, so let's compare them.
328
335
     * This code is somewhat borrowed from tuplerichcompare, except we know our
329
 
     * objects are strings, so we get to cheat a bit.
 
336
     * objects are limited in scope, so we cheat a bit.
330
337
     */
331
338
    if (v == w) {
332
339
        /* Identical pointers, we can shortcut this easily. */
349
356
        min_len = (vlen < wlen) ? vlen : wlen;
350
357
    string_richcompare = PyString_Type.tp_richcompare;
351
358
    for (i = 0; i < min_len; i++) {
352
 
        PyObject *result;
353
 
        result = string_richcompare((PyObject *)vk->key_bits[i],
354
 
                                    (PyObject *)wk->key_bits[i],
355
 
                                    Py_EQ);
 
359
        PyObject *result = NULL;
 
360
        v_obj = StaticTuple_GET_ITEM(vk, i);
 
361
        w_obj = StaticTuple_GET_ITEM(wk, i);
 
362
        if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) {
 
363
            result = string_richcompare(v_obj, w_obj, Py_EQ);
 
364
        } else if (StaticTuple_CheckExact(v_obj) &&
 
365
                   StaticTuple_CheckExact(w_obj))
 
366
        {
 
367
            /* Both are StaticTuple types, so recurse */
 
368
            result = StaticTuple_richcompare(v_obj, w_obj, Py_EQ);
 
369
        } else {
 
370
            /* Not the same type, obviously they won't compare equal */
 
371
            break;
 
372
        }
356
373
        if (result == NULL) {
357
 
            return NULL; /* Seems to be an error */
 
374
            return NULL; /* There seems to be an error */
358
375
        }
359
376
        if (result == Py_NotImplemented) {
360
377
            PyErr_BadInternalCall();
362
379
            return NULL;
363
380
        }
364
381
        if (result == Py_False) {
365
 
            /* These strings are not identical
 
382
            /* This entry is not identical
366
383
             * Shortcut for Py_EQ
367
384
             */
368
385
            if (op == Py_EQ) {
372
389
            break;
373
390
        }
374
391
        if (result != Py_True) {
375
 
            /* We don't know *what* string_richcompare is returning, but it
376
 
             * isn't correct.
 
392
            /* We don't know *what* richcompare is returning, but it
 
393
             * isn't something we recognize
377
394
             */
378
395
            PyErr_BadInternalCall();
379
396
            Py_DECREF(result);
382
399
        Py_DECREF(result);
383
400
    }
384
401
        if (i >= vlen || i >= wlen) {
385
 
                /* No more items to compare -- compare sizes */
 
402
        /* We walked off one of the lists, but everything compared equal so
 
403
         * far. Just compare the size.
 
404
         */
386
405
                int cmp;
387
406
                PyObject *res;
388
407
                switch (op) {
407
426
        return Py_True;
408
427
    }
409
428
    /* It is some other comparison, go ahead and do the real check. */
410
 
    return string_richcompare((PyObject *)vk->key_bits[i],
411
 
                              (PyObject *)wk->key_bits[i],
412
 
                              op);
 
429
    if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj))
 
430
    {
 
431
        return string_richcompare(v_obj, w_obj, op);
 
432
    } else if (StaticTuple_CheckExact(v_obj) &&
 
433
               StaticTuple_CheckExact(w_obj))
 
434
    {
 
435
        /* Both are StaticTuple types, so recurse */
 
436
        return StaticTuple_richcompare(v_obj, w_obj, op);
 
437
    } else {
 
438
        Py_INCREF(Py_NotImplemented);
 
439
        return Py_NotImplemented;
 
440
    }
413
441
}
414
442
 
415
443
 
501
529
PyTypeObject StaticTuple_Type = {
502
530
    PyObject_HEAD_INIT(NULL)
503
531
    0,                                           /* ob_size */
504
 
    "StaticTuple",                                       /* tp_name */
505
 
    sizeof(StaticTuple) - sizeof(PyStringObject *),      /* tp_basicsize */
 
532
    "StaticTuple",                               /* tp_name */
 
533
    sizeof(StaticTuple) - sizeof(PyObject *),    /* tp_basicsize */
506
534
    sizeof(PyObject *),                          /* tp_itemsize */
507
 
    (destructor)StaticTuple_dealloc,                     /* tp_dealloc */
 
535
    (destructor)StaticTuple_dealloc,             /* tp_dealloc */
508
536
    0,                                           /* tp_print */
509
537
    0,                                           /* tp_getattr */
510
538
    0,                                           /* tp_setattr */
511
539
    0,                                           /* tp_compare */
512
 
    (reprfunc)StaticTuple_repr,                          /* tp_repr */
 
540
    (reprfunc)StaticTuple_repr,                  /* tp_repr */
513
541
    0,                                           /* tp_as_number */
514
 
    &StaticTuple_as_sequence,                            /* tp_as_sequence */
 
542
    &StaticTuple_as_sequence,                    /* tp_as_sequence */
515
543
    0,                                           /* tp_as_mapping */
516
 
    (hashfunc)StaticTuple_hash,                          /* tp_hash */
 
544
    (hashfunc)StaticTuple_hash,                  /* tp_hash */
517
545
    0,                                           /* tp_call */
518
546
    0,                                           /* tp_str */
519
547
    PyObject_GenericGetAttr,                     /* tp_getattro */
520
548
    0,                                           /* tp_setattro */
521
549
    0,                                           /* tp_as_buffer */
522
550
    Py_TPFLAGS_DEFAULT,                          /* tp_flags*/
523
 
    StaticTuple_doc,                                     /* tp_doc */
 
551
    StaticTuple_doc,                             /* tp_doc */
524
552
    /* gc.get_referents checks the IS_GC flag before it calls tp_traverse
525
553
     * And we don't include this object in the garbage collector because we
526
554
     * know it doesn't create cycles. However, 'meliae' will follow
527
555
     * tp_traverse, even if the object isn't GC, and we want that.
528
556
     */
529
 
    (traverseproc)StaticTuple_traverse,                  /* tp_traverse */
 
557
    (traverseproc)StaticTuple_traverse,          /* tp_traverse */
530
558
    0,                                           /* tp_clear */
531
559
    // TODO: implement richcompare, we should probably be able to compare vs an
532
560
    //       tuple, as well as versus another StaticTuples object.
533
 
    StaticTuple_richcompare,                             /* tp_richcompare */
 
561
    StaticTuple_richcompare,                     /* tp_richcompare */
534
562
    0,                                           /* tp_weaklistoffset */
535
563
    // We could implement this as returning tuples of keys...
536
564
    0,                                           /* tp_iter */
537
565
    0,                                           /* tp_iternext */
538
 
    StaticTuple_methods,                                 /* tp_methods */
 
566
    StaticTuple_methods,                         /* tp_methods */
539
567
    0,                                           /* tp_members */
540
568
    0,                                           /* tp_getset */
541
569
    0,                                           /* tp_base */
545
573
    0,                                           /* tp_dictoffset */
546
574
    0,                                           /* tp_init */
547
575
    0,                                           /* tp_alloc */
548
 
    StaticTuple_new,                                     /* tp_new */
 
576
    StaticTuple_new,                             /* tp_new */
549
577
};
550
578
 
551
579