summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <armin.rigo@gmail.com>2017-02-06 08:24:36 +0000
committerArmin Rigo <armin.rigo@gmail.com>2017-02-06 08:24:36 +0000
commit2ad2c47b3b76da0d683cd5bb5c404ff7100b535b (patch)
treeea427fc6b6688d74b38db6594ec7514bd7cdaf08
parent12f134111b1d1a0dd1f90b3b8f0d2d9b883fe3d4 (diff)
parentd005405f433e4ef9e4a12412c83421b78e3cff68 (diff)
downloadcffi-2ad2c47b3b76da0d683cd5bb5c404ff7100b535b.tar.gz
Merged in coronafire/cffi/buffer_richcompare (pull request #76)
Add richcompare to buffer objects
-rw-r--r--c/minibuffer.h83
-rw-r--r--testing/cffi0/backend_tests.py17
-rw-r--r--testing/cffi0/test_ffi_backend.py6
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)