static CYTHON_INLINE PyObject* __Pyx_PyFrozenSet_New(PyObject* it) { if (it) { PyObject* result; #if CYTHON_COMPILING_IN_PYPY // PyPy currently lacks PyFrozenSet_CheckExact() and PyFrozenSet_New() PyObject* args; args = PyTuple_Pack(1, it); if (unlikely(!args)) return NULL; result = PyObject_Call((PyObject*)&PyFrozenSet_Type, args, NULL); Py_DECREF(args); return result; #else if (PyFrozenSet_CheckExact(it)) { Py_INCREF(it); return it; } result = PyFrozenSet_New(it); if (unlikely(!result)) return NULL; if (likely(PySet_GET_SIZE(result))) return result; // empty frozenset is a singleton // seems wasteful, but CPython does the same Py_DECREF(result); #endif } #if CYTHON_COMPILING_IN_CPYTHON return PyFrozenSet_Type.tp_new(&PyFrozenSet_Type, $empty_tuple, NULL); #else return PyObject_Call((PyObject*)&PyFrozenSet_Type, $empty_tuple, NULL); #endif }
/* Intern selected string constants */ static int intern_string_constants(PyObject *tuple) { int modified = 0; Py_ssize_t i; for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { PyObject *v = PyTuple_GET_ITEM(tuple, i); if (PyUnicode_CheckExact(v)) { if (PyUnicode_READY(v) == -1) { PyErr_Clear(); continue; } if (all_name_chars(v)) { PyObject *w = v; PyUnicode_InternInPlace(&v); if (w != v) { PyTuple_SET_ITEM(tuple, i, v); modified = 1; } } } else if (PyTuple_CheckExact(v)) { intern_string_constants(v); } else if (PyFrozenSet_CheckExact(v)) { PyObject *w = v; PyObject *tmp = PySequence_Tuple(v); if (tmp == NULL) { PyErr_Clear(); continue; } if (intern_string_constants(tmp)) { v = PyFrozenSet_New(tmp); if (v == NULL) { PyErr_Clear(); } else { PyTuple_SET_ITEM(tuple, i, v); Py_DECREF(w); modified = 1; } } Py_DECREF(tmp); } } return modified; }
static CYTHON_INLINE PyObject* __Pyx_PyFrozenSet_New(PyObject* it) { if (it) { PyObject* result; if (PyFrozenSet_CheckExact(it)) { Py_INCREF(it); return it; } result = PyFrozenSet_New(it); if (unlikely(!result)) return NULL; if (likely(PySet_GET_SIZE(result))) return result; // empty frozenset is a singleton // seems wasteful, but CPython does the same Py_DECREF(result); } #if CYTHON_COMPILING_IN_CPYTHON return PyFrozenSet_Type.tp_new(&PyFrozenSet_Type, $empty_tuple, NULL); #else return PyObject_Call((PyObject*)&PyFrozenSet_Type, $empty_tuple, NULL); #endif }
PyObject* _PyCode_ConstantKey(PyObject *op) { PyObject *key; /* Py_None and Py_Ellipsis are singleton */ if (op == Py_None || op == Py_Ellipsis || PyLong_CheckExact(op) || PyBool_Check(op) || PyBytes_CheckExact(op) || PyUnicode_CheckExact(op) /* code_richcompare() uses _PyCode_ConstantKey() internally */ || PyCode_Check(op)) { key = PyTuple_Pack(2, Py_TYPE(op), op); } else if (PyFloat_CheckExact(op)) { double d = PyFloat_AS_DOUBLE(op); /* all we need is to make the tuple different in either the 0.0 * or -0.0 case from all others, just to avoid the "coercion". */ if (d == 0.0 && copysign(1.0, d) < 0.0) key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None); else key = PyTuple_Pack(2, Py_TYPE(op), op); } else if (PyComplex_CheckExact(op)) { Py_complex z; int real_negzero, imag_negzero; /* For the complex case we must make complex(x, 0.) different from complex(x, -0.) and complex(0., y) different from complex(-0., y), for any x and y. All four complex zeros must be distinguished.*/ z = PyComplex_AsCComplex(op); real_negzero = z.real == 0.0 && copysign(1.0, z.real) < 0.0; imag_negzero = z.imag == 0.0 && copysign(1.0, z.imag) < 0.0; /* use True, False and None singleton as tags for the real and imag * sign, to make tuples different */ if (real_negzero && imag_negzero) { key = PyTuple_Pack(3, Py_TYPE(op), op, Py_True); } else if (imag_negzero) { key = PyTuple_Pack(3, Py_TYPE(op), op, Py_False); } else if (real_negzero) { key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None); } else { key = PyTuple_Pack(2, Py_TYPE(op), op); } } else if (PyTuple_CheckExact(op)) { Py_ssize_t i, len; PyObject *tuple; len = PyTuple_GET_SIZE(op); tuple = PyTuple_New(len); if (tuple == NULL) return NULL; for (i=0; i < len; i++) { PyObject *item, *item_key; item = PyTuple_GET_ITEM(op, i); item_key = _PyCode_ConstantKey(item); if (item_key == NULL) { Py_DECREF(tuple); return NULL; } PyTuple_SET_ITEM(tuple, i, item_key); } key = PyTuple_Pack(3, Py_TYPE(op), op, tuple); Py_DECREF(tuple); } else if (PyFrozenSet_CheckExact(op)) { Py_ssize_t pos = 0; PyObject *item; Py_hash_t hash; Py_ssize_t i, len; PyObject *tuple, *set; len = PySet_GET_SIZE(op); tuple = PyTuple_New(len); if (tuple == NULL) return NULL; i = 0; while (_PySet_NextEntry(op, &pos, &item, &hash)) { PyObject *item_key; item_key = _PyCode_ConstantKey(item); if (item_key == NULL) { Py_DECREF(tuple); return NULL; } assert(i < len); PyTuple_SET_ITEM(tuple, i, item_key); i++; } set = PyFrozenSet_New(tuple); Py_DECREF(tuple); if (set == NULL) return NULL; key = PyTuple_Pack(3, Py_TYPE(op), op, set); Py_DECREF(set); return key; } else { /* for other types, use the object identifier as a unique identifier * to ensure that they are seen as unequal. */ PyObject *obj_id = PyLong_FromVoidPtr(op); if (obj_id == NULL) return NULL; key = PyTuple_Pack(3, Py_TYPE(op), op, obj_id); Py_DECREF(obj_id); } return key; }