Commit 045a4279 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #978 from undingen/pyxl2

Misc optimizations for pyxl2
parents d44733b1 82459763
...@@ -402,3 +402,543 @@ done: ...@@ -402,3 +402,543 @@ done:
Py_XDECREF(tmp); Py_XDECREF(tmp);
return result; return result;
} }
/* find and count characters and substrings */
#define findchar(target, target_len, c) \
((char *)memchr((const void *)(target), c, target_len))
/* String ops must return a string. */
/* If the object is subclass of string, create a copy */
Py_LOCAL(PyStringObject *)
return_self(PyStringObject *self)
{
if (PyString_CheckExact(self)) {
Py_INCREF(self);
return self;
}
return (PyStringObject *)PyString_FromStringAndSize(
PyString_AS_STRING(self),
PyString_GET_SIZE(self));
}
Py_LOCAL_INLINE(Py_ssize_t)
countchar(const char *target, Py_ssize_t target_len, char c, Py_ssize_t maxcount)
{
Py_ssize_t count=0;
const char *start=target;
const char *end=target+target_len;
while ( (start=findchar(start, end-start, c)) != NULL ) {
count++;
if (count >= maxcount)
break;
start += 1;
}
return count;
}
/* Algorithms for different cases of string replacement */
/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_interleave(PyStringObject *self,
const char *to_s, Py_ssize_t to_len,
Py_ssize_t maxcount)
{
char *self_s, *result_s;
Py_ssize_t self_len, result_len;
Py_ssize_t count, i, product;
PyStringObject *result;
self_len = PyString_GET_SIZE(self);
/* 1 at the end plus 1 after every character */
count = self_len+1;
if (maxcount < count)
count = maxcount;
/* Check for overflow */
/* result_len = count * to_len + self_len; */
product = count * to_len;
if (product / to_len != count) {
PyErr_SetString(PyExc_OverflowError,
"replace string is too long");
return NULL;
}
result_len = product + self_len;
if (result_len < 0) {
PyErr_SetString(PyExc_OverflowError,
"replace string is too long");
return NULL;
}
if (! (result = (PyStringObject *)
PyString_FromStringAndSize(NULL, result_len)) )
return NULL;
self_s = PyString_AS_STRING(self);
result_s = PyString_AS_STRING(result);
/* TODO: special case single character, which doesn't need memcpy */
/* Lay the first one down (guaranteed this will occur) */
Py_MEMCPY(result_s, to_s, to_len);
result_s += to_len;
count -= 1;
for (i=0; i<count; i++) {
*result_s++ = *self_s++;
Py_MEMCPY(result_s, to_s, to_len);
result_s += to_len;
}
/* Copy the rest of the original string */
Py_MEMCPY(result_s, self_s, self_len-i);
return result;
}
/* Special case for deleting a single character */
/* len(self)>=1, len(from)==1, to="", maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_delete_single_character(PyStringObject *self,
char from_c, Py_ssize_t maxcount)
{
char *self_s, *result_s;
char *start, *next, *end;
Py_ssize_t self_len, result_len;
Py_ssize_t count;
PyStringObject *result;
self_len = PyString_GET_SIZE(self);
self_s = PyString_AS_STRING(self);
count = countchar(self_s, self_len, from_c, maxcount);
if (count == 0) {
return return_self(self);
}
result_len = self_len - count; /* from_len == 1 */
assert(result_len>=0);
if ( (result = (PyStringObject *)
PyString_FromStringAndSize(NULL, result_len)) == NULL)
return NULL;
result_s = PyString_AS_STRING(result);
start = self_s;
end = self_s + self_len;
while (count-- > 0) {
next = findchar(start, end-start, from_c);
if (next == NULL)
break;
Py_MEMCPY(result_s, start, next-start);
result_s += (next-start);
start = next+1;
}
Py_MEMCPY(result_s, start, end-start);
return result;
}
/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_delete_substring(PyStringObject *self,
const char *from_s, Py_ssize_t from_len,
Py_ssize_t maxcount) {
char *self_s, *result_s;
char *start, *next, *end;
Py_ssize_t self_len, result_len;
Py_ssize_t count, offset;
PyStringObject *result;
self_len = PyString_GET_SIZE(self);
self_s = PyString_AS_STRING(self);
count = stringlib_count(self_s, self_len,
from_s, from_len,
maxcount);
if (count == 0) {
/* no matches */
return return_self(self);
}
result_len = self_len - (count * from_len);
assert (result_len>=0);
if ( (result = (PyStringObject *)
PyString_FromStringAndSize(NULL, result_len)) == NULL )
return NULL;
result_s = PyString_AS_STRING(result);
start = self_s;
end = self_s + self_len;
while (count-- > 0) {
offset = stringlib_find(start, end-start,
from_s, from_len,
0);
if (offset == -1)
break;
next = start + offset;
Py_MEMCPY(result_s, start, next-start);
result_s += (next-start);
start = next+from_len;
}
Py_MEMCPY(result_s, start, end-start);
return result;
}
/* len(self)>=1, len(from)==len(to)==1, maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_single_character_in_place(PyStringObject *self,
char from_c, char to_c,
Py_ssize_t maxcount)
{
char *self_s, *result_s, *start, *end, *next;
Py_ssize_t self_len;
PyStringObject *result;
/* The result string will be the same size */
self_s = PyString_AS_STRING(self);
self_len = PyString_GET_SIZE(self);
next = findchar(self_s, self_len, from_c);
if (next == NULL) {
/* No matches; return the original string */
return return_self(self);
}
/* Need to make a new string */
result = (PyStringObject *) PyString_FromStringAndSize(NULL, self_len);
if (result == NULL)
return NULL;
result_s = PyString_AS_STRING(result);
Py_MEMCPY(result_s, self_s, self_len);
/* change everything in-place, starting with this one */
start = result_s + (next-self_s);
*start = to_c;
start++;
end = result_s + self_len;
while (--maxcount > 0) {
next = findchar(start, end-start, from_c);
if (next == NULL)
break;
*next = to_c;
start = next+1;
}
return result;
}
/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_substring_in_place(PyStringObject *self,
const char *from_s, Py_ssize_t from_len,
const char *to_s, Py_ssize_t to_len,
Py_ssize_t maxcount)
{
char *result_s, *start, *end;
char *self_s;
Py_ssize_t self_len, offset;
PyStringObject *result;
/* The result string will be the same size */
self_s = PyString_AS_STRING(self);
self_len = PyString_GET_SIZE(self);
offset = stringlib_find(self_s, self_len,
from_s, from_len,
0);
if (offset == -1) {
/* No matches; return the original string */
return return_self(self);
}
/* Need to make a new string */
result = (PyStringObject *) PyString_FromStringAndSize(NULL, self_len);
if (result == NULL)
return NULL;
result_s = PyString_AS_STRING(result);
Py_MEMCPY(result_s, self_s, self_len);
/* change everything in-place, starting with this one */
start = result_s + offset;
Py_MEMCPY(start, to_s, from_len);
start += from_len;
end = result_s + self_len;
while ( --maxcount > 0) {
offset = stringlib_find(start, end-start,
from_s, from_len,
0);
if (offset==-1)
break;
Py_MEMCPY(start+offset, to_s, from_len);
start += offset+from_len;
}
return result;
}
/* len(self)>=1, len(from)==1, len(to)>=2, maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_single_character(PyStringObject *self,
char from_c,
const char *to_s, Py_ssize_t to_len,
Py_ssize_t maxcount)
{
char *self_s, *result_s;
char *start, *next, *end;
Py_ssize_t self_len, result_len;
Py_ssize_t count, product;
PyStringObject *result;
self_s = PyString_AS_STRING(self);
self_len = PyString_GET_SIZE(self);
count = countchar(self_s, self_len, from_c, maxcount);
if (count == 0) {
/* no matches, return unchanged */
return return_self(self);
}
/* use the difference between current and new, hence the "-1" */
/* result_len = self_len + count * (to_len-1) */
product = count * (to_len-1);
if (product / (to_len-1) != count) {
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
return NULL;
}
result_len = self_len + product;
if (result_len < 0) {
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
return NULL;
}
if ( (result = (PyStringObject *)
PyString_FromStringAndSize(NULL, result_len)) == NULL)
return NULL;
result_s = PyString_AS_STRING(result);
start = self_s;
end = self_s + self_len;
while (count-- > 0) {
next = findchar(start, end-start, from_c);
if (next == NULL)
break;
if (next == start) {
/* replace with the 'to' */
Py_MEMCPY(result_s, to_s, to_len);
result_s += to_len;
start += 1;
} else {
/* copy the unchanged old then the 'to' */
Py_MEMCPY(result_s, start, next-start);
result_s += (next-start);
Py_MEMCPY(result_s, to_s, to_len);
result_s += to_len;
start = next+1;
}
}
/* Copy the remainder of the remaining string */
Py_MEMCPY(result_s, start, end-start);
return result;
}
/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_substring(PyStringObject *self,
const char *from_s, Py_ssize_t from_len,
const char *to_s, Py_ssize_t to_len,
Py_ssize_t maxcount) {
char *self_s, *result_s;
char *start, *next, *end;
Py_ssize_t self_len, result_len;
Py_ssize_t count, offset, product;
PyStringObject *result;
self_s = PyString_AS_STRING(self);
self_len = PyString_GET_SIZE(self);
count = stringlib_count(self_s, self_len,
from_s, from_len,
maxcount);
if (count == 0) {
/* no matches, return unchanged */
return return_self(self);
}
/* Check for overflow */
/* result_len = self_len + count * (to_len-from_len) */
product = count * (to_len-from_len);
if (product / (to_len-from_len) != count) {
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
return NULL;
}
result_len = self_len + product;
if (result_len < 0) {
PyErr_SetString(PyExc_OverflowError, "replace string is too long");
return NULL;
}
if ( (result = (PyStringObject *)
PyString_FromStringAndSize(NULL, result_len)) == NULL)
return NULL;
result_s = PyString_AS_STRING(result);
start = self_s;
end = self_s + self_len;
while (count-- > 0) {
offset = stringlib_find(start, end-start,
from_s, from_len,
0);
if (offset == -1)
break;
next = start+offset;
if (next == start) {
/* replace with the 'to' */
Py_MEMCPY(result_s, to_s, to_len);
result_s += to_len;
start += from_len;
} else {
/* copy the unchanged old then the 'to' */
Py_MEMCPY(result_s, start, next-start);
result_s += (next-start);
Py_MEMCPY(result_s, to_s, to_len);
result_s += to_len;
start = next+from_len;
}
}
/* Copy the remainder of the remaining string */
Py_MEMCPY(result_s, start, end-start);
return result;
}
Py_LOCAL(PyStringObject *)
replace(PyStringObject *self,
const char *from_s, Py_ssize_t from_len,
const char *to_s, Py_ssize_t to_len,
Py_ssize_t maxcount)
{
if (maxcount < 0) {
maxcount = PY_SSIZE_T_MAX;
} else if (maxcount == 0 || PyString_GET_SIZE(self) == 0) {
/* nothing to do; return the original string */
return return_self(self);
}
if (maxcount == 0 ||
(from_len == 0 && to_len == 0)) {
/* nothing to do; return the original string */
return return_self(self);
}
/* Handle zero-length special cases */
if (from_len == 0) {
/* insert the 'to' string everywhere. */
/* >>> "Python".replace("", ".") */
/* '.P.y.t.h.o.n.' */
return replace_interleave(self, to_s, to_len, maxcount);
}
/* Except for "".replace("", "A") == "A" there is no way beyond this */
/* point for an empty self string to generate a non-empty string */
/* Special case so the remaining code always gets a non-empty string */
if (PyString_GET_SIZE(self) == 0) {
return return_self(self);
}
if (to_len == 0) {
/* delete all occurances of 'from' string */
if (from_len == 1) {
return replace_delete_single_character(
self, from_s[0], maxcount);
} else {
return replace_delete_substring(self, from_s, from_len, maxcount);
}
}
/* Handle special case where both strings have the same length */
if (from_len == to_len) {
if (from_len == 1) {
return replace_single_character_in_place(
self,
from_s[0],
to_s[0],
maxcount);
} else {
return replace_substring_in_place(
self, from_s, from_len, to_s, to_len, maxcount);
}
}
/* Otherwise use the more generic algorithms */
if (from_len == 1) {
return replace_single_character(self, from_s[0],
to_s, to_len, maxcount);
} else {
/* len('from')>=2, len('to')>=1 */
return replace_substring(self, from_s, from_len, to_s, to_len, maxcount);
}
}
// Pyston change: don't use varags calling convention
// PyObject* string_replace(PyStringObject *self, PyObject *args)
PyObject* string_replace(PyStringObject *self, PyObject *from, PyObject* to, PyObject** args)
{
PyObject* _count = args[0];
Py_ssize_t count = -1;
const char *from_s, *to_s;
Py_ssize_t from_len, to_len;
// Pyston change: don't use varags calling convention
// if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
// return NULL;
if (_count && !PyArg_ParseSingle(_count, 3, "replace", "n", &count))
return NULL;
if (PyString_Check(from)) {
from_s = PyString_AS_STRING(from);
from_len = PyString_GET_SIZE(from);
}
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(from))
return PyUnicode_Replace((PyObject *)self,
from, to, count);
#endif
else if (PyObject_AsCharBuffer(from, &from_s, &from_len))
return NULL;
if (PyString_Check(to)) {
to_s = PyString_AS_STRING(to);
to_len = PyString_GET_SIZE(to);
}
#ifdef Py_USING_UNICODE
else if (PyUnicode_Check(to))
return PyUnicode_Replace((PyObject *)self,
from, to, count);
#endif
else if (PyObject_AsCharBuffer(to, &to_s, &to_len))
return NULL;
return (PyObject *)replace((PyStringObject *) self,
from_s, from_len,
to_s, to_len, count);
}
...@@ -894,11 +894,12 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name) ...@@ -894,11 +894,12 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name)
/* Pyston change: static */ PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept { /* Pyston change: static */ PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
assert(name->cls == str_cls); assert(name->cls == str_cls);
return slotTpGetattrHookInternal<CAPI, NOT_REWRITABLE>(self, (BoxedString*)name, NULL); return slotTpGetattrHookInternal<CAPI, NOT_REWRITABLE>(self, (BoxedString*)name, NULL, false, NULL, NULL);
} }
template <ExceptionStyle S, Rewritable rewritable> template <ExceptionStyle S, Rewritable rewritable>
Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI) { Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* rewrite_args, bool for_call,
Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI) {
if (rewritable == NOT_REWRITABLE) { if (rewritable == NOT_REWRITABLE) {
assert(!rewrite_args); assert(!rewrite_args);
rewrite_args = NULL; rewrite_args = NULL;
...@@ -982,7 +983,8 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -982,7 +983,8 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
try { try {
assert(!PyType_Check(self)); // There would be a getattribute assert(!PyType_Check(self)); // There would be a getattribute
res = getattrInternalGeneric<false, rewritable>(self, name, &grewrite_args, false, false, NULL, NULL); res = getattrInternalGeneric<false, rewritable>(self, name, &grewrite_args, false, for_call,
bind_obj_out, r_bind_obj_out);
} catch (ExcInfo e) { } catch (ExcInfo e) {
if (!e.matches(AttributeError)) { if (!e.matches(AttributeError)) {
if (S == CAPI) { if (S == CAPI) {
...@@ -1108,13 +1110,17 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1108,13 +1110,17 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
} }
// Force instantiation of the template // Force instantiation of the template
template Box* slotTpGetattrHookInternal<CAPI, REWRITABLE>(Box* self, BoxedString* name, template Box* slotTpGetattrHookInternal<CAPI, REWRITABLE>(Box* self, BoxedString* name,
GetattrRewriteArgs* rewrite_args); GetattrRewriteArgs* rewrite_args, bool for_call,
template Box* slotTpGetattrHookInternal<CXX, REWRITABLE>(Box* self, BoxedString* name, Box** bind_obj_out, RewriterVar** r_bind_obj_out);
GetattrRewriteArgs* rewrite_args); template Box* slotTpGetattrHookInternal<CXX, REWRITABLE>(Box* self, BoxedString* name, GetattrRewriteArgs* rewrite_args,
bool for_call, Box** bind_obj_out,
RewriterVar** r_bind_obj_out);
template Box* slotTpGetattrHookInternal<CAPI, NOT_REWRITABLE>(Box* self, BoxedString* name, template Box* slotTpGetattrHookInternal<CAPI, NOT_REWRITABLE>(Box* self, BoxedString* name,
GetattrRewriteArgs* rewrite_args); GetattrRewriteArgs* rewrite_args, bool for_call,
Box** bind_obj_out, RewriterVar** r_bind_obj_out);
template Box* slotTpGetattrHookInternal<CXX, NOT_REWRITABLE>(Box* self, BoxedString* name, template Box* slotTpGetattrHookInternal<CXX, NOT_REWRITABLE>(Box* self, BoxedString* name,
GetattrRewriteArgs* rewrite_args); GetattrRewriteArgs* rewrite_args, bool for_call,
Box** bind_obj_out, RewriterVar** r_bind_obj_out);
/* Pyston change: static */ PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept { /* Pyston change: static */ PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept {
STAT_TIMER(t0, "us_timer_slot_tpnew", SLOT_AVOIDABILITY(self)); STAT_TIMER(t0, "us_timer_slot_tpnew", SLOT_AVOIDABILITY(self));
......
...@@ -56,7 +56,8 @@ int slot_tp_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept; ...@@ -56,7 +56,8 @@ int slot_tp_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept;
class GetattrRewriteArgs; class GetattrRewriteArgs;
template <ExceptionStyle S, Rewritable rewritable> template <ExceptionStyle S, Rewritable rewritable>
Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI); Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool for_call,
Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI);
} }
#endif #endif
...@@ -357,6 +357,8 @@ GCAllocation* SmallArena::realloc(GCAllocation* al, size_t bytes) { ...@@ -357,6 +357,8 @@ GCAllocation* SmallArena::realloc(GCAllocation* al, size_t bytes) {
#else #else
memcpy(rtn, al, std::min(bytes, size)); memcpy(rtn, al, std::min(bytes, size));
#endif #endif
if (bytesAllocatedSinceCollection > size)
bytesAllocatedSinceCollection -= size;
free(al); free(al);
return rtn; return rtn;
...@@ -772,6 +774,9 @@ GCAllocation* LargeArena::realloc(GCAllocation* al, size_t bytes) { ...@@ -772,6 +774,9 @@ GCAllocation* LargeArena::realloc(GCAllocation* al, size_t bytes) {
GCAllocation* rtn = heap->alloc(bytes); GCAllocation* rtn = heap->alloc(bytes);
memcpy(rtn, al, std::min(bytes, obj->size)); memcpy(rtn, al, std::min(bytes, obj->size));
if (bytesAllocatedSinceCollection > size)
bytesAllocatedSinceCollection -= size;
_freeLargeObj(obj); _freeLargeObj(obj);
return rtn; return rtn;
} }
...@@ -994,6 +999,9 @@ GCAllocation* HugeArena::realloc(GCAllocation* al, size_t bytes) { ...@@ -994,6 +999,9 @@ GCAllocation* HugeArena::realloc(GCAllocation* al, size_t bytes) {
GCAllocation* rtn = heap->alloc(bytes); GCAllocation* rtn = heap->alloc(bytes);
memcpy(rtn, al, std::min(bytes, obj->size)); memcpy(rtn, al, std::min(bytes, obj->size));
if (bytesAllocatedSinceCollection > obj->size)
bytesAllocatedSinceCollection -= obj->size;
_freeHugeObj(obj); _freeHugeObj(obj);
return rtn; return rtn;
} }
......
...@@ -1561,7 +1561,8 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -1561,7 +1561,8 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
STAT_TIMER(t0, "us_timer_slowpath_tpgetattro", 10); STAT_TIMER(t0, "us_timer_slowpath_tpgetattro", 10);
if (obj->cls->tp_getattro == slot_tp_getattr_hook) { if (obj->cls->tp_getattro == slot_tp_getattr_hook) {
return slotTpGetattrHookInternal<S, rewritable>(obj, attr, rewrite_args); return slotTpGetattrHookInternal<S, rewritable>(obj, attr, rewrite_args, for_call, bind_obj_out,
r_bind_obj_out);
} else if (obj->cls->tp_getattro == instance_getattro) { } else if (obj->cls->tp_getattro == instance_getattro) {
return instanceGetattroInternal<S>(obj, attr, rewrite_args); return instanceGetattroInternal<S>(obj, attr, rewrite_args);
} else if (obj->cls->tp_getattro == type_getattro) { } else if (obj->cls->tp_getattro == type_getattro) {
......
...@@ -42,6 +42,7 @@ extern "C" PyObject* string_find(PyStringObject* self, PyObject* args) noexcept; ...@@ -42,6 +42,7 @@ extern "C" PyObject* string_find(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_index(PyStringObject* self, PyObject* args) noexcept; extern "C" PyObject* string_index(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_rindex(PyStringObject* self, PyObject* args) noexcept; extern "C" PyObject* string_rindex(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_rfind(PyStringObject* self, PyObject* args) noexcept; extern "C" PyObject* string_rfind(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_replace(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_splitlines(PyStringObject* self, PyObject* args) noexcept; extern "C" PyObject* string_splitlines(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string__format__(PyObject* self, PyObject* args) noexcept; extern "C" PyObject* string__format__(PyObject* self, PyObject* args) noexcept;
...@@ -1839,53 +1840,6 @@ extern "C" PyObject* _PyString_Join(PyObject* sep, PyObject* x) noexcept { ...@@ -1839,53 +1840,6 @@ extern "C" PyObject* _PyString_Join(PyObject* sep, PyObject* x) noexcept {
return string_join((PyStringObject*)sep, x); return string_join((PyStringObject*)sep, x);
} }
Box* strReplace(Box* _self, Box* _old, Box* _new, Box** _args) {
if (!PyString_Check(_self))
raiseExcHelper(TypeError, "descriptor 'replace' requires a 'str' object but received a '%s'",
getTypeName(_self));
BoxedString* self = static_cast<BoxedString*>(_self);
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(_old) || PyUnicode_Check(_new))
return PyUnicode_Replace((PyObject*)self, _old, _new, -1 /*count*/);
#endif
if (!PyString_Check(_old))
raiseExcHelper(TypeError, "expected a character buffer object");
BoxedString* old = static_cast<BoxedString*>(_old);
if (!PyString_Check(_new))
raiseExcHelper(TypeError, "expected a character buffer object");
BoxedString* new_ = static_cast<BoxedString*>(_new);
Box* _maxreplace = _args[0];
if (!PyInt_Check(_maxreplace))
raiseExcHelper(TypeError, "an integer is required");
int max_replaces = static_cast<BoxedInt*>(_maxreplace)->n;
size_t start_pos = 0;
std::string s = self->s();
bool single_char = old->size() == 1;
int num_replaced = 0;
for (; num_replaced < max_replaces || max_replaces < 0; ++num_replaced) {
if (single_char)
start_pos = s.find(old->s()[0], start_pos);
else
start_pos = s.find(old->s(), start_pos);
if (start_pos == std::string::npos)
break;
s.replace(start_pos, old->size(), new_->s());
start_pos += new_->size(); // Handles case where 'to' is a substring of 'from'
}
if (num_replaced == 0 && self->cls == str_cls)
return self;
return boxString(s);
}
Box* strPartition(BoxedString* self, BoxedString* sep) { Box* strPartition(BoxedString* self, BoxedString* sep) {
RELEASE_ASSERT(PyString_Check(self), ""); RELEASE_ASSERT(PyString_Check(self), "");
RELEASE_ASSERT(PyString_Check(sep), ""); RELEASE_ASSERT(PyString_Check(sep), "");
...@@ -2826,6 +2780,7 @@ static PyMethodDef string_methods[] = { ...@@ -2826,6 +2780,7 @@ static PyMethodDef string_methods[] = {
{ "rindex", (PyCFunction)string_rindex, METH_VARARGS, NULL }, { "rindex", (PyCFunction)string_rindex, METH_VARARGS, NULL },
{ "rfind", (PyCFunction)string_rfind, METH_VARARGS, NULL }, { "rfind", (PyCFunction)string_rfind, METH_VARARGS, NULL },
{ "expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS, NULL }, { "expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS, NULL },
{ "replace", (PyCFunction)string_replace, METH_O3 | METH_D1, NULL },
{ "splitlines", (PyCFunction)string_splitlines, METH_VARARGS, NULL }, { "splitlines", (PyCFunction)string_splitlines, METH_VARARGS, NULL },
{ "zfill", (PyCFunction)string_zfill, METH_VARARGS, NULL }, { "zfill", (PyCFunction)string_zfill, METH_VARARGS, NULL },
{ "__format__", (PyCFunction)string__format__, METH_VARARGS, NULL }, { "__format__", (PyCFunction)string__format__, METH_VARARGS, NULL },
...@@ -2927,9 +2882,6 @@ void setupStr() { ...@@ -2927,9 +2882,6 @@ void setupStr() {
str_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)strIter, typeFromClass(str_iterator_cls), 1))); str_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)strIter, typeFromClass(str_iterator_cls), 1)));
str_cls->giveAttr("replace",
new BoxedFunction(boxRTFunction((void*)strReplace, UNKNOWN, 4, false, false), { boxInt(-1) }));
for (auto& md : string_methods) { for (auto& md : string_methods) {
str_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, str_cls)); str_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, str_cls));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment