summaryrefslogtreecommitdiffstats
path: root/Modules/arraymodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/arraymodule.c')
-rw-r--r--Modules/arraymodule.c252
1 files changed, 178 insertions, 74 deletions
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 641e283..b0921c8 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -22,7 +22,7 @@ struct arrayobject; /* Forward */
* functions aren't visible yet.
*/
struct arraydescr {
- Py_UNICODE typecode;
+ char typecode;
int itemsize;
PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
@@ -174,24 +174,25 @@ BB_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
static PyObject *
u_getitem(arrayobject *ap, Py_ssize_t i)
{
- return PyUnicode_FromUnicode(&((Py_UNICODE *) ap->ob_item)[i], 1);
+ return PyUnicode_FromOrdinal(((Py_UCS4 *) ap->ob_item)[i]);
}
static int
u_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{
- Py_UNICODE *p;
- Py_ssize_t len;
+ PyObject *p;
- if (!PyArg_Parse(v, "u#;array item must be unicode character", &p, &len))
+ if (!PyArg_Parse(v, "U;array item must be unicode character", &p))
+ return -1;
+ if (PyUnicode_READY(p))
return -1;
- if (len != 1) {
+ if (PyUnicode_GET_LENGTH(p) != 1) {
PyErr_SetString(PyExc_TypeError,
"array item must be unicode character");
return -1;
}
if (i >= 0)
- ((Py_UNICODE *)ap->ob_item)[i] = p[0];
+ ((Py_UCS4 *)ap->ob_item)[i] = PyUnicode_READ_CHAR(p, 0);
return 0;
}
@@ -356,6 +357,59 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
return 0;
}
+#ifdef HAVE_LONG_LONG
+
+static PyObject *
+q_getitem(arrayobject *ap, Py_ssize_t i)
+{
+ return PyLong_FromLongLong(((PY_LONG_LONG *)ap->ob_item)[i]);
+}
+
+static int
+q_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
+{
+ PY_LONG_LONG x;
+ if (!PyArg_Parse(v, "L;array item must be integer", &x))
+ return -1;
+ if (i >= 0)
+ ((PY_LONG_LONG *)ap->ob_item)[i] = x;
+ return 0;
+}
+
+static PyObject *
+QQ_getitem(arrayobject *ap, Py_ssize_t i)
+{
+ return PyLong_FromUnsignedLongLong(
+ ((unsigned PY_LONG_LONG *)ap->ob_item)[i]);
+}
+
+static int
+QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
+{
+ unsigned PY_LONG_LONG x;
+ if (PyLong_Check(v)) {
+ x = PyLong_AsUnsignedLongLong(v);
+ if (x == (unsigned PY_LONG_LONG) -1 && PyErr_Occurred())
+ return -1;
+ }
+ else {
+ PY_LONG_LONG y;
+ if (!PyArg_Parse(v, "L;array item must be integer", &y))
+ return -1;
+ if (y < 0) {
+ PyErr_SetString(PyExc_OverflowError,
+ "unsigned long long is less than minimum");
+ return -1;
+ }
+ x = (unsigned PY_LONG_LONG)y;
+ }
+
+ if (i >= 0)
+ ((unsigned PY_LONG_LONG *)ap->ob_item)[i] = x;
+ return 0;
+}
+#endif
+
static PyObject *
f_getitem(arrayobject *ap, Py_ssize_t i)
{
@@ -390,6 +444,13 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
return 0;
}
+#if SIZEOF_INT == 4
+# define STRUCT_LONG_FORMAT "I"
+#elif SIZEOF_LONG == 4
+# define STRUCT_LONG_FORMAT "L"
+#else
+# error "Unable to get struct format for Py_UCS4"
+#endif
/* Description of types.
*
@@ -399,13 +460,17 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
static struct arraydescr descriptors[] = {
{'b', 1, b_getitem, b_setitem, "b", 1, 1},
{'B', 1, BB_getitem, BB_setitem, "B", 1, 0},
- {'u', sizeof(Py_UNICODE), u_getitem, u_setitem, "u", 0, 0},
+ {'u', sizeof(Py_UCS4), u_getitem, u_setitem, STRUCT_LONG_FORMAT, 0, 0},
{'h', sizeof(short), h_getitem, h_setitem, "h", 1, 1},
{'H', sizeof(short), HH_getitem, HH_setitem, "H", 1, 0},
{'i', sizeof(int), i_getitem, i_setitem, "i", 1, 1},
{'I', sizeof(int), II_getitem, II_setitem, "I", 1, 0},
{'l', sizeof(long), l_getitem, l_setitem, "l", 1, 1},
{'L', sizeof(long), LL_getitem, LL_setitem, "L", 1, 0},
+#ifdef HAVE_LONG_LONG
+ {'q', sizeof(PY_LONG_LONG), q_getitem, q_setitem, "q", 1, 1},
+ {'Q', sizeof(PY_LONG_LONG), QQ_getitem, QQ_setitem, "Q", 1, 0},
+#endif
{'f', sizeof(float), f_getitem, f_setitem, "f", 0, 0},
{'d', sizeof(double), d_getitem, d_setitem, "d", 0, 0},
{'\0', 0, 0, 0, 0, 0, 0} /* Sentinel */
@@ -514,10 +579,8 @@ array_richcompare(PyObject *v, PyObject *w, int op)
Py_ssize_t i, k;
PyObject *res;
- if (!array_Check(v) || !array_Check(w)) {
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
- }
+ if (!array_Check(v) || !array_Check(w))
+ Py_RETURN_NOTIMPLEMENTED;
va = (arrayobject *)v;
wa = (arrayobject *)w;
@@ -876,7 +939,6 @@ array_inplace_repeat(arrayobject *self, Py_ssize_t n)
if (Py_SIZE(self) > 0) {
if (n < 0)
n = 0;
- items = self->ob_item;
if ((self->ob_descr->itemsize != 0) &&
(Py_SIZE(self) > PY_SSIZE_T_MAX / self->ob_descr->itemsize)) {
return PyErr_NoMemory();
@@ -1191,6 +1253,7 @@ array_fromfile(arrayobject *self, PyObject *args)
PyObject *f, *b, *res;
Py_ssize_t itemsize = self->ob_descr->itemsize;
Py_ssize_t n, nbytes;
+ _Py_IDENTIFIER(read);
int not_enough_bytes;
if (!PyArg_ParseTuple(args, "On:fromfile", &f, &n))
@@ -1202,7 +1265,7 @@ array_fromfile(arrayobject *self, PyObject *args)
return NULL;
}
- b = PyObject_CallMethod(f, "read", "n", nbytes);
+ b = _PyObject_CallMethodId(f, &PyId_read, "n", nbytes);
if (b == NULL)
return NULL;
@@ -1259,12 +1322,14 @@ array_tofile(arrayobject *self, PyObject *f)
char* ptr = self->ob_item + i*BLOCKSIZE;
Py_ssize_t size = BLOCKSIZE;
PyObject *bytes, *res;
+ _Py_IDENTIFIER(write);
+
if (i*BLOCKSIZE + size > nbytes)
size = nbytes - i*BLOCKSIZE;
bytes = PyBytes_FromStringAndSize(ptr, size);
if (bytes == NULL)
return NULL;
- res = PyObject_CallMethod(f, "write", "O", bytes);
+ res = _PyObject_CallMethodId(f, &PyId_write, "O", bytes);
Py_DECREF(bytes);
if (res == NULL)
return NULL;
@@ -1454,25 +1519,26 @@ This method is deprecated. Use tobytes instead.");
static PyObject *
array_fromunicode(arrayobject *self, PyObject *args)
{
- Py_UNICODE *ustr;
+ PyObject *ustr;
Py_ssize_t n;
- Py_UNICODE typecode;
- if (!PyArg_ParseTuple(args, "u#:fromunicode", &ustr, &n))
+ if (!PyArg_ParseTuple(args, "U:fromunicode", &ustr))
return NULL;
- typecode = self->ob_descr->typecode;
- if ((typecode != 'u')) {
+ if (self->ob_descr->typecode != 'u') {
PyErr_SetString(PyExc_ValueError,
"fromunicode() may only be called on "
"unicode type arrays");
return NULL;
}
+ if (PyUnicode_READY(ustr))
+ return NULL;
+ n = PyUnicode_GET_LENGTH(ustr);
if (n > 0) {
Py_ssize_t old_size = Py_SIZE(self);
if (array_resize(self, old_size + n) == -1)
return NULL;
- memcpy(self->ob_item + old_size * sizeof(Py_UNICODE),
- ustr, n * sizeof(Py_UNICODE));
+ if (!PyUnicode_AsUCS4(ustr, (Py_UCS4 *)self->ob_item + old_size, n, 0))
+ return NULL;
}
Py_INCREF(Py_None);
@@ -1491,14 +1557,14 @@ append Unicode data to an array of some other type.");
static PyObject *
array_tounicode(arrayobject *self, PyObject *unused)
{
- Py_UNICODE typecode;
- typecode = self->ob_descr->typecode;
- if ((typecode != 'u')) {
+ if (self->ob_descr->typecode != 'u') {
PyErr_SetString(PyExc_ValueError,
"tounicode() may only be called on unicode type arrays");
return NULL;
}
- return PyUnicode_FromUnicode((Py_UNICODE *) self->ob_item, Py_SIZE(self));
+ return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND,
+ (Py_UCS4 *) self->ob_item,
+ Py_SIZE(self));
}
PyDoc_STRVAR(tounicode_doc,
@@ -1588,7 +1654,7 @@ static const struct mformatdescr {
* be found.
*/
static enum machine_format_code
-typecode_to_mformat_code(int typecode)
+typecode_to_mformat_code(char typecode)
{
#ifdef WORDS_BIGENDIAN
const int is_big_endian = 1;
@@ -1605,13 +1671,7 @@ typecode_to_mformat_code(int typecode)
return UNSIGNED_INT8;
case 'u':
- if (sizeof(Py_UNICODE) == 2) {
- return UTF16_LE + is_big_endian;
- }
- if (sizeof(Py_UNICODE) == 4) {
- return UTF32_LE + is_big_endian;
- }
- return UNKNOWN_FORMAT;
+ return UTF32_LE + is_big_endian;
case 'f':
if (sizeof(float) == 4) {
@@ -1658,6 +1718,16 @@ typecode_to_mformat_code(int typecode)
intsize = sizeof(long);
is_signed = 0;
break;
+#if HAVE_LONG_LONG
+ case 'q':
+ intsize = sizeof(PY_LONG_LONG);
+ is_signed = 1;
+ break;
+ case 'Q':
+ intsize = sizeof(PY_LONG_LONG);
+ is_signed = 0;
+ break;
+#endif
default:
return UNKNOWN_FORMAT;
}
@@ -1688,7 +1758,7 @@ static PyObject *array_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
* NULL is returned to indicate a failure.
*/
static PyObject *
-make_array(PyTypeObject *arraytype, Py_UNICODE typecode, PyObject *items)
+make_array(PyTypeObject *arraytype, char typecode, PyObject *items)
{
PyObject *new_args;
PyObject *array_obj;
@@ -1697,7 +1767,7 @@ make_array(PyTypeObject *arraytype, Py_UNICODE typecode, PyObject *items)
assert(arraytype != NULL);
assert(items != NULL);
- typecode_obj = PyUnicode_FromUnicode(&typecode, 1);
+ typecode_obj = PyUnicode_FromOrdinal(typecode);
if (typecode_obj == NULL)
return NULL;
@@ -1727,17 +1797,14 @@ array_reconstructor(PyObject *self, PyObject *args)
PyObject *items;
PyObject *converted_items;
PyObject *result;
- int typecode_int;
- Py_UNICODE typecode;
+ int typecode;
enum machine_format_code mformat_code;
struct arraydescr *descr;
if (!PyArg_ParseTuple(args, "OCiO:array._array_reconstructor",
- &arraytype, &typecode_int, &mformat_code, &items))
+ &arraytype, &typecode, &mformat_code, &items))
return NULL;
- typecode = (Py_UNICODE)typecode_int;
-
if (!PyType_Check(arraytype)) {
PyErr_Format(PyExc_TypeError,
"first argument must a type object, not %.200s",
@@ -1751,7 +1818,7 @@ array_reconstructor(PyObject *self, PyObject *args)
return NULL;
}
for (descr = descriptors; descr->typecode != '\0'; descr++) {
- if (descr->typecode == typecode)
+ if ((int)descr->typecode == typecode)
break;
}
if (descr->typecode == '\0') {
@@ -1773,9 +1840,9 @@ array_reconstructor(PyObject *self, PyObject *args)
}
/* Fast path: No decoding has to be done. */
- if (mformat_code == typecode_to_mformat_code(typecode) ||
+ if (mformat_code == typecode_to_mformat_code((char)typecode) ||
mformat_code == UNKNOWN_FORMAT) {
- return make_array(arraytype, typecode, items);
+ return make_array(arraytype, (char)typecode, items);
}
/* Slow path: Decode the byte string according to the given machine
@@ -1921,7 +1988,7 @@ array_reconstructor(PyObject *self, PyObject *args)
return NULL;
}
- result = make_array(arraytype, typecode, converted_items);
+ result = make_array(arraytype, (char)typecode, converted_items);
Py_DECREF(converted_items);
return result;
}
@@ -1936,14 +2003,16 @@ array_reduce_ex(arrayobject *array, PyObject *value)
int mformat_code;
static PyObject *array_reconstructor = NULL;
long protocol;
+ _Py_IDENTIFIER(_array_reconstructor);
+ _Py_IDENTIFIER(__dict__);
if (array_reconstructor == NULL) {
PyObject *array_module = PyImport_ImportModule("array");
if (array_module == NULL)
return NULL;
- array_reconstructor = PyObject_GetAttrString(
+ array_reconstructor = _PyObject_GetAttrId(
array_module,
- "_array_reconstructor");
+ &PyId__array_reconstructor);
Py_DECREF(array_module);
if (array_reconstructor == NULL)
return NULL;
@@ -1958,7 +2027,7 @@ array_reduce_ex(arrayobject *array, PyObject *value)
if (protocol == -1 && PyErr_Occurred())
return NULL;
- dict = PyObject_GetAttrString((PyObject *)array, "__dict__");
+ dict = _PyObject_GetAttrId((PyObject *)array, &PyId___dict__);
if (dict == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
@@ -2010,8 +2079,8 @@ PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
static PyObject *
array_get_typecode(arrayobject *a, void *closure)
{
- Py_UNICODE tc = a->ob_descr->typecode;
- return PyUnicode_FromUnicode(&tc, 1);
+ char typecode = a->ob_descr->typecode;
+ return PyUnicode_FromOrdinal(typecode);
}
static PyObject *
@@ -2083,7 +2152,7 @@ static PyMethodDef array_methods[] = {
static PyObject *
array_repr(arrayobject *a)
{
- Py_UNICODE typecode;
+ char typecode;
PyObject *s, *v = NULL;
Py_ssize_t len;
@@ -2092,7 +2161,7 @@ array_repr(arrayobject *a)
if (len == 0) {
return PyUnicode_FromFormat("array('%c')", (int)typecode);
}
- if ((typecode == 'u'))
+ if (typecode == 'u')
v = array_tounicode(a, NULL);
else
v = array_tolist(a, NULL);
@@ -2287,7 +2356,7 @@ array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
self->ob_item + (cur + 1) * itemsize,
lim * itemsize);
}
- cur = start + slicelength * step;
+ cur = start + (size_t)slicelength * step;
if (cur < (size_t)Py_SIZE(self)) {
memmove(self->ob_item + (cur-slicelength) * itemsize,
self->ob_item + cur * itemsize,
@@ -2350,14 +2419,8 @@ array_buffer_getbuf(arrayobject *self, Py_buffer *view, int flags)
view->strides = &(view->itemsize);
view->format = NULL;
view->internal = NULL;
- if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
view->format = self->ob_descr->formats;
-#ifdef Py_UNICODE_WIDE
- if (self->ob_descr->typecode == 'u') {
- view->format = "w";
- }
-#endif
- }
finish:
self->ob_exports++;
@@ -2471,19 +2534,25 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_DECREF(v);
}
else if (initial != NULL && PyUnicode_Check(initial)) {
- Py_ssize_t n = PyUnicode_GET_DATA_SIZE(initial);
+ Py_ssize_t n;
+ if (PyUnicode_READY(initial)) {
+ Py_DECREF(a);
+ return NULL;
+ }
+ n = PyUnicode_GET_LENGTH(initial);
if (n > 0) {
arrayobject *self = (arrayobject *)a;
- char *item = self->ob_item;
- item = (char *)PyMem_Realloc(item, n);
+ Py_UCS4 *item = (Py_UCS4 *)self->ob_item;
+ item = (Py_UCS4 *)PyMem_Realloc(item, n * sizeof(Py_UCS4));
if (item == NULL) {
PyErr_NoMemory();
Py_DECREF(a);
return NULL;
}
- self->ob_item = item;
- Py_SIZE(self) = n / sizeof(Py_UNICODE);
- memcpy(item, PyUnicode_AS_DATA(initial), n);
+ self->ob_item = (char*)item;
+ Py_SIZE(self) = n;
+ if (!PyUnicode_AsUCS4(initial, item, n, 0))
+ return NULL;
self->allocated = Py_SIZE(self);
}
}
@@ -2504,7 +2573,11 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
}
PyErr_SetString(PyExc_ValueError,
+#ifdef HAVE_LONG_LONG
+ "bad typecode (must be b, B, u, h, H, i, I, l, L, q, Q, f or d)");
+#else
"bad typecode (must be b, B, u, h, H, i, I, l, L, f or d)");
+#endif
return NULL;
}
@@ -2520,18 +2593,21 @@ is a single character. The following type codes are defined:\n\
Type code C Type Minimum size in bytes \n\
'b' signed integer 1 \n\
'B' unsigned integer 1 \n\
- 'u' Unicode character 2 (see note) \n\
+ 'u' Unicode character 4 \n\
'h' signed integer 2 \n\
'H' unsigned integer 2 \n\
'i' signed integer 2 \n\
'I' unsigned integer 2 \n\
'l' signed integer 4 \n\
'L' unsigned integer 4 \n\
+ 'q' signed integer 8 (see note) \n\
+ 'Q' unsigned integer 8 (see note) \n\
'f' floating point 4 \n\
'd' floating point 8 \n\
\n\
-NOTE: The 'u' typecode corresponds to Python's unicode character. On \n\
-narrow builds this is 2-bytes on wide builds this is 4-bytes.\n\
+NOTE: The 'q' and 'Q' type codes are only available if the platform \n\
+C compiler used to build Python supports 'long long', or, on Windows, \n\
+'__int64'.\n\
\n\
The constructor is:\n\
\n\
@@ -2677,6 +2753,34 @@ arrayiter_traverse(arrayiterobject *it, visitproc visit, void *arg)
return 0;
}
+static PyObject *
+arrayiter_reduce(arrayiterobject *it)
+{
+ return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+ it->ao, it->index);
+}
+
+static PyObject *
+arrayiter_setstate(arrayiterobject *it, PyObject *state)
+{
+ Py_ssize_t index = PyLong_AsSsize_t(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ if (index < 0)
+ index = 0;
+ it->index = index;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+static PyMethodDef arrayiter_methods[] = {
+ {"__reduce__", (PyCFunction)arrayiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)arrayiter_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
static PyTypeObject PyArrayIter_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"arrayiterator", /* tp_name */
@@ -2706,7 +2810,7 @@ static PyTypeObject PyArrayIter_Type = {
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)arrayiter_next, /* tp_iternext */
- 0, /* tp_methods */
+ arrayiter_methods, /* tp_methods */
};
@@ -2736,9 +2840,9 @@ PyMODINIT_FUNC
PyInit_array(void)
{
PyObject *m;
+ char buffer[Py_ARRAY_LENGTH(descriptors)], *p;
PyObject *typecodes;
Py_ssize_t size = 0;
- register Py_UNICODE *p;
struct arraydescr *descr;
if (PyType_Ready(&Arraytype) < 0)
@@ -2757,13 +2861,13 @@ PyInit_array(void)
size++;
}
- typecodes = PyUnicode_FromStringAndSize(NULL, size);
- p = PyUnicode_AS_UNICODE(typecodes);
+ p = buffer;
for (descr = descriptors; descr->typecode != '\0'; descr++) {
*p++ = (char)descr->typecode;
}
+ typecodes = PyUnicode_DecodeASCII(buffer, p - buffer, NULL);
- PyModule_AddObject(m, "typecodes", (PyObject *)typecodes);
+ PyModule_AddObject(m, "typecodes", typecodes);
if (PyErr_Occurred()) {
Py_DECREF(m);