diff -r 94710cbcac47 Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst Thu Sep 01 13:55:33 2016 -0400 +++ b/Doc/library/stdtypes.rst Thu Sep 01 12:23:14 2016 -0700 @@ -2298,8 +2298,11 @@ In addition to the literal forms, bytes other ways: * A zero-filled bytes object of a specified length: ``bytes(10)`` + (deprecated in version 3.6) * From an iterable of integers: ``bytes(range(20))`` * Copying existing binary data via the buffer protocol: ``bytes(obj)`` +* Using the :meth:`~bytes.zeros` constructor: ``bytes.zeros(10)`` +* Using the :meth:`~bytes.byte` single-byte constructor: ``bytes.byte(65)`` Also see the :ref:`bytes ` built-in. @@ -2362,8 +2365,11 @@ they are always created by calling the c * Creating an empty instance: ``bytearray()`` * Creating a zero-filled instance with a given length: ``bytearray(10)`` + (deprecated in version 3.6) * From an iterable of integers: ``bytearray(range(20))`` * Copying existing binary data via the buffer protocol: ``bytearray(b'Hi!')`` +* Using the :meth:`~bytearray.zeros` constructor: ``bytearray.zeros(10)`` +* Using the :meth:`~bytearray.byte` single-byte constructor: ``bytearray.byte(65)`` As bytearray objects are mutable, they support the :ref:`mutable ` sequence operations in addition to the @@ -2530,6 +2536,14 @@ arbitrary binary data. Also accept an integer in the range 0 to 255 as the subsequence. +.. classmethod:: bytes.iterbytes() + bytearray.iterbytes() + + Return an iterator that produce :class:`bytes` objects of length 1. + + .. versionadded:: 3.6 + + .. method:: bytes.join(iterable) bytearray.join(iterable) @@ -3667,6 +3681,12 @@ copying. .. versionchanged:: 3.5 The source format is no longer restricted when casting to a byte view. + .. classmethod:: memoryview.iterbytes() + + Return an iterator that produce :class:`bytes` objects of length 1. + + .. versionadded:: 3.6 + There are also several readonly attributes available: .. attribute:: obj diff -r 94710cbcac47 Include/bytes_methods.h --- a/Include/bytes_methods.h Thu Sep 01 13:55:33 2016 -0400 +++ b/Include/bytes_methods.h Thu Sep 01 12:23:14 2016 -0700 @@ -41,6 +41,7 @@ extern const char _Py_isdigit__doc__[]; extern const char _Py_islower__doc__[]; extern const char _Py_isupper__doc__[]; extern const char _Py_istitle__doc__[]; +extern const char _Py_iterbytes__doc__[]; extern const char _Py_lower__doc__[]; extern const char _Py_upper__doc__[]; extern const char _Py_title__doc__[]; diff -r 94710cbcac47 Lib/sre_compile.py --- a/Lib/sre_compile.py Thu Sep 01 13:55:33 2016 -0400 +++ b/Lib/sre_compile.py Thu Sep 01 12:23:14 2016 -0700 @@ -249,7 +249,7 @@ def _optimize_charset(charset, fixup, fi # internal: optimize character set out = [] tail = [] - charmap = bytearray(256) + charmap = bytearray.zeros(256) for op, av in charset: while True: try: @@ -351,7 +351,7 @@ def _optimize_charset(charset, fixup, fi charmap = bytes(charmap) # should be hashable comps = {} - mapping = bytearray(256) + mapping = bytearray.zeros(256) block = 0 data = bytearray() for i in range(0, 65536, 256): diff -r 94710cbcac47 Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py Thu Sep 01 13:55:33 2016 -0400 +++ b/Lib/test/test_bytes.py Thu Sep 01 12:23:14 2016 -0700 @@ -82,15 +82,38 @@ class BaseBytesTest: self.assertRaises(ValueError, self.type2test, [Indexable(256)]) def test_from_ssize(self): - self.assertEqual(self.type2test(0), b'') - self.assertEqual(self.type2test(1), b'\x00') - self.assertEqual(self.type2test(5), b'\x00\x00\x00\x00\x00') + with self.assertWarns(DeprecationWarning): + self.assertEqual(self.type2test(0), b'') + with self.assertWarns(DeprecationWarning): + self.assertEqual(self.type2test(1), b'\x00') + with self.assertWarns(DeprecationWarning): + self.assertEqual(self.type2test(5), b'\x00\x00\x00\x00\x00') + with self.assertWarns(DeprecationWarning): + self.assertEqual(self.type2test(10), self.type2test([0]*10)) + with self.assertWarns(DeprecationWarning): + self.assertEqual(self.type2test(10000), self.type2test([0]*10000)) + self.assertRaises(ValueError, self.type2test, -1) self.assertEqual(self.type2test('0', 'ascii'), b'0') self.assertEqual(self.type2test(b'0'), b'0') self.assertRaises(OverflowError, self.type2test, sys.maxsize + 1) + def test_zeros(self): + self.assertEqual(self.type2test.zeros(0), b'') + self.assertEqual(self.type2test.zeros(1), b'\x00') + self.assertEqual(self.type2test.zeros(5), b'\x00\x00\x00\x00\x00') + self.assertRaises(ValueError, self.type2test.zeros, -1) + + def test_single_byte(self): + self.assertEqual(self.type2test.byte(0), b'\x00') + self.assertEqual(self.type2test.byte(65), b'A') + self.assertEqual(self.type2test.byte(255), b'\xff') + self.assertEqual(self.type2test.byte(False), b'\x00') + self.assertEqual(self.type2test.byte(True), b'\x01') + self.assertRaises(ValueError, self.type2test.byte, 256) + self.assertRaises(ValueError, self.type2test.byte, -1) + def test_constructor_type_errors(self): self.assertRaises(TypeError, self.type2test, 0.0) class C: @@ -229,14 +252,6 @@ class BaseBytesTest: # Default encoding is utf-8 self.assertEqual(self.type2test(b'\xe2\x98\x83').decode(), '\u2603') - def test_from_int(self): - b = self.type2test(0) - self.assertEqual(b, self.type2test()) - b = self.type2test(10) - self.assertEqual(b, self.type2test([0]*10)) - b = self.type2test(10000) - self.assertEqual(b, self.type2test([0]*10000)) - def test_concat(self): b1 = self.type2test(b"abc") b2 = self.type2test(b"def") @@ -483,6 +498,14 @@ class BaseBytesTest: self.assertEqual(b.rindex(i, 3, 9), 7) self.assertRaises(ValueError, b.rindex, w, 1, 3) + def test_iterbytes(self): + b = self.type2test(b'foo') + it = b.iterbytes() + self.assertEqual(next(it), b'f') + self.assertEqual(next(it), b'o') + self.assertEqual(next(it), b'o') + self.assertRaises(StopIteration, next, it) + def test_mod(self): b = self.type2test(b'hello, %b!') orig = b diff -r 94710cbcac47 Lib/test/test_doctest.py --- a/Lib/test/test_doctest.py Thu Sep 01 13:55:33 2016 -0400 +++ b/Lib/test/test_doctest.py Thu Sep 01 12:23:14 2016 -0700 @@ -659,7 +659,7 @@ plain ol' Python and is guaranteed to be >>> import builtins >>> tests = doctest.DocTestFinder().find(builtins) - >>> 790 < len(tests) < 810 # approximate number of objects with docstrings + >>> 800 < len(tests) < 850 # approximate number of objects with docstrings True >>> real_tests = [t for t in tests if len(t.examples) > 0] >>> len(real_tests) # objects that actually have doctests diff -r 94710cbcac47 Lib/test/test_memoryview.py --- a/Lib/test/test_memoryview.py Thu Sep 01 13:55:33 2016 -0400 +++ b/Lib/test/test_memoryview.py Thu Sep 01 12:23:14 2016 -0700 @@ -383,6 +383,15 @@ class AbstractMemoryTests: self.assertEqual(c.format, "H") self.assertEqual(d.format, "H") + def test_iterbytes(self): + for tp in self._types: + b = tp(self._source) + m = self._view(b) + it = m.iterbytes() + for byte in m: + self.assertEqual(next(it), bytes([byte])) + self.assertRaises(StopIteration, next, it) + # Variations on source objects for the buffer: bytes-like objects, then arrays # with itemsize > 1. diff -r 94710cbcac47 Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Thu Sep 01 13:55:33 2016 -0400 +++ b/Objects/bytearrayobject.c Thu Sep 01 12:23:14 2016 -0700 @@ -804,6 +804,13 @@ bytearray_init(PyByteArrayObject *self, PyErr_SetString(PyExc_ValueError, "negative count"); return -1; } + if (count >= 0) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "Passing an integer to the bytearray " + "constructor is deprecated. Use " + "bytearray.zeros(%zd) instead.\n", count) < 0) + return NULL; + } if (count > 0) { if (PyByteArray_Resize((PyObject *)self, count)) return -1; @@ -1991,6 +1998,67 @@ bytearray_fromhex_impl(PyTypeObject *typ return result; } +/*[clinic input] +@classmethod +bytearray.zeros + + size: int + / + +Create a bytearray object of size given by the parameter initialized with null bytes. + +Parameter must be 0 or a positive integer. +Example: bytearray.zeros(3) -> bytearray(b\'\\x00\\x00\\x00') +[clinic start generated code]*/ + +static PyObject * +bytearray_zeros_impl(PyTypeObject *type, int size) +/*[clinic end generated code: output=483e961ce69e50dc input=b6e4556bd3095de2]*/ +{ + if (size == -1 && PyErr_Occurred()) { + return NULL; + } + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative count"); + return NULL; + } + if (size >= 0) { + PyObject *result = PyByteArray_FromStringAndSize(NULL, size); + if (PyByteArray_Resize((PyObject *)result, size)) + return NULL; + memset(PyByteArray_AS_STRING(result), 0, size); + return result; + } +} + +/*[clinic input] +@classmethod +bytearray.byte + + x: int + / + +Create a bytearray object, consisting of a single byte. + +Parameter must be in range(0, 256) +bytearray.byte(x) is equivalent to bytearray([x]) +Example: bytearray.byte(3) -> bytearray(b'\x03') +[clinic start generated code]*/ + +static PyObject * +bytearray_byte_impl(PyTypeObject *type, int x) +/*[clinic end generated code: output=756fefaafb00a523 input=d36148c99214b551]*/ +{ + char byte; + if (x < 0 || x > 255) { + PyErr_Format(PyExc_ValueError, "bytes must be in range(0, 256)"); + return NULL; + } + byte = (char)x; + return PyByteArray_FromStringAndSize(&byte, 1); +} + + PyDoc_STRVAR(hex__doc__, "B.hex() -> string\n\ \n\ @@ -2109,6 +2177,8 @@ static PyBufferProcs bytearray_as_buffer (releasebufferproc)bytearray_releasebuffer, }; +static PyObject *bytearray_iterbytes(PyObject *seq); + static PyMethodDef bytearray_methods[] = { {"__alloc__", (PyCFunction)bytearray_alloc, METH_NOARGS, alloc_doc}, @@ -2116,6 +2186,7 @@ bytearray_methods[] = { BYTEARRAY_REDUCE_EX_METHODDEF BYTEARRAY_SIZEOF_METHODDEF BYTEARRAY_APPEND_METHODDEF + BYTEARRAY_BYTE_METHODDEF {"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS, _Py_capitalize__doc__}, {"center", (PyCFunction)stringlib_center, METH_VARARGS, _Py_center__doc__}, @@ -2149,6 +2220,8 @@ bytearray_methods[] = { _Py_istitle__doc__}, {"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS, _Py_isupper__doc__}, + {"iterbytes", (PyCFunction)bytearray_iterbytes, METH_NOARGS, + _Py_iterbytes__doc__}, BYTEARRAY_JOIN_METHODDEF {"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, _Py_ljust__doc__}, {"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__}, @@ -2175,6 +2248,7 @@ bytearray_methods[] = { {"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__}, BYTEARRAY_TRANSLATE_METHODDEF {"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__}, + BYTEARRAY_ZEROS_METHODDEF {"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, _Py_zfill__doc__}, {NULL} }; @@ -2410,3 +2484,67 @@ bytearray_iter(PyObject *seq) _PyObject_GC_TRACK(it); return (PyObject *)it; } + +/****************** bytearray_iterbytes object ***********************/ + +static PyObject * +bytearray_iterbytes_next(bytesiterobject *it) +{ + PyObject *item = bytearrayiter_next(it); + if (item != NULL) { + return Py_BuildValue("c", (unsigned char)PyLong_AsLong(item)); + } + return item; +} + +PyTypeObject PyByteArrayIterBytes_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "bytearray_iterator", /* tp_name */ + sizeof(bytesiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)bytearrayiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)bytearrayiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)bytearray_iterbytes_next, /* tp_iternext */ + bytearrayiter_methods, /* tp_methods */ + 0, +}; + +static PyObject * +bytearray_iterbytes(PyObject *seq) +{ + bytesiterobject *it; + + if (!PyByteArray_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(bytesiterobject, &PyByteArrayIterBytes_Type); + if (it == NULL) + return NULL; + it->it_index = 0; + Py_INCREF(seq); + it->it_seq = (PyByteArrayObject *)seq; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} diff -r 94710cbcac47 Objects/bytes_methods.c --- a/Objects/bytes_methods.c Thu Sep 01 13:55:33 2016 -0400 +++ b/Objects/bytes_methods.c Thu Sep 01 12:23:14 2016 -0700 @@ -239,6 +239,10 @@ PyObject* } +PyDoc_STRVAR_shared(_Py_iterbytes__doc__, +"B.iterbytes() -> iterator that produces length 1 bytes objects instead of integers"); + + PyDoc_STRVAR_shared(_Py_lower__doc__, "B.lower() -> copy of B\n\ \n\ diff -r 94710cbcac47 Objects/bytesobject.c --- a/Objects/bytesobject.c Thu Sep 01 13:55:33 2016 -0400 +++ b/Objects/bytesobject.c Thu Sep 01 12:23:14 2016 -0700 @@ -2384,6 +2384,58 @@ PyObject* return NULL; } +/*[clinic input] +@classmethod +bytes.zeros + + size: int + / + +Create a bytes object of size given by the parameter initialized with null bytes. + +Parameter must be 0 or a positive integer. +Example: bytes.zeros(3) -> b\'\\x00\\x00\\x00' +[clinic start generated code]*/ + +static PyObject * +bytes_zeros_impl(PyTypeObject *type, int size) +/*[clinic end generated code: output=ae545bb17865f2a1 input=12e0adfbb086d92d]*/ +{ + if (size == -1 && PyErr_Occurred()) { + return NULL; + } + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative count"); + return NULL; + } + return _PyBytes_FromSize(size, 1); +} + +/*[clinic input] +@classmethod +bytes.byte + + x: int + / + +Create a bytes object, consisting of a single byte. + +Parameter must be in range(0, 256) +bytes.byte(x) is equivalent to bytes([x]) +Example: bytes.byte(3) -> b'\x03' +[clinic start generated code]*/ + +static PyObject * +bytes_byte_impl(PyTypeObject *type, int x) +/*[clinic end generated code: output=9045f894ce311daa input=eb583448446d0edd]*/ +{ + if (x < 0 || x > 255) { + PyErr_Format(PyExc_ValueError, "bytes must be in range(0, 256)"); + return NULL; + } + return Py_BuildValue("c", x); +} + PyDoc_STRVAR(hex__doc__, "B.hex() -> string\n\ \n\ @@ -2404,10 +2456,13 @@ bytes_getnewargs(PyBytesObject *v) return Py_BuildValue("(y#)", v->ob_sval, Py_SIZE(v)); } +static PyObject *bytes_iterbytes(PyObject *seq); + static PyMethodDef bytes_methods[] = { {"__getnewargs__", (PyCFunction)bytes_getnewargs, METH_NOARGS}, + BYTES_BYTE_METHODDEF {"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS, _Py_capitalize__doc__}, {"center", (PyCFunction)stringlib_center, METH_VARARGS, @@ -2438,6 +2493,8 @@ bytes_methods[] = { _Py_istitle__doc__}, {"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS, _Py_isupper__doc__}, + {"iterbytes", (PyCFunction)bytes_iterbytes, METH_NOARGS, + _Py_iterbytes__doc__}, BYTES_JOIN_METHODDEF {"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, _Py_ljust__doc__}, {"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__}, @@ -2461,6 +2518,7 @@ bytes_methods[] = { {"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__}, BYTES_TRANSLATE_METHODDEF {"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__}, + BYTES_ZEROS_METHODDEF {"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, _Py_zfill__doc__}, {NULL, NULL} /* sentinel */ }; @@ -2573,6 +2631,11 @@ bytes_new(PyTypeObject *type, PyObject * new = _PyBytes_FromSize(size, 1); if (new == NULL) return NULL; + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "Passing an integer to the bytes constructor is " + "deprecated. Use bytes.zeros(%zd) instead.\n", + size) < 0) + return NULL; return new; } @@ -3099,6 +3162,71 @@ bytes_iter(PyObject *seq) } +/*********************** iterbytes object ****************************/ + +static PyObject * +iterbytes_next(striterobject *it) +{ + PyObject *item = striter_next(it); + if (item != NULL) { + return Py_BuildValue("c", (unsigned char)PyLong_AsLong(item)); + } + return item; +} + +PyTypeObject PyIterBytes_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "bytes_iterator", /* tp_name */ + sizeof(striterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)striter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)striter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)iterbytes_next, /* tp_iternext */ + striter_methods, /* tp_methods */ + 0, +}; + +static PyObject * +bytes_iterbytes(PyObject *seq) +{ + striterobject *it; + + if (!PyBytes_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(striterobject, &PyIterBytes_Type); + if (it == NULL) + return NULL; + it->it_index = 0; + Py_INCREF(seq); + it->it_seq = (PyBytesObject *)seq; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} + + /* _PyBytesWriter API */ #ifdef MS_WINDOWS diff -r 94710cbcac47 Objects/clinic/bytearrayobject.c.h --- a/Objects/clinic/bytearrayobject.c.h Thu Sep 01 13:55:33 2016 -0400 +++ b/Objects/clinic/bytearrayobject.c.h Thu Sep 01 12:23:14 2016 -0700 @@ -648,6 +648,67 @@ exit: return return_value; } +PyDoc_STRVAR(bytearray_zeros__doc__, +"zeros($type, size, /)\n" +"--\n" +"\n" +"Create a bytearray object of size given by the parameter initialized with null bytes.\n" +"\n" +"Parameter must be 0 or a positive integer.\n" +"Example: bytearray.zeros(3) -> bytearray(b\\\'\\\\x00\\\\x00\\\\x00\')"); + +#define BYTEARRAY_ZEROS_METHODDEF \ + {"zeros", (PyCFunction)bytearray_zeros, METH_O|METH_CLASS, bytearray_zeros__doc__}, + +static PyObject * +bytearray_zeros_impl(PyTypeObject *type, int size); + +static PyObject * +bytearray_zeros(PyTypeObject *type, PyObject *arg) +{ + PyObject *return_value = NULL; + int size; + + if (!PyArg_Parse(arg, "i:zeros", &size)) { + goto exit; + } + return_value = bytearray_zeros_impl(type, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(bytearray_byte__doc__, +"byte($type, x, /)\n" +"--\n" +"\n" +"Create a bytearray object, consisting of a single byte.\n" +"\n" +"Parameter must be in range(0, 256)\n" +"bytearray.byte(x) is equivalent to bytearray([x])\n" +"Example: bytearray.byte(3) -> bytearray(b\'\\x03\')"); + +#define BYTEARRAY_BYTE_METHODDEF \ + {"byte", (PyCFunction)bytearray_byte, METH_O|METH_CLASS, bytearray_byte__doc__}, + +static PyObject * +bytearray_byte_impl(PyTypeObject *type, int x); + +static PyObject * +bytearray_byte(PyTypeObject *type, PyObject *arg) +{ + PyObject *return_value = NULL; + int x; + + if (!PyArg_Parse(arg, "i:byte", &x)) { + goto exit; + } + return_value = bytearray_byte_impl(type, x); + +exit: + return return_value; +} + PyDoc_STRVAR(bytearray_reduce__doc__, "__reduce__($self, /)\n" "--\n" @@ -711,4 +772,4 @@ bytearray_sizeof(PyByteArrayObject *self { return bytearray_sizeof_impl(self); } -/*[clinic end generated code: output=59a0c86b29ff06d1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=42bdbffd9f162866 input=a9049054013a1b77]*/ diff -r 94710cbcac47 Objects/clinic/bytesobject.c.h --- a/Objects/clinic/bytesobject.c.h Thu Sep 01 13:55:33 2016 -0400 +++ b/Objects/clinic/bytesobject.c.h Thu Sep 01 12:23:14 2016 -0700 @@ -499,4 +499,66 @@ bytes_fromhex(PyTypeObject *type, PyObje exit: return return_value; } -/*[clinic end generated code: output=5618c05c24c1e617 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(bytes_zeros__doc__, +"zeros($type, size, /)\n" +"--\n" +"\n" +"Create a bytes object of size given by the parameter initialized with null bytes.\n" +"\n" +"Parameter must be 0 or a positive integer.\n" +"Example: bytes.zeros(3) -> b\\\'\\\\x00\\\\x00\\\\x00\'"); + +#define BYTES_ZEROS_METHODDEF \ + {"zeros", (PyCFunction)bytes_zeros, METH_O|METH_CLASS, bytes_zeros__doc__}, + +static PyObject * +bytes_zeros_impl(PyTypeObject *type, int size); + +static PyObject * +bytes_zeros(PyTypeObject *type, PyObject *arg) +{ + PyObject *return_value = NULL; + int size; + + if (!PyArg_Parse(arg, "i:zeros", &size)) { + goto exit; + } + return_value = bytes_zeros_impl(type, size); + +exit: + return return_value; +} +/*[clinic end generated code: output=bb6252dfe230df90 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(bytes_byte__doc__, +"byte($type, x, /)\n" +"--\n" +"\n" +"Create a bytes object, consisting of a single byte.\n" +"\n" +"Parameter must be in range(0, 256)\n" +"bytes.byte(x) is equivalent to bytes([x])\n" +"Example: bytes.byte(3) -> b\'\\x03\'"); + +#define BYTES_BYTE_METHODDEF \ + {"byte", (PyCFunction)bytes_byte, METH_O|METH_CLASS, bytes_byte__doc__}, + +static PyObject * +bytes_byte_impl(PyTypeObject *type, int x); + +static PyObject * +bytes_byte(PyTypeObject *type, PyObject *arg) +{ + PyObject *return_value = NULL; + int x; + + if (!PyArg_Parse(arg, "i:byte", &x)) { + goto exit; + } + return_value = bytes_byte_impl(type, x); + +exit: + return return_value; +} +/*[clinic end generated code: output=08e0d63b0e0453d7 input=a9049054013a1b77]*/ diff -r 94710cbcac47 Objects/memoryobject.c --- a/Objects/memoryobject.c Thu Sep 01 13:55:33 2016 -0400 +++ b/Objects/memoryobject.c Thu Sep 01 12:23:14 2016 -0700 @@ -2564,6 +2564,167 @@ static PySequenceMethods memory_as_seque /**************************************************************************/ +/* iterbytes object */ +/**************************************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t it_index; + PyMemoryViewObject *it_seq; /* Set to NULL when iterator is exhausted */ +} memoryview_iterobject; + +static void +memoryview_iter_dealloc(memoryview_iterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); +} + +static int +memoryview_iter_traverse(memoryview_iterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_seq); + return 0; +} + +static PyObject * +memoryview_iterbytes_next(memoryview_iterobject *it) +{ + PyMemoryViewObject *seq; + PyObject *item; + Py_buffer *view; + + assert(it != NULL); + seq = it->it_seq; + if (seq == NULL) + return NULL; + assert(PyMemoryView_Check(seq)); + view = &(seq->view); + + if (it->it_index < view->shape[0]) { + char *ptr = ptr_from_index(view, it->it_index); + item = Py_BuildValue("c", (unsigned char)*ptr); + if (item != NULL) + ++it->it_index; + return item; + } + + it->it_seq = NULL; + Py_DECREF(seq); + return NULL; +} + +static PyObject * +memoryview_iter_len(memoryview_iterobject *it) +{ + Py_ssize_t len = 0; + if (it->it_seq) + len = Py_SIZE(it->it_seq) - it->it_index; + return PyLong_FromSsize_t(len); +} + +PyDoc_STRVAR(length_hint_doc, + "Private method returning an estimate of len(list(it))."); + +static PyObject * +memoryview_iter_reduce(memoryview_iterobject *it) +{ + if (it->it_seq != NULL) { + return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"), + it->it_seq, it->it_index); + } else { + PyObject *u = PyUnicode_FromUnicode(NULL, 0); + if (u == NULL) + return NULL; + return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u); + } +} + +PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); + +static PyObject * +memoryview_iter_setstate(memoryview_iterobject *it, PyObject *state) +{ + Py_ssize_t index = PyLong_AsSsize_t(state); + if (index == -1 && PyErr_Occurred()) + return NULL; + if (it->it_seq != NULL) { + if (index < 0) + index = 0; + else if (index > Py_SIZE(it->it_seq)) + index = Py_SIZE(it->it_seq); /* iterator exhausted */ + it->it_index = index; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); + +static PyMethodDef memoryview_iter_methods[] = { + {"__length_hint__", (PyCFunction)memoryview_iter_len, METH_NOARGS, + length_hint_doc}, + {"__reduce__", (PyCFunction)memoryview_iter_reduce, METH_NOARGS, + reduce_doc}, + {"__setstate__", (PyCFunction)memoryview_iter_setstate, METH_O, + setstate_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyTypeObject PyMemoryViewIterBytes_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "memoryview_iterator", /* tp_name */ + sizeof(memoryview_iterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)memoryview_iter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)memoryview_iter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)memoryview_iterbytes_next, /* tp_iternext */ + memoryview_iter_methods, /* tp_methods */ + 0, +}; + +static PyObject * +memoryview_iterbytes(PyObject *seq) +{ + memoryview_iterobject *it; + + if (!PyMemoryView_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(memoryview_iterobject, &PyMemoryViewIterBytes_Type); + if (it == NULL) + return NULL; + it->it_index = 0; + Py_INCREF(seq); + it->it_seq = (PyMemoryViewObject *)seq; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} + + +/**************************************************************************/ /* Comparisons */ /**************************************************************************/ @@ -3091,6 +3252,12 @@ PyDoc_STRVAR(memory_cast_doc, "cast($self, /, format, *, shape)\n--\n\ \n\ Cast a memoryview to a new format or shape."); +PyDoc_STRVAR(memory_iterbytes_doc, +"iterbytes($self, /)\n--\n\ +\n\ +Iterator that produces length 1 bytes objects instead of integers"); + +static PyObject *memoryview_iterbytes(PyObject *seq); static PyMethodDef memory_methods[] = { {"release", (PyCFunction)memory_release, METH_NOARGS, memory_release_doc}, @@ -3098,6 +3265,7 @@ static PyMethodDef memory_methods[] = { {"hex", (PyCFunction)memory_hex, METH_NOARGS, memory_hex_doc}, {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_doc}, {"cast", (PyCFunction)memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc}, + {"iterbytes", (PyCFunction)memoryview_iterbytes, METH_NOARGS, memory_iterbytes_doc}, {"__enter__", memory_enter, METH_NOARGS, NULL}, {"__exit__", memory_exit, METH_VARARGS, NULL}, {NULL, NULL}