#include
#define WHITESPACE_CHARS " \t\n\v\f\r"
/* memrchr not available on some systems, so reimplement. */
const char *_memrchr(const char *s, int c, size_t n) {
for(const char *p = s + n - 1; p >= s; --p) {
if(*p == c)
return p;
}
return NULL;
}
const char *_strrstr(const char *s, const char *find) {
const char *p = s + strlen(s) - 1;
for(;p > s; --p) {
if(memcmp(p, find, strlen(find)) == 0)
return p;
}
return NULL;
}
struct cstring {
PyObject_VAR_HEAD
Py_hash_t hash;
char value[];
};
static PyTypeObject cstring_type;
#define CSTRING_HASH(self) (((struct cstring *)self)->hash)
#define CSTRING_VALUE(self) (((struct cstring *)self)->value)
#define CSTRING_VALUE_AT(self, i) (&CSTRING_VALUE(self)[(i)])
#define CSTRING_LAST_BYTE(self) (CSTRING_VALUE(self)[Py_SIZE(self) - 1])
#define CSTRING_ALLOC(tp, len) ((struct cstring *)(tp)->tp_alloc((tp), (len)))
/* singleton, initialized in cstring_new_empty */
static const struct cstring *cstring_EMPTY = NULL;
static void *_bad_argument_type(PyObject *o) {
PyErr_Format(
PyExc_TypeError,
"Bad argument type: %s",
Py_TYPE(o)->tp_name);
return NULL;
}
static PyObject *_cstring_new(PyTypeObject *type, const char *value, Py_ssize_t len) {
struct cstring *new = CSTRING_ALLOC(type, len + 1);
if(!new)
return NULL;
new->hash = -1;
memcpy(new->value, value, len);
CSTRING_LAST_BYTE(new) = '\0';
return (PyObject *)new;
}
static PyObject *_cstring_realloc(PyObject *self, Py_ssize_t len) {
if(Py_REFCNT(self) > 1)
return PyErr_BadInternalCall(), NULL;
struct cstring *new = PyObject_Realloc(self, sizeof(struct cstring) + len + 1);
if(!new)
return PyErr_NoMemory();
Py_SET_SIZE(new, len + 1);
new->hash = -1;
return (PyObject *)new;
}
static PyObject *_cstring_copy(PyObject *self) {
return _cstring_new(Py_TYPE(self), CSTRING_VALUE(self), Py_SIZE(self) - 1);
}
static PyObject *cstring_new_empty(void) {
if(!cstring_EMPTY) {
cstring_EMPTY = (struct cstring *)_cstring_new(&cstring_type, "", 0);
}
/* leaking one reference for singleton cache (never cleaned up) */
Py_INCREF(cstring_EMPTY);
return (PyObject *)cstring_EMPTY;
}
static const char *_obj_as_string_and_size(PyObject *o, Py_ssize_t *s) {
if(PyUnicode_Check(o))
return PyUnicode_AsUTF8AndSize(o, s);
if(PyObject_CheckBuffer(o)) {
/* handles bytes, bytearrays, arrays, memoryviews, etc. */
Py_buffer view;
if(PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) < 0)
return NULL;
*s = view.len;
const char *buffer = view.buf;
PyBuffer_Release(&view);
return buffer;
}
if(PyObject_TypeCheck(o, &cstring_type)) {
/* TODO: implement buffer protocol for cstring */
*s = Py_SIZE(o) - 1;
return CSTRING_VALUE(o);
}
*s = -1;
return _bad_argument_type(o);
}
static PyObject *cstring_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
PyObject *argobj = NULL;
if(!PyArg_ParseTuple(args, "O", &argobj))
return NULL;
if(PyObject_TypeCheck(argobj, type)) {
Py_INCREF(argobj);
return argobj;
}
Py_ssize_t len = 0;
const char *buffer = _obj_as_string_and_size(argobj, &len);
if(!buffer)
return NULL;
if(len == 0)
return cstring_new_empty();
return _cstring_new(type, buffer, len);
}
static void cstring_dealloc(PyObject *self) {
Py_TYPE(self)->tp_free(self);
}
static int _ensure_cstring(PyObject *self) {
if(PyObject_TypeCheck(self, &cstring_type))
return 1;
PyErr_Format(
PyExc_TypeError,
"Object must have type cstring, not %s.",
Py_TYPE(self)->tp_name);
return 0;
}
static PyObject *cstring_str(PyObject *self) {
return PyUnicode_FromString(CSTRING_VALUE(self));
}
static PyObject *cstring_repr(PyObject *self) {
PyObject *tmp = cstring_str(self);
PyObject *repr = PyObject_Repr(tmp);
Py_DECREF(tmp);
return repr;
}
static Py_hash_t cstring_hash(PyObject *self) {
if(CSTRING_HASH(self) == -1)
CSTRING_HASH(self) = _Py_HashBytes(CSTRING_VALUE(self), Py_SIZE(self));
return CSTRING_HASH(self);
}
static PyObject *cstring_richcompare(PyObject *self, PyObject *other, int op) {
if(!_ensure_cstring(other))
return NULL;
const char *left = CSTRING_VALUE(self);
const char *right = CSTRING_VALUE(other);
for(;*left && *right && *left == *right; ++left, ++right)
;
switch (op) {
case Py_EQ:
return PyBool_FromLong(*left == *right);
case Py_NE:
return PyBool_FromLong(*left != *right);
case Py_LT:
return PyBool_FromLong(*left < *right);
case Py_GT:
return PyBool_FromLong(*left > *right);
case Py_LE:
return PyBool_FromLong(*left = *right);
default:
Py_UNREACHABLE();
}
}
static Py_ssize_t cstring_len(PyObject *self) {
return Py_SIZE(self) - 1;
}
static PyObject *_concat_in_place(PyObject *self, PyObject *other) {
if(!other)
return PyErr_BadArgument(), NULL;
if(!_ensure_cstring(other))
return NULL;
if(!self)
return _cstring_copy(other); /* new (mutable) copy with refcnt=1 */
if(!_ensure_cstring(self))
return NULL;
Py_ssize_t origlen = cstring_len(self);
Py_ssize_t newlen = origlen + cstring_len(other);
PyObject *new = _cstring_realloc(self, newlen);
if(!new)
return NULL;
memcpy(CSTRING_VALUE_AT(new, origlen), CSTRING_VALUE(other), cstring_len(other));
CSTRING_LAST_BYTE(new) = '\0';
return new;
}
static PyObject *cstring_concat(PyObject *left, PyObject *right) {
if(!_ensure_cstring(left))
return NULL;
if(!_ensure_cstring(right))
return NULL;
Py_ssize_t size = cstring_len(left) + cstring_len(right) + 1;
struct cstring *new = CSTRING_ALLOC(Py_TYPE(left), size);
if(!new)
return NULL;
memcpy(new->value, CSTRING_VALUE(left), Py_SIZE(left));
memcpy(&new->value[cstring_len(left)], CSTRING_VALUE(right), Py_SIZE(right));
return (PyObject *)new;
}
static PyObject *cstring_repeat(PyObject *self, Py_ssize_t count) {
if(!_ensure_cstring(self))
return NULL;
if(count value[i], CSTRING_VALUE(self), Py_SIZE(self));
}
return (PyObject *)new;
}
static Py_ssize_t _ensure_valid_index(PyObject *self, Py_ssize_t i) {
if(i >= 0 && i < cstring_len(self))
return i;
PyErr_SetString(PyExc_IndexError, "Index is out of bounds");
return -1;
}
static PyObject *cstring_item(PyObject *self, Py_ssize_t i) {
if(_ensure_valid_index(self, i) < 0)
return NULL;
return _cstring_new(Py_TYPE(self), CSTRING_VALUE_AT(self, i), 1);
}
static int cstring_contains(PyObject *self, PyObject *arg) {
if(!_ensure_cstring(arg))
return -1;
if(strstr(CSTRING_VALUE(self), CSTRING_VALUE(arg)))
return 1;
return 0;
}
static PyObject *_cstring_subscript_index(PyObject *self, PyObject *index) {
Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError);
if(PyErr_Occurred())
return NULL;
if(i < 0)
i += cstring_len(self);
return cstring_item(self, i);
}
static PyObject *_cstring_subscript_slice(PyObject *self, PyObject *slice) {
Py_ssize_t start, stop, step;
if(PySlice_Unpack(slice, &start, &stop, &step) < 0)
return NULL;
Py_ssize_t slicelen = PySlice_AdjustIndices(cstring_len(self), &start, &stop, step);
struct cstring *new = CSTRING_ALLOC(Py_TYPE(self), slicelen + 1);
if(!new)
return NULL;
char *src = CSTRING_VALUE_AT(self, start);
for(Py_ssize_t i = 0; i < slicelen; ++i) {
new->value[i] = *src;
src += step;
}
new->value[slicelen] = '\0';
return (PyObject *)new;
}
static PyObject *cstring_subscript(PyObject *self, PyObject *key) {
if(PyIndex_Check(key))
return _cstring_subscript_index(self, key);
if(PySlice_Check(key))
return _cstring_subscript_slice(self, key);
PyErr_SetString(PyExc_TypeError, "Subscript must be int or slice.");
return NULL;
}
static Py_ssize_t _fix_index(Py_ssize_t i, Py_ssize_t len) {
Py_ssize_t result = i;
if(result < 0)
result += len;
if(result < 0)
result = 0;
if(result > len)
result = len;
return result;
}
struct _substr_params {
const char *start;
const char *end;
const char *substr;
Py_ssize_t substr_len;
};
static struct _substr_params *_parse_substr_args(PyObject *self, PyObject *args, struct _substr_params *params) {
PyObject *substr_obj;
Py_ssize_t start = 0;
Py_ssize_t end = PY_SSIZE_T_MAX;
if(!PyArg_ParseTuple(args, "O|nn", &substr_obj, &start, &end))
return NULL;
Py_ssize_t substr_len;
const char *substr = _obj_as_string_and_size(substr_obj, &substr_len);
if(!substr)
return NULL;
start = _fix_index(start, cstring_len(self));
end = _fix_index(end, cstring_len(self));
params->start = CSTRING_VALUE_AT(self, start);
params->end = CSTRING_VALUE_AT(self, end);
params->substr = substr;
params->substr_len = substr_len;
return params;
}
PyDoc_STRVAR(count__doc__, "");
static PyObject *cstring_count(PyObject *self, PyObject *args) {
struct _substr_params params;
if(!_parse_substr_args(self, args, ¶ms))
return NULL;
const char *p = params.start;
long result = 0;
while((p = strstr(p, params.substr)) != NULL) {
++result;
p += params.substr_len;
if(p >= params.end)
break;
}
return PyLong_FromLong(result);
}
static const char *_substr_params_str(const struct _substr_params *params) {
const char *p = strstr(params->start, params->substr);
if(!p || p + params->substr_len > params->end)
return NULL;
return p;
}
static const char *_substr_params_rstr(const struct _substr_params *params) {
const char *p = params->end - params->substr_len + 1;
for(;;) {
p = _memrchr(params->start, *params->substr, p - params->start);
if(!p)
goto done;
if(memcmp(p, params->substr, params->substr_len) == 0)
return p;
}
done:
return NULL;
}
PyDoc_STRVAR(find__doc__, "");
PyObject *cstring_find(PyObject *self, PyObject *args) {
struct _substr_params params;
if(!_parse_substr_args(self, args, ¶ms))
return NULL;
const char *p = _substr_params_str(¶ms);
if(!p)
return PyLong_FromLong(-1);
return PyLong_FromSsize_t(p - CSTRING_VALUE(self));
}
PyDoc_STRVAR(index__doc__, "");
PyObject *cstring_index(PyObject *self, PyObject *args) {
struct _substr_params params;
if(!_parse_substr_args(self, args, ¶ms))
return NULL;
const char *p = _substr_params_str(¶ms);
if(!p) {
PyErr_SetString(PyExc_ValueError, "substring not found");
return NULL;
}
return PyLong_FromSsize_t(p - CSTRING_VALUE(self));
}
PyDoc_STRVAR(isalnum__doc__, "");
PyObject *cstring_isalnum(PyObject *self, PyObject *args) {
const char *p = CSTRING_VALUE(self);
while(*p) {
if(!isalnum(*p))
Py_RETURN_FALSE;
++p;
}
Py_RETURN_TRUE;
}
PyDoc_STRVAR(isalpha__doc__, "");
PyObject *cstring_isalpha(PyObject *self, PyObject *args) {
const char *p = CSTRING_VALUE(self);
while(*p) {
if(!isalpha(*p))
Py_RETURN_FALSE;
++p;
}
Py_RETURN_TRUE;
}
PyDoc_STRVAR(isdigit__doc__, "");
PyObject *cstring_isdigit(PyObject *self, PyObject *args) {
const char *p = CSTRING_VALUE(self);
while(*p) {
if(!isdigit(*p))
Py_RETURN_FALSE;
++p;
}
Py_RETURN_TRUE;
}
PyDoc_STRVAR(islower__doc__, "");
PyObject *cstring_islower(PyObject *self, PyObject *args) {
const char *p = CSTRING_VALUE(self);
while(*p) {
if(isalpha(*p)) {
if(!islower(*p))
Py_RETURN_FALSE;
++p;
while(*p) {
if(isalpha(*p) && !islower(*p))
Py_RETURN_FALSE;
++p;
}
/* at least one lc alpha and no uc alphas */
Py_RETURN_TRUE;
}
++p;
}
Py_RETURN_FALSE;
}
PyDoc_STRVAR(isprintable__doc__, "");
PyObject *cstring_isprintable(PyObject *self, PyObject *args) {
const char *p = CSTRING_VALUE(self);
while(*p) {
if(!isprint(*p))
Py_RETURN_FALSE;
++p;
}
Py_RETURN_TRUE;
}
PyDoc_STRVAR(isspace__doc__, "");
PyObject *cstring_isspace(PyObject *self, PyObject *args) {
const char *p = CSTRING_VALUE(self);
while(*p) {
if(!isspace(*p))
Py_RETURN_FALSE;
++p;
}
return PyBool_FromLong(p != CSTRING_VALUE(self));
}
PyDoc_STRVAR(isupper__doc__, "");
PyObject *cstring_isupper(PyObject *self, PyObject *args) {
const char *p = CSTRING_VALUE(self);
while(*p) {
if(isalpha(*p)) {
if(!isupper(*p))
Py_RETURN_FALSE;
++p;
while(*p) {
if(isalpha(*p) && !isupper(*p))
Py_RETURN_FALSE;
++p;
}
/* at least one uc alpha and no lc alphas */
Py_RETURN_TRUE;
}
++p;
}
Py_RETURN_FALSE;
}
PyDoc_STRVAR(join__doc__, "");
PyObject *cstring_join(PyObject *self, PyObject *arg) {
PyObject *iter = PyObject_GetIter(arg);
if(!iter)
return NULL;
PyObject *result = NULL;
PyObject *item = NULL;
while((item = PyIter_Next(iter)) != NULL) {
if(result) {
PyObject *next = _concat_in_place(result, self);
if(!next)
goto fail;
result = next;
}
PyObject *next = _concat_in_place(result, item);
if(!next)
goto fail;
Py_DECREF(item);
result = next;
}
return result;
fail:
Py_XDECREF(item);
Py_XDECREF(result);
return NULL;
}
PyDoc_STRVAR(lower__doc__, "");
PyObject *cstring_lower(PyObject *self, PyObject *args) {
struct cstring *new = CSTRING_ALLOC(Py_TYPE(self), Py_SIZE(self));
if(!new)
return NULL;
const char *s = CSTRING_VALUE(self);
char *d = CSTRING_VALUE(new);
while((*d++ = tolower(*s++)) != '\0')
;
return (PyObject *)new;
}
static PyObject *_tuple_steal_refs(Py_ssize_t count, ...) {
PyObject *result = PyTuple_New(count);
if(!result)
return NULL;
va_list va;
va_start(va, count);
for(int i = 0; i < count; ++i) {
PyObject *o = va_arg(va, PyObject *);
if(!o)
goto fail;
PyTuple_SET_ITEM(result, i, o);
}
va_end(va);
return result;
fail:
Py_DECREF(result);
return NULL;
}
PyDoc_STRVAR(partition__doc__, "");
PyObject *cstring_partition(PyObject *self, PyObject *arg) {
if(!_ensure_cstring(arg))
return NULL;
const char *search = CSTRING_VALUE(arg);
const char *left = CSTRING_VALUE(self);
const char *mid = strstr(left, search);
if(!mid) {
return _tuple_steal_refs(3,
(Py_INCREF(self), self),
cstring_new_empty(),
cstring_new_empty());
}
const char *right = mid + strlen(search);
return _tuple_steal_refs(3,
_cstring_new(Py_TYPE(self), left, mid - left),
_cstring_new(Py_TYPE(self), mid, right - mid),
_cstring_new(Py_TYPE(self), right, &CSTRING_LAST_BYTE(self) - right));
}
PyDoc_STRVAR(rpartition__doc__, "");
PyObject *cstring_rpartition(PyObject *self, PyObject *arg) {
if(!_ensure_cstring(arg))
return NULL;
const char *search = CSTRING_VALUE(arg);
const char *left = CSTRING_VALUE(self);
const char *mid = _strrstr(left, search);
if(!mid) {
return _tuple_steal_refs(3,
cstring_new_empty(),
cstring_new_empty(),
(Py_INCREF(self), self));
}
const char *right = mid + strlen(search);
return _tuple_steal_refs(3,
_cstring_new(Py_TYPE(self), left, mid - left),
_cstring_new(Py_TYPE(self), mid, right - mid),
_cstring_new(Py_TYPE(self), right, &CSTRING_LAST_BYTE(self) - right));
}
PyDoc_STRVAR(rfind__doc__, "");
PyObject *cstring_rfind(PyObject *self, PyObject *args) {
struct _substr_params params;
if(!_parse_substr_args(self, args, ¶ms))
return NULL;
const char *p = _substr_params_rstr(¶ms);
if(!p)
return PyLong_FromLong(-1);
return PyLong_FromSsize_t(p - CSTRING_VALUE(self));
}
PyDoc_STRVAR(rindex__doc__, "");
PyObject *cstring_rindex(PyObject *self, PyObject *args) {
struct _substr_params params;
if(!_parse_substr_args(self, args, ¶ms))
return NULL;
const char *p = _substr_params_rstr(¶ms);
if(!p) {
PyErr_SetString(PyExc_ValueError, "substring not found");
return NULL;
}
return PyLong_FromSsize_t(p - CSTRING_VALUE(self));
}
PyObject *_cstring_split_on_chars(PyObject *self, const char seps[], Py_ssize_t maxsplit) {
if(maxsplit < 0)
maxsplit = PY_SSIZE_T_MAX;
const char *start = CSTRING_VALUE(self);
PyObject *list = PyList_New(0);
if(!list)
return NULL;
while(*start) {
const char *end = start;
while(*end && !strchr(seps, *end))
++end;
PyObject *new = _cstring_new(Py_TYPE(self), start, end - start);
if(!new)
goto fail;
PyList_Append(list, new);
Py_DECREF(new);
const char *skip = end + 1;
while(*skip && strchr(seps, *skip))
++skip;
start = skip;
if(PyList_GET_SIZE(list) + 1 > maxsplit) {
PyObject *new = _cstring_new(Py_TYPE(self), start, strlen(start));
if(!new)
goto fail;
PyList_Append(list, new);
Py_DECREF(new);
break;
}
}
return list;
fail:
Py_DECREF(list);
return NULL;
}
PyObject *_cstring_split_on_cstring(PyObject *self, PyObject *sepobj, Py_ssize_t maxsplit) {
if(!_ensure_cstring(sepobj))
return NULL;
if(maxsplit < 0)
maxsplit = PY_SSIZE_T_MAX;
PyObject *list = PyList_New(0);
if(!list)
return NULL;
const char *sep = CSTRING_VALUE(sepobj);
const char *s = CSTRING_VALUE(self);
for(;;) {
const char *e = strstr(s, sep);
if(!e)
break;
PyObject *new = _cstring_new(Py_TYPE(self), s, e - s);
if(!new)
goto fail;
PyList_Append(list, new);
Py_DECREF(new);
s = e + strlen(sep);
if(PyList_GET_SIZE(list) + 1 > maxsplit)
break;
}
PyObject *new = _cstring_new(Py_TYPE(self), s, strlen(s));
if(!new)
goto fail;
PyList_Append(list, new);
return list;
fail:
Py_DECREF(list);
return NULL;
}
PyDoc_STRVAR(split__doc__, "");
PyObject *cstring_split(PyObject *self, PyObject *args, PyObject *kwargs) {
PyObject *sepobj = Py_None;
int maxsplit = -1;
char *kwlist[] = {"sep", "maxsplit", NULL};
if(!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi", kwlist, &sepobj, &maxsplit))
return NULL;
return (sepobj == Py_None)
? _cstring_split_on_chars(self, WHITESPACE_CHARS, maxsplit)
: _cstring_split_on_cstring(self, sepobj, maxsplit);
}
PyDoc_STRVAR(startswith__doc__, "");
PyObject *cstring_startswith(PyObject *self, PyObject *args) {
struct _substr_params params;
if(!_parse_substr_args(self, args, ¶ms))
return NULL;
if(params.end - params.start < params.substr_len)
return PyBool_FromLong(0);
int cmp = memcmp(params.start, params.substr, params.substr_len);
return PyBool_FromLong(cmp == 0);
}
const char *_strip_chars_from_args(PyObject *args) {
PyObject *charsobj = NULL;
if(!PyArg_ParseTuple(args, "|O", &charsobj))
return NULL;
const char *chars = WHITESPACE_CHARS;
if(charsobj && charsobj != Py_None) {
if(!PyUnicode_Check(charsobj))
return _bad_argument_type(charsobj);
chars = PyUnicode_AsUTF8(charsobj);
}
return chars;
}
PyDoc_STRVAR(strip__doc__, "");
PyObject *cstring_strip(PyObject *self, PyObject *args) {
const char *chars = _strip_chars_from_args(args);
const char *start = CSTRING_VALUE(self);
while(strchr(chars, *start))
++start;
const char *end = &CSTRING_LAST_BYTE(self) - 1;
while(strchr(chars, *end))
--end;
Py_ssize_t newsize = end - start + 1;
return _cstring_new(Py_TYPE(self), start, newsize);
}
PyDoc_STRVAR(lstrip__doc__, "");
PyObject *cstring_lstrip(PyObject *self, PyObject *args) {
const char *chars = _strip_chars_from_args(args);
const char *start = CSTRING_VALUE(self);
while(strchr(chars, *start))
++start;
const char *end = &CSTRING_LAST_BYTE(self) - 1;
Py_ssize_t newsize = end - start + 1;
return _cstring_new(Py_TYPE(self), start, newsize);
}
PyDoc_STRVAR(rstrip__doc__, "");
PyObject *cstring_rstrip(PyObject *self, PyObject *args) {
const char *chars = _strip_chars_from_args(args);
const char *start = CSTRING_VALUE(self);
const char *end = &CSTRING_LAST_BYTE(self) - 1;
while(strchr(chars, *end))
--end;
Py_ssize_t newsize = end - start + 1;
return _cstring_new(Py_TYPE(self), start, newsize);
}
PyDoc_STRVAR(endswith__doc__, "");
PyObject *cstring_endswith(PyObject *self, PyObject *args) {
struct _substr_params params;
if(!_parse_substr_args(self, args, ¶ms))
return NULL;
if(params.end - params.start < params.substr_len)
return PyBool_FromLong(0);
int cmp = memcmp(params.end - params.substr_len, params.substr, params.substr_len);
return PyBool_FromLong(cmp == 0);
}
PyDoc_STRVAR(swapcase__doc__, "");
PyObject *cstring_swapcase(PyObject *self, PyObject *args) {
struct cstring *new = CSTRING_ALLOC(Py_TYPE(self), Py_SIZE(self));
if(!new)
return NULL;
const char *s = CSTRING_VALUE(self);
char *d = CSTRING_VALUE(new);
for(;*s; ++s, ++d) {
if(islower(*s)) {
*d = toupper(*s);
} else if(isupper(*s)) {
*d = tolower(*s);
} else {
*d = *s;
}
}
return (PyObject *)new;
}
PyDoc_STRVAR(upper__doc__, "");
PyObject *cstring_upper(PyObject *self, PyObject *args) {
struct cstring *new = CSTRING_ALLOC(Py_TYPE(self), Py_SIZE(self));
if(!new)
return NULL;
const char *s = CSTRING_VALUE(self);
char *d = CSTRING_VALUE(new);
while((*d++ = toupper(*s++)) != '\0')
;
return (PyObject *)new;
}
static PySequenceMethods cstring_as_sequence = {
.sq_length = cstring_len,
.sq_concat = cstring_concat,
.sq_repeat = cstring_repeat,
.sq_item = cstring_item,
.sq_contains = cstring_contains,
};
static PyMappingMethods cstring_as_mapping = {
.mp_length = cstring_len,
.mp_subscript = cstring_subscript,
};
static PyMethodDef cstring_methods[] = {
/* TODO: capitalize */
/* TODO: casefold */
/* TODO: center */
{"count", cstring_count, METH_VARARGS, count__doc__},
/* TODO: encode (decode???) */
{"endswith", cstring_endswith, METH_VARARGS, endswith__doc__},
/* TODO: expandtabs */
{"find", cstring_find, METH_VARARGS, find__doc__},
/* TODO: format */
/* TODO: format_map */
{"index", cstring_index, METH_VARARGS, index__doc__},
{"isalnum", cstring_isalnum, METH_NOARGS, isalnum__doc__},
{"isalpha", cstring_isalpha, METH_NOARGS, isalpha__doc__},
/* TODO: isascii */
/* TODO: isdecimal */
{"isdigit", cstring_isdigit, METH_NOARGS, isdigit__doc__},
/* TODO: isidentifier */
{"islower", cstring_islower, METH_NOARGS, islower__doc__},
/* TODO: isnumeric */
{"isprintable", cstring_isprintable, METH_NOARGS, isprintable__doc__},
{"isspace", cstring_isspace, METH_NOARGS, isspace__doc__},
/* TODO: istitle */
{"isupper", cstring_isupper, METH_NOARGS, isupper__doc__},
{"join", cstring_join, METH_O, join__doc__},
/* TODO: ljust */
{"lower", cstring_lower, METH_NOARGS, lower__doc__},
{"lstrip", cstring_lstrip, METH_VARARGS, lstrip__doc__},
/* TODO: maketrans */
{"partition", cstring_partition, METH_O, partition__doc__},
/* TODO: removeprefix */
/* TODO: replace */
{"rfind", cstring_rfind, METH_VARARGS, rfind__doc__},
{"rindex", cstring_rindex, METH_VARARGS, rindex__doc__},
/* TODO: rjust */
{"rpartition", cstring_rpartition, METH_O, rpartition__doc__},
/* TODO: rsplit */
{"rstrip", cstring_rstrip, METH_VARARGS, rstrip__doc__},
{"split", (PyCFunction)cstring_split, METH_VARARGS | METH_KEYWORDS, split__doc__},
/* TODO: splitlines */
{"startswith", cstring_startswith, METH_VARARGS, startswith__doc__},
{"strip", cstring_strip, METH_VARARGS, strip__doc__},
{"swapcase", cstring_swapcase, METH_NOARGS, swapcase__doc__},
/* TODO: title */
/* TODO: translate */
{"upper", cstring_upper, METH_NOARGS, upper__doc__},
/* TODO: zfill */
{0},
};
static PyTypeObject cstring_type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "cstring.cstring",
.tp_doc = "",
.tp_basicsize = sizeof(struct cstring),
.tp_itemsize = sizeof(char),
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = cstring_new,
.tp_dealloc = cstring_dealloc,
.tp_richcompare = cstring_richcompare,
.tp_str = cstring_str,
.tp_repr = cstring_repr,
.tp_hash = cstring_hash,
.tp_as_sequence = &cstring_as_sequence,
.tp_as_mapping = &cstring_as_mapping,
.tp_methods = cstring_methods,
};
static struct PyModuleDef module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "cstring",
.m_doc = "",
.m_size = 0,
.m_methods = NULL,
};
PyMODINIT_FUNC PyInit_cstring(void) {
if(PyType_Ready(&cstring_type) < 0)
return NULL;
Py_INCREF(&cstring_type);
PyObject *m = PyModule_Create(&module);
PyModule_AddObject(m, "cstring", (PyObject *)&cstring_type);
return m;
}