Commit 646af4e4 authored by Stefan Behnel's avatar Stefan Behnel

support slicing with negative indices for C strings and C++ strings during decoding

parent 0cbc0f43
...@@ -506,16 +506,19 @@ static CYTHON_INLINE PyObject* __Pyx_decode_cpp_string( ...@@ -506,16 +506,19 @@ static CYTHON_INLINE PyObject* __Pyx_decode_cpp_string(
const char* cstring = cppstring.data(); const char* cstring = cppstring.data();
Py_ssize_t length = cppstring.size(); Py_ssize_t length = cppstring.size();
if (start < 0) if (unlikely(start < 0)) {
start += length; start += length;
if (stop < 0) if (unlikely(start < 0))
length += stop; start = 0;
else if (length > stop) }
length = stop; if (unlikely(stop < 0))
if ((start < 0) | (start >= length)) stop += length;
else if (stop >= length)
stop = length;
if (unlikely(start >= stop))
return PyUnicode_FromUnicode(NULL, 0); return PyUnicode_FromUnicode(NULL, 0);
cstring += start; cstring += start;
length -= start; length = stop - start;
if (decode_func) { if (decode_func) {
return decode_func(cstring, length, errors); return decode_func(cstring, length, errors);
...@@ -532,12 +535,26 @@ static CYTHON_INLINE PyObject* __Pyx_decode_c_string( ...@@ -532,12 +535,26 @@ static CYTHON_INLINE PyObject* __Pyx_decode_c_string(
PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)); PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors));
/////////////// decode_c_string /////////////// /////////////// decode_c_string ///////////////
//@requires StringTools.c::IncludeStringH
static CYTHON_INLINE PyObject* __Pyx_decode_c_string( static CYTHON_INLINE PyObject* __Pyx_decode_c_string(
const char* cstring, Py_ssize_t start, Py_ssize_t stop, const char* cstring, Py_ssize_t start, Py_ssize_t stop,
const char* encoding, const char* errors, const char* encoding, const char* errors,
PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) {
Py_ssize_t length = stop - start; Py_ssize_t length;
if (unlikely((start < 0) | (stop < 0))) {
length = strlen(cstring);
if (start < 0) {
start += length;
if (start < 0)
start = 0;
}
if (stop < 0)
stop += length;
}
length = stop - start;
if (unlikely(length <= 0))
return PyUnicode_FromUnicode(NULL, 0);
cstring += start; cstring += start;
if (decode_func) { if (decode_func) {
return decode_func(cstring, length, errors); return decode_func(cstring, length, errors);
......
...@@ -60,11 +60,14 @@ def slice_charptr_decode_slice2(): ...@@ -60,11 +60,14 @@ def slice_charptr_decode_slice2():
def slice_charptr_decode_strlen(): def slice_charptr_decode_strlen():
""" """
>>> print(str(slice_charptr_decode_strlen()).replace("u'", "'")) >>> print(str(slice_charptr_decode_strlen()).replace("u'", "'"))
('abcABCqtp', 'bcABCqtp', '') ('abcABCqtp', 'bcABCqtp', '', 'BCq', 'abcA', '')
""" """
return (cstring.decode('UTF-8'), return (cstring.decode('UTF-8'),
cstring[1:].decode('UTF-8'), cstring[1:].decode('UTF-8'),
cstring[9:].decode('UTF-8')) cstring[9:].decode('UTF-8'),
cstring[-5:-2].decode('UTF-8'),
cstring[:-5].decode('UTF-8'),
cstring[:-9].decode('UTF-8'))
@cython.test_assert_path_exists("//PythonCapiCallNode") @cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode") @cython.test_fail_if_path_exists("//AttributeNode")
......
...@@ -165,15 +165,50 @@ def test_decode_sliced(char* a): ...@@ -165,15 +165,50 @@ def test_decode_sliced(char* a):
cdef string b = string(a) cdef string b = string(a)
return b[1:3].decode('ascii') return b[1:3].decode('ascii')
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def test_decode_sliced_negative(char* a):
"""
>>> a,b,c,d = test_decode_sliced_negative(b_asdf)
>>> print(a)
sd
>>> print(b)
a
>>> print(c)
<BLANKLINE>
>>> print(d)
<BLANKLINE>
"""
cdef string b = string(a)
return b[-3:-1].decode('ascii'), b[-5:-3].decode('ascii'), b[-20:-4].decode('ascii'), b[-2:-20].decode('ascii')
@cython.test_assert_path_exists("//PythonCapiCallNode") @cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode") @cython.test_fail_if_path_exists("//AttributeNode")
def test_decode_sliced_end(char* a): def test_decode_sliced_end(char* a):
""" """
>>> print(test_decode_sliced_end(b_asdf)) >>> a,b = test_decode_sliced_end(b_asdf)
>>> print(a)
asd asd
>>> print(b)
asdf
""" """
cdef string b = string(a) cdef string b = string(a)
return b[:3].decode('ascii') return b[:3].decode('ascii'), b[:42].decode('ascii')
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def test_decode_sliced_end_negative(char* a):
"""
>>> a,b,c = test_decode_sliced_end_negative(b_asdf)
>>> print(a)
asd
>>> print(b)
a
>>> print(c)
<BLANKLINE>
"""
cdef string b = string(a)
return b[:-1].decode('ascii'), b[:-3].decode('ascii'), b[:-4].decode('ascii')
@cython.test_assert_path_exists("//PythonCapiCallNode") @cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode") @cython.test_fail_if_path_exists("//AttributeNode")
...@@ -185,6 +220,19 @@ def test_decode_sliced_start(char* a): ...@@ -185,6 +220,19 @@ def test_decode_sliced_start(char* a):
cdef string b = string(a) cdef string b = string(a)
return b[2:].decode('ascii') return b[2:].decode('ascii')
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def test_decode_sliced_start_negative(char* a):
"""
>>> a,b = test_decode_sliced_start_negative(b_asdf)
>>> print(a)
df
>>> print(b)
asdf
"""
cdef string b = string(a)
return b[-2:].decode('ascii'), b[-20:].decode('ascii')
def test_equals_operator(char *a, char *b): def test_equals_operator(char *a, char *b):
""" """
>>> test_equals_operator(b_asdf, b_asdf) >>> test_equals_operator(b_asdf, b_asdf)
......
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