26
26
#include "_static_tuple_c.h"
27
27
#include "_export_c_api.h"
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_breezy___simple_set_pyx(). As such, we just #define one to be
32
* equivalent to the other in our internal code.
34
#define import__simple_set_pyx import_breezy___simple_set_pyx
29
35
#include "_simple_set_pyx_api.h"
31
37
#if defined(__GNUC__)
236
242
" should not have a NULL entry.");
239
if (PyBytes_CheckExact(obj)
245
if (PyString_CheckExact(obj)
240
246
|| StaticTuple_CheckExact(obj)
241
247
|| obj == Py_None
242
248
|| PyBool_Check(obj)
243
#if PY_MAJOR_VERSION >= 3
245
249
|| PyInt_CheckExact(obj)
247
250
|| PyLong_CheckExact(obj)
248
251
|| PyFloat_CheckExact(obj)
249
252
|| PyUnicode_CheckExact(obj)
311
314
if (tuple_repr == NULL) {
314
#if PY_MAJOR_VERSION >= 3
315
result = PyUnicode_FromFormat("StaticTuple%U", tuple_repr);
317
317
result = PyString_FromFormat("StaticTuple%s",
318
318
PyString_AsString(tuple_repr));
323
/* adapted from tuplehash(), is the specific hash value considered
327
#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 8)
328
/* Hash for tuples. This is a slightly simplified version of the xxHash
329
non-cryptographic hash:
330
- we do not use any parallellism, there is only 1 accumulator.
331
- we drop the final mixing since this is just a permutation of the
332
output space: it does not help against collisions.
333
- at the end, we mangle the length with a single constant.
334
For the xxHash specification, see
335
https://github.com/Cyan4973/xxHash/blob/master/doc/xxhash_spec.md
337
Below are the official constants from the xxHash specification. Optimizing
338
compilers should emit a single "rotate" instruction for the
339
_PyHASH_XXROTATE() expansion. If that doesn't happen for some important
340
platform, the macro could be changed to expand to a platform-specific rotate
343
#if SIZEOF_PY_UHASH_T > 4
344
#define _PyHASH_XXPRIME_1 ((Py_uhash_t)11400714785074694791ULL)
345
#define _PyHASH_XXPRIME_2 ((Py_uhash_t)14029467366897019727ULL)
346
#define _PyHASH_XXPRIME_5 ((Py_uhash_t)2870177450012600261ULL)
347
#define _PyHASH_XXROTATE(x) ((x << 31) | (x >> 33)) /* Rotate left 31 bits */
349
#define _PyHASH_XXPRIME_1 ((Py_uhash_t)2654435761UL)
350
#define _PyHASH_XXPRIME_2 ((Py_uhash_t)2246822519UL)
351
#define _PyHASH_XXPRIME_5 ((Py_uhash_t)374761393UL)
352
#define _PyHASH_XXROTATE(x) ((x << 13) | (x >> 19)) /* Rotate left 13 bits */
355
/* Tests have shown that it's not worth to cache the hash value, see
356
https://bugs.python.org/issue9685 */
358
StaticTuple_hash(StaticTuple *self)
360
Py_ssize_t i, len = self->size;
361
PyObject **item = self->items;
363
#if STATIC_TUPLE_HAS_HASH
364
if (self->hash != -1) {
369
Py_uhash_t acc = _PyHASH_XXPRIME_5;
370
for (i = 0; i < len; i++) {
371
Py_uhash_t lane = PyObject_Hash(item[i]);
372
if (lane == (Py_uhash_t)-1) {
375
acc += lane * _PyHASH_XXPRIME_2;
376
acc = _PyHASH_XXROTATE(acc);
377
acc *= _PyHASH_XXPRIME_1;
380
/* Add input length, mangled to keep the historical value of hash(()). */
381
acc += len ^ (_PyHASH_XXPRIME_5 ^ 3527539UL);
383
if (acc == (Py_uhash_t)-1) {
387
#if STATIC_TUPLE_HAS_HASH
396
323
StaticTuple_hash(StaticTuple *self)
501
427
} else if (w == Py_None) {
502
428
// None is always less than the object
505
#if PY_MAJOR_VERSION >= 3
507
case Py_GT:case Py_GE:
430
case Py_NE:case Py_GT:case Py_GE:
509
431
Py_INCREF(Py_True);
512
#if PY_MAJOR_VERSION >= 3
514
case Py_LT:case Py_LE:
433
case Py_EQ:case Py_LT:case Py_LE:
516
434
Py_INCREF(Py_False);
518
default: // Should only happen on Python 3
519
return Py_NotImplemented;
436
default: // Should never happen
437
return Py_NotImplemented;
522
440
/* We don't special case this comparison, we just let python handle
569
487
/* Shortcut case, these must be identical */
572
if (PyBytes_CheckExact(v_obj) && PyBytes_CheckExact(w_obj)) {
490
if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) {
573
491
result = string_richcompare(v_obj, w_obj, Py_EQ);
574
492
} else if (StaticTuple_CheckExact(v_obj) &&
575
493
StaticTuple_CheckExact(w_obj))
776
692
Py_DECREF(as_tuple);
782
StaticTuple_subscript(StaticTuple *self, PyObject *key)
784
PyObject *as_tuple, *result;
786
as_tuple = StaticTuple_as_tuple(self);
787
if (as_tuple == NULL) {
790
result = PyTuple_Type.tp_as_mapping->mp_subscript(as_tuple, key);
796
697
StaticTuple_traverse(StaticTuple *self, visitproc visit, void *arg)
859
760
0, /* nb_coerce */
863
764
static PySequenceMethods StaticTuple_as_sequence = {
864
765
(lenfunc)StaticTuple_length, /* sq_length */
865
766
0, /* sq_concat */
866
767
0, /* sq_repeat */
867
768
(ssizeargfunc)StaticTuple_item, /* sq_item */
868
#if PY_MAJOR_VERSION >= 3
870
769
(ssizessizeargfunc)StaticTuple_slice, /* sq_slice */
872
770
0, /* sq_ass_item */
873
771
0, /* sq_ass_slice */
874
772
0, /* sq_contains */
875
#if PY_MAJOR_VERSION >= 3
876
0, /* sq_inplace_concat */
877
0, /* sq_inplace_repeat */
882
static PyMappingMethods StaticTuple_as_mapping = {
883
(lenfunc)StaticTuple_length, /* mp_length */
884
(binaryfunc)StaticTuple_subscript, /* mp_subscript */
885
0, /* mp_ass_subscript */
775
/* TODO: Implement StaticTuple_as_mapping.
776
* The only thing we really want to support from there is mp_subscript,
777
* so that we could support extended slicing (foo[::2]). Not worth it
889
782
PyTypeObject StaticTuple_Type = {
890
PyVarObject_HEAD_INIT(NULL, 0)
783
PyObject_HEAD_INIT(NULL)
891
785
"breezy._static_tuple_c.StaticTuple", /* tp_name */
892
786
sizeof(StaticTuple), /* tp_basicsize */
893
787
sizeof(PyObject *), /* tp_itemsize */
899
793
(reprfunc)StaticTuple_repr, /* tp_repr */
900
794
&StaticTuple_as_number, /* tp_as_number */
901
795
&StaticTuple_as_sequence, /* tp_as_sequence */
902
&StaticTuple_as_mapping, /* tp_as_mapping */
796
0, /* tp_as_mapping */
903
797
(hashfunc)StaticTuple_hash, /* tp_hash */
996
PYMOD_INIT_FUNC(_static_tuple_c)
891
_workaround_pyrex_096(void)
893
/* Work around an incompatibility in how pyrex 0.9.6 exports a module,
894
* versus how pyrex 0.9.8 and cython 0.11 export it.
895
* Namely 0.9.6 exports import__simple_set_pyx and tries to
896
* "import _simple_set_pyx" but it is available only as
897
* "import breezy._simple_set_pyx"
898
* It is a shame to hack up sys.modules, but that is what we've got to do.
900
PyObject *sys_module = NULL, *modules = NULL, *set_module = NULL;
903
/* Clear out the current ImportError exception, and try again. */
905
/* Note that this only seems to work if somewhere else imports
906
* breezy._simple_set_pyx before importing breezy._static_tuple_c
908
set_module = PyImport_ImportModule("breezy._simple_set_pyx");
909
if (set_module == NULL) {
912
/* Add the _simple_set_pyx into sys.modules at the appropriate location. */
913
sys_module = PyImport_ImportModule("sys");
914
if (sys_module == NULL) {
917
modules = PyObject_GetAttrString(sys_module, "modules");
918
if (modules == NULL || !PyDict_Check(modules)) {
921
PyDict_SetItemString(modules, "_simple_set_pyx", set_module);
922
/* Now that we have hacked it in, try the import again. */
923
retval = import_breezy___simple_set_pyx();
925
Py_XDECREF(set_module);
926
Py_XDECREF(sys_module);
933
init_static_tuple_c(void)
1000
937
StaticTuple_Type.tp_getattro = PyObject_GenericGetAttr;
1001
if (PyType_Ready(&StaticTuple_Type) < 0) {
938
if (PyType_Ready(&StaticTuple_Type) < 0)
1005
PYMOD_CREATE(m, "_static_tuple_c",
1006
"C implementation of a StaticTuple structure",
1007
static_tuple_c_methods);
941
m = Py_InitModule3("_static_tuple_c", static_tuple_c_methods,
942
"C implementation of a StaticTuple structure");
1012
946
Py_INCREF(&StaticTuple_Type);
1013
947
PyModule_AddObject(m, "StaticTuple", (PyObject *)&StaticTuple_Type);
1014
if (import_breezy___simple_set_pyx() == -1) {
948
if (import_breezy___simple_set_pyx() == -1
949
&& _workaround_pyrex_096() == -1)
1017
953
setup_interned_tuples(m);
1018
954
setup_empty_tuple(m);
1021
return PYMOD_SUCCESS(m);
1024
958
// vim: tabstop=4 sw=4 expandtab