Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 376446d

Browse files
committed
Implement extended slicing in bytes objects.
1 parent 5672904 commit 376446d

2 files changed

Lines changed: 248 additions & 16 deletions

File tree

Lib/test/test_bytes.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,17 @@ def by(s):
163163
self.assertEqual(b[-5:100], by("world"))
164164
self.assertEqual(b[-100:5], by("Hello"))
165165

166+
def test_extended_getslice(self):
167+
# Test extended slicing by comparing with list slicing.
168+
L = list(range(255))
169+
b = bytes(L)
170+
indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100)
171+
for start in indices:
172+
for stop in indices:
173+
# Skip step 0 (invalid)
174+
for step in indices[1:]:
175+
self.assertEqual(b[start:stop:step], bytes(L[start:stop:step]))
176+
166177
def test_regexps(self):
167178
def by(s):
168179
return bytes(map(ord, s))
@@ -239,6 +250,26 @@ def test_setslice(self):
239250
b[3:0] = [42, 42, 42]
240251
self.assertEqual(b, bytes([0, 1, 2, 42, 42, 42, 3, 4, 5, 6, 7, 8, 9]))
241252

253+
def test_extended_set_del_slice(self):
254+
indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
255+
for start in indices:
256+
for stop in indices:
257+
# Skip invalid step 0
258+
for step in indices[1:]:
259+
L = list(range(255))
260+
b = bytes(L)
261+
# Make sure we have a slice of exactly the right length,
262+
# but with different data.
263+
data = L[start:stop:step]
264+
data.reverse()
265+
L[start:stop:step] = data
266+
b[start:stop:step] = data
267+
self.assertEquals(b, bytes(L))
268+
269+
del L[start:stop:step]
270+
del b[start:stop:step]
271+
self.assertEquals(b, bytes(L))
272+
242273
def test_setslice_trap(self):
243274
# This test verifies that we correctly handle assigning self
244275
# to a slice of self (the old Lambert Meertens trap).

Objects/bytesobject.c

Lines changed: 217 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,62 @@ bytes_getitem(PyBytesObject *self, Py_ssize_t i)
269269
}
270270

