diff -r 86ddd32068a1 Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py Tue Jan 03 11:20:15 2017 +0200 +++ b/Lib/test/test_bytes.py Wed Jan 04 12:26:58 2017 +0200 @@ -1497,6 +1497,28 @@ class AssortedBytesTest(unittest.TestCas self.assertRaises(SyntaxError, eval, 'b"%s"' % chr(c)) + def test_mtranslate(self): + rosetta = bytearray(range(0, 256)) + rosetta[ord('o')] = ord('e') + + ba = bytearray(b'hello') + ba.mtranslate(rosetta, b'l') + self.assertEqual(ba, b'hee') + + ba = bytearray(b'hello') + ba.mtranslate(None, b'e') + self.assertEqual(ba, b'hllo') + + ba = bytearray(b'ohio') + ba.mtranslate(rosetta) + self.assertEqual(ba, bytearray(b'ehie')) + + ba = bytearray(b'erie') + ba.mtranslate(rosetta, b'e') + self.assertEqual(ba, bytearray(b'ri')) + + self.assertRaises(TypeError, ba.mtranslate, None, None) + def test_split_bytearray(self): self.assertEqual(b'a b'.split(memoryview(b' ')), [b'a', b'b']) diff -r 86ddd32068a1 Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Tue Jan 03 11:20:15 2017 +0200 +++ b/Objects/bytearrayobject.c Wed Jan 04 12:26:58 2017 +0200 @@ -1502,6 +1502,100 @@ bytearray_reverse_impl(PyByteArrayObject Py_RETURN_NONE; } +PyDoc_STRVAR(mtranslate__doc__, +"B.mtranslate(table[, deletechars]) -> bytearray\n\ +\n\ +Mutable translate performs the same action as translate,\n\ +in place on the string"); + +static PyObject * +bytearray_mtranslate(PyByteArrayObject *self, PyObject *args) +{ + register char *input, *target; + register const char *table; + register Py_ssize_t i, c; + PyObject *tableobj = NULL, *delobj = NULL; + Py_buffer vtable, vdel; + PyObject *input_obj = (PyObject*)self; + int inlen, outlen; + int trans_table[256]; + + if(!PyArg_UnpackTuple(args, "translate", 1, 2, + &tableobj, &delobj)){ + return NULL; + } + + if (tableobj == Py_None) { + table = NULL; + tableobj = NULL; + } else if (PyObject_GetBuffer(tableobj, &vtable, PyBUF_SIMPLE) != 0) { + return NULL; + } else { + if(vtable.len != 256){ + PyErr_SetString(PyExc_ValueError, + "translation table must be 256 characters long"); + PyBuffer_Release(&vtable); + return NULL; + } + table = (const char*)vtable.buf; + } + + if (delobj != NULL) { + if (PyObject_GetBuffer(delobj, &vdel, PyBUF_SIMPLE) != 0) { + if (tableobj != NULL) + PyBuffer_Release(&vtable); + return NULL; + } + } + else { + vdel.buf = NULL; + vdel.len = 0; + } + + inlen = PyByteArray_GET_SIZE(input_obj); + input = PyByteArray_AS_STRING(input_obj); + + if(vdel.len == 0 && table != NULL){ + for (i = inlen; --i >= 0; ) { + c = Py_CHARMASK(*input); + *input = table[c]; + ++input; + } + goto done; + } + + if (table == NULL) { + for (i = 0; i < 256; i++) + trans_table[i] = Py_CHARMASK(i); + } else { + for (i = 0; i < 256; i++) + trans_table[i] = Py_CHARMASK(table[i]); + } + + for (i = 0; i < vdel.len; i++) + trans_table[(int) Py_CHARMASK( ((unsigned char*)vdel.buf)[i] )] = -1; + + outlen = 0; + target = input; + for (i = inlen; --i >= 0; ) { + c = Py_CHARMASK(*input); + if (trans_table[c] != -1){ + ++outlen; + *target++ = (char)trans_table[c]; + } + ++input; + } + + if(outlen != inlen) + PyByteArray_Resize(input_obj, outlen); + +done: + if (tableobj != NULL) + PyBuffer_Release(&vtable); + if (delobj != NULL) + PyBuffer_Release(&vdel); + Py_RETURN_NONE; +} /*[python input] class bytesvalue_converter(CConverter): @@ -2176,6 +2270,8 @@ bytearray_methods[] = { BYTEARRAY_TRANSLATE_METHODDEF {"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__}, {"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, _Py_zfill__doc__}, + {"mtranslate", (PyCFunction)bytearray_mtranslate, METH_VARARGS, + mtranslate__doc__}, {NULL} };