Skip to content

Commit e0dbf9e

Browse files
committed
Implement rich compare
1 parent 0deeb44 commit e0dbf9e

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

src/cstring.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,6 @@ static void cstring_dealloc(PyObject *self) {
2626
Py_TYPE(self)->tp_free(self);
2727
}
2828

29-
static PyObject *cstring_str(PyObject *self) {
30-
return PyUnicode_FromString(CSTRING_VALUE(self));
31-
}
32-
33-
static Py_ssize_t cstring_len(PyObject *self) {
34-
return Py_SIZE(self) - 1;
35-
}
36-
3729
static PyTypeObject cstring_type;
3830

3931
static int _ensure_cstring(PyObject *self) {
@@ -46,6 +38,42 @@ static int _ensure_cstring(PyObject *self) {
4638
return 0;
4739
}
4840

41+
static PyObject *cstring_str(PyObject *self) {
42+
return PyUnicode_FromString(CSTRING_VALUE(self));
43+
}
44+
45+
static PyObject *cstring_richcompare(PyObject *self, PyObject *other, int op) {
46+
if(!_ensure_cstring(other))
47+
return NULL;
48+
49+
const char *left = CSTRING_VALUE(self);
50+
const char *right = CSTRING_VALUE(other);
51+
52+
for(;*left && *right && *left == *right; ++left, ++right)
53+
;
54+
55+
switch (op) {
56+
case Py_EQ:
57+
return PyBool_FromLong(*left == *right);
58+
case Py_NE:
59+
return PyBool_FromLong(*left != *right);
60+
case Py_LT:
61+
return PyBool_FromLong(*left < *right);
62+
case Py_GT:
63+
return PyBool_FromLong(*left > *right);
64+
case Py_LE:
65+
return PyBool_FromLong(*left <= *right);
66+
case Py_GE:
67+
return PyBool_FromLong(*left >= *right);
68+
default:
69+
assert(0);
70+
}
71+
}
72+
73+
static Py_ssize_t cstring_len(PyObject *self) {
74+
return Py_SIZE(self) - 1;
75+
}
76+
4977
static PyObject *cstring_concat(PyObject *left, PyObject *right) {
5078
if(!_ensure_cstring(left))
5179
return NULL;
@@ -113,6 +141,7 @@ static PyTypeObject cstring_type = {
113141
.tp_flags = Py_TPFLAGS_DEFAULT,
114142
.tp_new = cstring_new,
115143
.tp_dealloc = cstring_dealloc,
144+
.tp_richcompare = cstring_richcompare,
116145
.tp_str = cstring_str,
117146
.tp_as_sequence = &cstring_as_sequence,
118147
};

test/test_cstring.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,44 @@ def test_str():
77
assert str(result) == 'hello, world'
88

99

10+
# Rich Compare
11+
12+
13+
def test_eq():
14+
a = cstring('hello')
15+
b = cstring('hello')
16+
assert a is not b
17+
assert a == b
18+
19+
20+
def test_neq():
21+
assert cstring('hello') != cstring('world')
22+
23+
24+
def test_ne():
25+
assert cstring('hello') != cstring('world')
26+
27+
28+
def test_lt():
29+
assert cstring('a') < cstring('b')
30+
assert cstring('a') < cstring('aa')
31+
32+
33+
def test_le():
34+
assert cstring('a') <= cstring('a')
35+
assert cstring('a') <= cstring('b')
36+
37+
38+
def test_gt():
39+
assert cstring('b') > cstring('a')
40+
assert cstring('aa') > cstring('a')
41+
42+
43+
def test_ge():
44+
assert cstring('a') >= cstring('a')
45+
assert cstring('b') >= cstring('a')
46+
47+
1048
# Sequence API
1149

1250

@@ -64,3 +102,5 @@ def test_contains_True():
64102
def test_contains_False():
65103
assert cstring('hello') not in cstring('world')
66104

105+
106+

0 commit comments

Comments
 (0)