diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2016-11-21 15:35:08 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2016-11-21 15:35:08 (GMT) |
commit | b44fb128ae5d9562f00a944e2d22392235073a69 (patch) | |
tree | a02c44010193373a6766920250f2bfbd1af03f21 /Modules | |
parent | a2f7ee8b26e00124c0587932364b26635af84c45 (diff) | |
download | cpython-b44fb128ae5d9562f00a944e2d22392235073a69.zip cpython-b44fb128ae5d9562f00a944e2d22392235073a69.tar.gz cpython-b44fb128ae5d9562f00a944e2d22392235073a69.tar.bz2 |
Implement rich comparison for _sre.SRE_Pattern
Issue #28727: Regular expression patterns, _sre.SRE_Pattern objects created by
re.compile(), become comparable (only x==y and x!=y operators). This change
should fix the issue #18383: don't duplicate warning filters when the warnings
module is reloaded (thing usually only done in unit tests).
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_sre.c | 73 |
1 files changed, 67 insertions, 6 deletions
diff --git a/Modules/_sre.c b/Modules/_sre.c index 69c7bc0..c1e9fa6 100644 --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1506,14 +1506,12 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, self->groups = groups; - Py_XINCREF(groupindex); + Py_INCREF(groupindex); self->groupindex = groupindex; - Py_XINCREF(indexgroup); + Py_INCREF(indexgroup); self->indexgroup = indexgroup; - self->weakreflist = NULL; - if (!_validate(self)) { Py_DECREF(self); return NULL; @@ -2649,6 +2647,69 @@ pattern_scanner(PatternObject *self, PyObject *string, Py_ssize_t pos, Py_ssize_ return (PyObject*) scanner; } +static Py_hash_t +pattern_hash(PatternObject *self) +{ + Py_hash_t hash, hash2; + + hash = PyObject_Hash(self->pattern); + if (hash == -1) { + return -1; + } + + hash2 = _Py_HashBytes(self->code, sizeof(self->code[0]) * self->codesize); + hash ^= hash2; + + hash ^= self->flags; + hash ^= self->isbytes; + hash ^= self->codesize; + + if (hash == -1) { + hash = -2; + } + return hash; +} + +static PyObject* +pattern_richcompare(PyObject *lefto, PyObject *righto, int op) +{ + PatternObject *left, *right; + int cmp; + + if (op != Py_EQ && op != Py_NE) { + Py_RETURN_NOTIMPLEMENTED; + } + + if (Py_TYPE(lefto) != &Pattern_Type || Py_TYPE(righto) != &Pattern_Type) { + Py_RETURN_NOTIMPLEMENTED; + } + left = (PatternObject *)lefto; + right = (PatternObject *)righto; + + cmp = (left->flags == right->flags + && left->isbytes == right->isbytes + && left->codesize && right->codesize); + if (cmp) { + /* Compare the code and the pattern because the same pattern can + produce different codes depending on the locale used to compile the + pattern when the re.LOCALE flag is used. Don't compare groups, + indexgroup nor groupindex: they are derivated from the pattern. */ + cmp = (memcmp(left->code, right->code, + sizeof(left->code[0]) * left->codesize) == 0); + } + if (cmp) { + cmp = PyObject_RichCompareBool(left->pattern, right->pattern, + Py_EQ); + if (cmp < 0) { + return NULL; + } + } + if (op == Py_NE) { + cmp = !cmp; + } + return PyBool_FromLong(cmp); +} + #include "clinic/_sre.c.h" static PyMethodDef pattern_methods[] = { @@ -2693,7 +2754,7 @@ static PyTypeObject Pattern_Type = { 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)pattern_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ @@ -2703,7 +2764,7 @@ static PyTypeObject Pattern_Type = { pattern_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + pattern_richcompare, /* tp_richcompare */ offsetof(PatternObject, weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ |