Skip to content

Commit 1c9f0c9

Browse files
committed
Issue #1172711: Add 'long long' support to the array module.
Initial patch by Oren Tirosh and Hirokazu Yamamoto.
1 parent 4ad6ed7 commit 1c9f0c9

4 files changed

Lines changed: 143 additions & 30 deletions

File tree

Doc/library/array.rst

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,49 @@ them is constrained. The type is specified at object creation time by using a
1414
:dfn:`type code`, which is a single character. The following type codes are
1515
defined:
1616

17-
+-----------+----------------+-------------------+-----------------------+
18-
| Type code | C Type | Python Type | Minimum size in bytes |
19-
+===========+================+===================+=======================+
20-
| ``'b'`` | signed char | int | 1 |
21-
+-----------+----------------+-------------------+-----------------------+
22-
| ``'B'`` | unsigned char | int | 1 |
23-
+-----------+----------------+-------------------+-----------------------+
24-
| ``'u'`` | Py_UNICODE | Unicode character | 2 (see note) |
25-
+-----------+----------------+-------------------+-----------------------+
26-
| ``'h'`` | signed short | int | 2 |
27-
+-----------+----------------+-------------------+-----------------------+
28-
| ``'H'`` | unsigned short | int | 2 |
29-
+-----------+----------------+-------------------+-----------------------+
30-
| ``'i'`` | signed int | int | 2 |
31-
+-----------+----------------+-------------------+-----------------------+
32-
| ``'I'`` | unsigned int | int | 2 |
33-
+-----------+----------------+-------------------+-----------------------+
34-
| ``'l'`` | signed long | int | 4 |
35-
+-----------+----------------+-------------------+-----------------------+
36-
| ``'L'`` | unsigned long | int | 4 |
37-
+-----------+----------------+-------------------+-----------------------+
38-
| ``'f'`` | float | float | 4 |
39-
+-----------+----------------+-------------------+-----------------------+
40-
| ``'d'`` | double | float | 8 |
41-
+-----------+----------------+-------------------+-----------------------+
42-
43-
.. note::
44-
45-
The ``'u'`` typecode corresponds to Python's unicode character. On narrow
17+
+-----------+--------------------+-------------------+-----------------------+-------+
18+
| Type code | C Type | Python Type | Minimum size in bytes | Notes |
19+
+===========+====================+===================+=======================+=======+
20+
| ``'b'`` | signed char | int | 1 | |
21+
+-----------+--------------------+-------------------+-----------------------+-------+
22+
| ``'B'`` | unsigned char | int | 1 | |
23+
+-----------+--------------------+-------------------+-----------------------+-------+
24+
| ``'u'`` | Py_UNICODE | Unicode character | 2 | \(1) |
25+
+-----------+--------------------+-------------------+-----------------------+-------+
26+
| ``'h'`` | signed short | int | 2 | |
27+
+-----------+--------------------+-------------------+-----------------------+-------+
28+
| ``'H'`` | unsigned short | int | 2 | |
29+
+-----------+--------------------+-------------------+-----------------------+-------+
30+
| ``'i'`` | signed int | int | 2 | |
31+
+-----------+--------------------+-------------------+-----------------------+-------+
32+
| ``'I'`` | unsigned int | int | 2 | |
33+
+-----------+--------------------+-------------------+-----------------------+-------+
34+
| ``'l'`` | signed long | int | 4 | |
35+
+-----------+--------------------+-------------------+-----------------------+-------+
36+
| ``'L'`` | unsigned long | int | 4 | |
37+
+-----------+--------------------+-------------------+-----------------------+-------+
38+
| ``'q'`` | signed long long | int | 8 | \(2) |
39+
+-----------+--------------------+-------------------+-----------------------+-------+
40+
| ``'Q'`` | unsigned long long | int | 8 | \(2) |
41+
+-----------+--------------------+-------------------+-----------------------+-------+
42+
| ``'f'`` | float | float | 4 | |
43+
+-----------+--------------------+-------------------+-----------------------+-------+
44+
| ``'d'`` | double | float | 8 | |
45+
+-----------+--------------------+-------------------+-----------------------+-------+
46+
47+
Notes:
48+
49+
(1)
50+
The ``'u'`` type code corresponds to Python's unicode character. On narrow
4651
Unicode builds this is 2-bytes, on wide builds this is 4-bytes.
4752