271271
static PyObject *
272-
bytes_getslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi)
272+
bytes_subscript(PyBytesObject *self, PyObject *item)
273273
{
274-
if (lo < 0)
275-
lo = 0;
276-
if (hi > self->ob_size)
277-
hi = self->ob_size;
278-
if (lo >= hi)
279-
lo = hi = 0;
280-
return PyBytes_FromStringAndSize(self->ob_bytes + lo, hi - lo);
281-
}
274+
if (PyIndex_Check(item)) {
275+
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
282276

277+
if (i == -1 && PyErr_Occurred())
278+
return NULL;
279+
280+
if (i < 0)
281+
i += PyBytes_GET_SIZE(self);
282+
283+
if (i < 0 || i >= self->ob_size) {
284+
PyErr_SetString(PyExc_IndexError, "bytes index out of range");
285+
return NULL;
286+
}
287+
return PyInt_FromLong((unsigned char)(self->ob_bytes[i]));
288+
}
289+
else if (PySlice_Check(item)) {
290+
Py_ssize_t start, stop, step, slicelength, cur, i;
291+
if (PySlice_GetIndicesEx((PySliceObject *)item,
292+
PyBytes_GET_SIZE(self),
293+
&start, &stop, &step, &slicelength) < 0) {
294+
return NULL;
295+
}
296+
297+
if (slicelength <= 0)
298+
return PyBytes_FromStringAndSize("", 0);
299+
else if (step == 1) {
300+
return PyBytes_FromStringAndSize(self->ob_bytes + start,
301+
slicelength);
302+
}
303+
else {
304+
char *source_buf = PyBytes_AS_STRING(self);
305+
char *result_buf = (char *)PyMem_Malloc(slicelength);
306+
PyObject *result;
307+
308+
if (result_buf == NULL)
309+
return PyErr_NoMemory();
310+
311+
for (cur = start, i = 0; i < slicelength;
312+
cur += step, i++) {
313+
result_buf[i] = source_buf[cur];
314+
}
315+
result = PyBytes_FromStringAndSize(result_buf, slicelength);
316+
PyMem_Free(result_buf);
317+
return result;
318+
}
319+
}
320+
else {
321+
PyErr_SetString(PyExc_TypeError, "bytes indices must be integers");
322+
return NULL;
323+
}
324+
}
325+
283326
static int
284-
bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi,
327+
bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi,
285328
PyObject *values)
286329
{
287330
int avail;
@@ -330,7 +373,7 @@ bytes_setslice(PyBytesObject *self, Py_ssize_t lo, Py_ssize_t hi,
330373
memmove(self->ob_bytes + lo + needed, self->ob_bytes + hi,
331374
self->ob_size - hi);
332375
}
333-
if (PyBytes_Resize((PyObject *)self,
376+
if (PyBytes_Resize((PyObject *)self,
334377
self->ob_size + needed - avail) < 0)
335378
return -1;
336379
if (avail < needed) {
@@ -380,6 +423,164 @@ bytes_setitem(PyBytesObject *self, Py_ssize_t i, PyObject *value)
380423
return 0;
381424
}
382425

426+
static int
427+
bytes_ass_subscript(PyBytesObject *self, PyObject *item, PyObject *values)
428+
{
429+
Py_ssize_t start, stop, step, slicelen, needed;
430+
char *bytes;
431+
432+
if (PyIndex_Check(item)) {
433+
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
434+
435+
if (i == -1 && PyErr_Occurred())
436+
return -1;
437+
438+
if (i < 0)
439+
i += PyBytes_GET_SIZE(self);
440+
441+
if (i < 0 || i >= self->ob_size) {
442+
PyErr_SetString(PyExc_IndexError, "bytes index out of range");
443+
return -1;
444+
}
445+
446+
if (values == NULL) {
447+
/* Fall through to slice assignment */
448+
start = i;
449+
stop = i + 1;
450+
step = 1;
451+
slicelen = 1;
452+
}
453+
else {
454+
Py_ssize_t ival = PyNumber_AsSsize_t(values, PyExc_ValueError);
455+
if (ival == -1 && PyErr_Occurred())
456+
return -1;
457+
if (ival < 0 || ival >= 256) {
458+
PyErr_SetString(PyExc_ValueError,
459+
"byte must be in range(0, 256)");
460+
return -1;
461+
}
462+
self->ob_bytes[i] = (char)ival;
463+
return 0;
464+
}
465+
}
466+
else if (PySlice_Check(item)) {
467+
if (PySlice_GetIndicesEx((PySliceObject *)item,
468+
PyBytes_GET_SIZE(self),
469+
&start, &stop, &step, &slicelen) < 0) {
470+
return -1;
471+
}
472+
}
473+
else {
474+
PyErr_SetString(PyExc_TypeError, "bytes indices must be integer");
475+
return -1;
476+
}
477+
478+
if (values == NULL) {
479+
bytes = NULL;
480+
needed = 0;
481+
}
482+
else if (values == (PyObject *)self || !PyBytes_Check(values)) {
483+
/* Make a copy an call this function recursively */
484+
int err;
485+
values = PyBytes_FromObject(values);
486+
if (values == NULL)
487+
return -1;
488+
err = bytes_ass_subscript(self, item, values);
489+
Py_DECREF(values);
490+
return err;
491+
}
492+
else {
493+
assert(PyBytes_Check(values));
494+
bytes = ((PyBytesObject *)values)->ob_bytes;
495+
needed = ((PyBytesObject *)values)->ob_size;
496+
}
497+
/* Make sure b[5:2] = ... inserts before 5, not before 2. */
498+
if ((step < 0 && start < stop) ||
499+
(step > 0 && start > stop))
500+
stop = start;
501+
if (step == 1) {
502+
if (slicelen != needed) {
503+
if (slicelen > needed) {
504+
/*
505+
0 start stop old_size
506+
| |<---slicelen--->|<-----tomove------>|
507+
| |<-needed->|<-----tomove------>|
508+
0 lo new_hi new_size
509+
*/
510+
memmove(self->ob_bytes + start + needed, self->ob_bytes + stop,
511+
self->ob_size - stop);
512+
}
513+
if (PyBytes_Resize((PyObject *)self,
514+
self->ob_size + needed - slicelen) < 0)
515+
return -1;
516+
if (slicelen < needed) {
517+
/*
518+
0 lo hi old_size
519+
| |<-avail->|<-----tomove------>|
520+
| |<----needed---->|<-----tomove------>|
521+
0 lo new_hi new_size
522+
*/
523+
memmove(self->ob_bytes + start + needed, self->ob_bytes + stop,
524+
self->ob_size - start - needed);
525+
}
526+
}
527+
528+
if (needed > 0)
529+
memcpy(self->ob_bytes + start, bytes, needed);
530+
531+
return 0;
532+
}
533+
else {
534+
if (needed == 0) {
535+
/* Delete slice */
536+
Py_ssize_t cur, i;
537+
538+
if (step < 0) {
539+
stop = start + 1;
540+
start = stop + step * (slicelen - 1) - 1;
541+
step = -step;
542+
}
543+
for (cur = start, i = 0;
544+
i < slicelen; cur += step, i++) {
545+
Py_ssize_t lim = step - 1;
546+
547+
if (cur + step >= PyBytes_GET_SIZE(self))
548+
lim = PyBytes_GET_SIZE(self) - cur - 1;
549+
550+
memmove(self->ob_bytes + cur - i,
551+
self->ob_bytes + cur + 1, lim);
552+
}
553+
/* Move the tail of the bytes, in one chunk */
554+
cur = start + slicelen*step;
555+
if (cur < PyBytes_GET_SIZE(self)) {
556+
memmove(self->ob_bytes + cur - slicelen,
557+
self->ob_bytes + cur,
558+
PyBytes_GET_SIZE(self) - cur);
559+
}
560+
if (PyBytes_Resize((PyObject *)self,
561+
PyBytes_GET_SIZE(self) - slicelen) < 0)
562+
return -1;
563+
564+
return 0;
565+
}
566+
else {
567+
/* Assign slice */
568+
Py_ssize_t cur, i;
569+
570+
if (needed != slicelen) {
571+
PyErr_Format(PyExc_ValueError,
572+
"attempt to assign bytes of size %zd "
573+
"to extended slice of size %zd",
574+
needed, slicelen);
575+
return -1;
576+
}
577+
for (cur = start, i = 0; i < slicelen; cur += step, i++)
578+
self->ob_bytes[cur] = bytes[i];
579+
return 0;
580+
}
581+
}
582+
}
583+
383584
static int
384585
bytes_init(PyBytesObject *self, PyObject *args, PyObject *kwds)
385586
{
@@ -776,18 +977,18 @@ static PySequenceMethods bytes_as_sequence = {
776977
(binaryfunc)bytes_concat, /*sq_concat*/
777978
(ssizeargfunc)bytes_repeat, /*sq_repeat*/
778979
(ssizeargfunc)bytes_getitem, /*sq_item*/
779-
(ssizessizeargfunc)bytes_getslice, /*sq_slice*/
980+
0, /*sq_slice*/
780981
(ssizeobjargproc)bytes_setitem, /*sq_ass_item*/
781-
(ssizessizeobjargproc)bytes_setslice, /* sq_ass_slice */
982+
0, /* sq_ass_slice */
782983
(objobjproc)bytes_contains, /* sq_contains */
783984
(binaryfunc)bytes_iconcat, /* sq_inplace_concat */
784985
(ssizeargfunc)bytes_irepeat, /* sq_inplace_repeat */
785986
};
786987

787988
static PyMappingMethods bytes_as_mapping = {
788989
(lenfunc)bytes_length,
789-
(binaryfunc)0,
790-
0,
990+
(binaryfunc)bytes_subscript,
991+
(objobjargproc)bytes_ass_subscript,
791992
};
792993

793994
static PyBufferProcs bytes_as_buffer = {
@@ -833,7 +1034,7 @@ PyTypeObject PyBytes_Type = {
8331034
PyObject_GenericGetAttr, /* tp_getattro */
8341035
0, /* tp_setattro */
8351036
&bytes_as_buffer, /* tp_as_buffer */
836-
Py_TPFLAGS_DEFAULT, /* tp_flags */
1037+
Py_TPFLAGS_DEFAULT, /* tp_flags */
8371038
/* bytes is 'final' or 'sealed' */
8381039
bytes_doc, /* tp_doc */
8391040
0, /* tp_traverse */

0 commit comments

Comments
 (0)