Skip to content

Commit 1ed5cd2

Browse files
committed
Implement getitem
1 parent 662729d commit 1ed5cd2

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

src/cstring.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ struct cstring {
77

88
#define CSTRING_VALUE(self) (((struct cstring *)self)->value)
99

10-
static PyObject *_cstring_new(PyTypeObject *type, const char *value, int size) {
11-
struct cstring *new = type->tp_alloc(type, size);
12-
memcpy(new->value, value, size);
10+
static PyObject *_cstring_new(PyTypeObject *type, const char *value, size_t len) {
11+
struct cstring *new = type->tp_alloc(type, len + 1);
12+
memcpy(new->value, value, len);
13+
new->value[len] = '\0';
1314
return (PyObject *)new;
1415
}
1516

1617
static PyObject *cstring_new(PyTypeObject *type, PyObject *args, PyObject **kwargs) {
1718
char *value = NULL;
1819
if(!PyArg_ParseTuple(args, "s", &value))
1920
return NULL;
20-
int size = strlen(value) + 1;
21-
return _cstring_new(type, value, size);
21+
size_t len = strlen(value);
22+
return _cstring_new(type, value, len);
2223
}
2324

2425
static void cstring_dealloc(PyObject *self) {
@@ -63,7 +64,7 @@ static PyObject *cstring_repeat(PyObject *self, Py_ssize_t count) {
6364
if(!_ensure_cstring(self))
6465
return NULL;
6566
if(count <= 0)
66-
return _cstring_new(Py_TYPE(self), "", 1);
67+
return _cstring_new(Py_TYPE(self), "", 0);
6768

6869
Py_ssize_t size = (cstring_len(self) * count) + 1;
6970

@@ -74,10 +75,24 @@ static PyObject *cstring_repeat(PyObject *self, Py_ssize_t count) {
7475
return (PyObject *)new;
7576
}
7677

78+
static Py_ssize_t _ensure_valid_index(PyObject *self, Py_ssize_t i) {
79+
if(i >= 0 && i < cstring_len(self))
80+
return i;
81+
PyErr_SetString(PyExc_IndexError, "Index is out of bounds");
82+
return -1;
83+
}
84+
85+
static PyObject *cstring_item(PyObject *self, Py_ssize_t i) {
86+
if(_ensure_valid_index(self, i) < 0)
87+
return NULL;
88+
return _cstring_new(Py_TYPE(self), &CSTRING_VALUE(self)[i], 1);
89+
}
90+
7791
static PySequenceMethods cstring_as_sequence = {
7892
.sq_length = cstring_len,
7993
.sq_concat = cstring_concat,
8094
.sq_repeat = cstring_repeat,
95+
.sq_item = cstring_item,
8196
};
8297

8398
static PyTypeObject cstring_type = {

test/test_cstring.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,25 @@ def test_repeat_five():
3434
result = cstring('hello') * 5
3535
assert str(result) == str(cstring('hellohellohellohellohello')) # TODO: implement cstring equality!
3636

37+
38+
def test_item_IndexError_too_small():
39+
with pytest.raises(IndexError):
40+
result = cstring('hello')[-6]
41+
42+
43+
def test_item_ok_neg():
44+
result = cstring('hello')[-5]
45+
assert isinstance(result, cstring)
46+
assert str(result) == str(cstring('h')) # TODO: implement cstring equality!
47+
48+
49+
def test_item_IndexError_too_big():
50+
with pytest.raises(IndexError):
51+
result = cstring('hello')[5]
52+
53+
54+
def test_item_ok_pos():
55+
result = cstring('hello')[4]
56+
assert isinstance(result, cstring)
57+
assert str(result) == str(cstring('o')) # TODO: implement cstring equality!
58+

0 commit comments

Comments
 (0)