53+
(2)
54+
The ``'q'`` and ``'Q'`` type codes are available only if
55+
the platform C compiler used to build Python supports C :ctype:`long long`,
56+
or, on Windows, :ctype:`__int64`.
57+
58+
.. versionadded:: 3.3
59+
4860
The actual representation of values is determined by the machine architecture
4961
(strictly speaking, by the C implementation). The actual size can be accessed
5062
through the :attr:`itemsize` attribute.

Lib/test/test_array.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616
import array
1717
from array import _array_reconstructor as array_reconstructor
1818

19+
try:
20+
# Try to determine availability of long long independently
21+
# of the array module under test
22+
struct.calcsize('@q')
23+
have_long_long = True
24+
except struct.error:
25+
have_long_long = False
1926

2027
class ArraySubclass(array.array):
2128
pass
@@ -26,6 +33,8 @@ def __init__(self, typecode, newarg=None):
2633

2734
tests = [] # list to accumulate all tests
2835
typecodes = "ubBhHiIlLfd"
36+
if have_long_long:
37+
typecodes += 'qQ'
2938

3039
class BadConstructorTest(unittest.TestCase):
3140

@@ -1205,6 +1214,18 @@ class UnsignedLongTest(UnsignedNumberTest):
12051214
minitemsize = 4
12061215
tests.append(UnsignedLongTest)
12071216

1217+
@unittest.skipIf(not have_long_long, 'need long long support')
1218+
class LongLongTest(SignedNumberTest):
1219+
typecode = 'q'
1220+
minitemsize = 8
1221+
tests.append(LongLongTest)
1222+
1223+
@unittest.skipIf(not have_long_long, 'need long long support')
1224+
class UnsignedLongLongTest(UnsignedNumberTest):
1225+
typecode = 'Q'
1226+
minitemsize = 8
1227+
tests.append(UnsignedLongLongTest)
1228+
12081229
class FPTest(NumberTest):
12091230
example = [-42.0, 0, 42, 1e5, -1e10]
12101231
smallerexample = [-42.0, 0, 42, 1e5, -2e10]

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,9 @@ Tools/Demos
12871287
Extension Modules
12881288
-----------------
12891289

1290+
- Issue #1172711: Add 'long long' support to the array module.
1291+
Initial patch by Oren Tirosh and Hirokazu Yamamoto.
1292+
12901293
- Issue #12483: ctypes: Fix a crash when the destruction of a callback
12911294
object triggers the garbage collector.
12921295

Modules/arraymodule.c

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,59 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
356356
return 0;
357357
}
358358

359+
#ifdef HAVE_LONG_LONG
360+
361+
static PyObject *
362+
q_getitem(arrayobject *ap, Py_ssize_t i)
363+
{
364+
return PyLong_FromLongLong(((PY_LONG_LONG *)ap->ob_item)[i]);
365+
}
366+
367+
static int
368+
q_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
369+
{
370+
PY_LONG_LONG x;
371+
if (!PyArg_Parse(v, "L;array item must be integer", &x))
372+
return -1;
373+
if (i >= 0)
374+
((PY_LONG_LONG *)ap->ob_item)[i] = x;
375+
return 0;
376+
}
377+
378+
static PyObject *
379+
QQ_getitem(arrayobject *ap, Py_ssize_t i)
380+
{
381+
return PyLong_FromUnsignedLongLong(
382+
((unsigned PY_LONG_LONG *)ap->ob_item)[i]);
383+
}
384+
385+
static int
386+
QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
387+
{
388+
unsigned PY_LONG_LONG x;
389+
if (PyLong_Check(v)) {
390+
x = PyLong_AsUnsignedLongLong(v);
391+
if (x == (unsigned PY_LONG_LONG) -1 && PyErr_Occurred())
392+
return -1;
393+
}
394+
else {
395+
PY_LONG_LONG y;
396+
if (!PyArg_Parse(v, "L;array item must be integer", &y))
397+
return -1;
398+
if (y < 0) {
399+
PyErr_SetString(PyExc_OverflowError,
400+
"unsigned long long is less than minimum");
401+
return -1;
402+
}
403+
x = (unsigned PY_LONG_LONG)y;
404+
}
405+
406+
if (i >= 0)
407+
((unsigned PY_LONG_LONG *)ap->ob_item)[i] = x;
408+
return 0;
409+
}
410+
#endif
411+
359412
static PyObject *
360413
f_getitem(arrayobject *ap, Py_ssize_t i)
361414
{
@@ -406,6 +459,10 @@ static struct arraydescr descriptors[] = {
406459
{'I', sizeof(int), II_getitem, II_setitem, "I", 1, 0},
407460
{'l', sizeof(long), l_getitem, l_setitem, "l", 1, 1},
408461
{'L', sizeof(long), LL_getitem, LL_setitem, "L", 1, 0},
462+
#ifdef HAVE_LONG_LONG
463+
{'q', sizeof(PY_LONG_LONG), q_getitem, q_setitem, "q", 1, 1},
464+
{'Q', sizeof(PY_LONG_LONG), QQ_getitem, QQ_setitem, "Q", 1, 0},
465+
#endif
409466
{'f', sizeof(float), f_getitem, f_setitem, "f", 0, 0},
410467
{'d', sizeof(double), d_getitem, d_setitem, "d", 0, 0},
411468
{'\0', 0, 0, 0, 0, 0, 0} /* Sentinel */
@@ -1655,6 +1712,16 @@ typecode_to_mformat_code(int typecode)
16551712
intsize = sizeof(long);
16561713
is_signed = 0;
16571714
break;
1715+
#if HAVE_LONG_LONG
1716+
case 'q':
1717+
intsize = sizeof(PY_LONG_LONG);
1718+
is_signed = 1;
1719+
break;
1720+
case 'Q':
1721+
intsize = sizeof(PY_LONG_LONG);
1722+
is_signed = 0;
1723+
break;
1724+
#endif
16581725
default:
16591726
return UNKNOWN_FORMAT;
16601727
}
@@ -2501,7 +2568,11 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
25012568
}
25022569
}
25032570
PyErr_SetString(PyExc_ValueError,
2571+
#ifdef HAVE_LONG_LONG
2572+
"bad typecode (must be b, B, u, h, H, i, I, l, L, q, Q, f or d)");
2573+
#else
25042574
"bad typecode (must be b, B, u, h, H, i, I, l, L, f or d)");
2575+
#endif
25052576
return NULL;
25062577
}
25072578

@@ -2524,12 +2595,18 @@ is a single character. The following type codes are defined:\n\
25242595
'I' unsigned integer 2 \n\
25252596
'l' signed integer 4 \n\
25262597
'L' unsigned integer 4 \n\
2598+
'q' signed integer 8 (see note) \n\
2599+
'Q' unsigned integer 8 (see note) \n\
25272600
'f' floating point 4 \n\
25282601
'd' floating point 8 \n\
25292602
\n\
2530-
NOTE: The 'u' typecode corresponds to Python's unicode character. On \n\
2603+
NOTE: The 'u' type code corresponds to Python's unicode character. On \n\
25312604
narrow builds this is 2-bytes on wide builds this is 4-bytes.\n\
25322605
\n\
2606+
NOTE: The 'q' and 'Q' type codes are only available if the platform \n\
2607+
C compiler used to build Python supports 'long long', or, on Windows, \n\
2608+
'__int64'.\n\
2609+
\n\
25332610
The constructor is:\n\
25342611
\n\
25352612
array(typecode [, initializer]) -- create a new array\n\

0 commit comments

Comments
 (0)