diff options
author | Armin Rigo <armin.rigo@gmail.com> | 2017-02-06 08:24:36 +0000 |
---|---|---|
committer | Armin Rigo <armin.rigo@gmail.com> | 2017-02-06 08:24:36 +0000 |
commit | 2ad2c47b3b76da0d683cd5bb5c404ff7100b535b (patch) | |
tree | ea427fc6b6688d74b38db6594ec7514bd7cdaf08 | |
parent | 12f134111b1d1a0dd1f90b3b8f0d2d9b883fe3d4 (diff) | |
parent | d005405f433e4ef9e4a12412c83421b78e3cff68 (diff) | |
download | cffi-2ad2c47b3b76da0d683cd5bb5c404ff7100b535b.tar.gz |
Merged in coronafire/cffi/buffer_richcompare (pull request #76)
Add richcompare to buffer objects
-rw-r--r-- | c/minibuffer.h | 83 | ||||
-rw-r--r-- | testing/cffi0/backend_tests.py | 17 | ||||
-rw-r--r-- | testing/cffi0/test_ffi_backend.py | 6 |
3 files changed, 102 insertions, 4 deletions
diff --git a/c/minibuffer.h b/c/minibuffer.h index 52cdd64..e8bf3b2 100644 --- a/c/minibuffer.h +++ b/c/minibuffer.h @@ -155,6 +155,87 @@ mb_clear(MiniBufferObj *ob) return 0; } +static PyObject * +mb_richcompare(PyObject *self, PyObject *other, int op) +{ + Py_ssize_t self_size, other_size; + Py_buffer self_bytes, other_bytes; + PyObject *res; + Py_ssize_t minsize; + int cmp, rc; + + /* Bytes can be compared to anything that supports the (binary) + buffer API. Except that a comparison with Unicode is always an + error, even if the comparison is for equality. */ + rc = PyObject_IsInstance(self, (PyObject*)&PyUnicode_Type); + if (!rc) + rc = PyObject_IsInstance(other, (PyObject*)&PyUnicode_Type); + if (rc < 0) + return NULL; + if (rc) { + if (Py_BytesWarningFlag && (op == Py_EQ || op == Py_NE)) { + if (PyErr_WarnEx(PyExc_BytesWarning, + "Comparison between bytearray and string", 1)) + return NULL; + } + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) { + PyErr_Clear(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + + } + self_size = self_bytes.len; + + if (PyObject_GetBuffer(other, &other_bytes, PyBUF_SIMPLE) != 0) { + PyErr_Clear(); + PyBuffer_Release(&self_bytes); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + + } + other_size = other_bytes.len; + + if (self_size != other_size && (op == Py_EQ || op == Py_NE)) { + /* Shortcut: if the lengths differ, the objects differ */ + cmp = (op == Py_NE); + } + else { + minsize = self_size; + if (other_size < minsize) + minsize = other_size; + + cmp = memcmp(self_bytes.buf, other_bytes.buf, minsize); + /* In ISO C, memcmp() guarantees to use unsigned bytes! */ + + if (cmp == 0) { + if (self_size < other_size) + cmp = -1; + else if (self_size > other_size) + cmp = 1; + } + + switch (op) { + case Py_LT: cmp = cmp < 0; break; + case Py_LE: cmp = cmp <= 0; break; + case Py_EQ: cmp = cmp == 0; break; + case Py_NE: cmp = cmp != 0; break; + case Py_GT: cmp = cmp > 0; break; + case Py_GE: cmp = cmp >= 0; break; + } + } + + res = cmp ? Py_True : Py_False; + PyBuffer_Release(&self_bytes); + PyBuffer_Release(&other_bytes); + Py_INCREF(res); + return res; +} + #if PY_MAJOR_VERSION >= 3 /* pfffffffffffff pages of copy-paste from listobject.c */ static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item) @@ -287,7 +368,7 @@ static PyTypeObject MiniBuffer_Type = { ffi_buffer_doc, /* tp_doc */ (traverseproc)mb_traverse, /* tp_traverse */ (inquiry)mb_clear, /* tp_clear */ - 0, /* tp_richcompare */ + (richcmpfunc)mb_richcompare, /* tp_richcompare */ offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py index 8eb279d..cf25512 100644 --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -1226,6 +1226,23 @@ class BackendTests: assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) f.close() + def test_ffi_buffer_comparisons(self): + ffi = FFI(backend=self.Backend()) + ba = bytearray(range(100, 110)) + a = ffi.new("uint8_t[]", list(ba)) + try: + b_full = ffi.buffer(a) + b_short = ffi.buffer(a, 3) + b_mid = ffi.buffer(a, 6) + except NotImplementedError as e: + py.test.skip(str(e)) + else: + content = b_full[:] + assert content == b_full == ba + assert b_short < b_mid < b_full + assert ba > b_mid > ba[0:2] + assert b_short != ba[1:4] + def test_array_in_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo_s { int len; short data[5]; };") diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py index f9d66de..b387adb 100644 --- a/testing/cffi0/test_ffi_backend.py +++ b/testing/cffi0/test_ffi_backend.py @@ -191,10 +191,10 @@ class TestBitfield: s = ffi.new("struct s1 *") setattr(s, name, value) assert getattr(s, name) == value - raw1 = ffi.buffer(s)[:] + buff1 = ffi.buffer(s) t = lib.try_with_value(fnames.index(name), value) - raw2 = ffi.buffer(t, len(raw1))[:] - assert raw1 == raw2 + buff2 = ffi.buffer(t, len(buff1)) + assert buff1 == buff2 def test_bitfield_basic(self): self.check("int a; int b:9; int c:20; int y;", 8, 4, 12) |