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

Skip to content

Commit 93f562c

Browse files
committed
Merged revisions 77842 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r77842 | mark.dickinson | 2010-01-30 10:08:33 +0000 (Sat, 30 Jan 2010) | 4 lines Issue #7767: Add new C-API function PyLong_AsLongLongAndOverflow, a long long variant of PyLong_AsLongAndOverflow. Patch by Case Van Horsen. ........
1 parent a79b757 commit 93f562c

5 files changed

Lines changed: 280 additions & 0 deletions

File tree

Doc/c-api/long.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@ All integers are implemented as "long" integer objects of arbitrary size.
130130
be ``0``.
131131

132132

133+
.. cfunction:: PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject *pylong, int* overflow)
134+
135+
Return a C :ctype:`long long` representation of the contents of
136+
*pylong*. If *pylong* is greater than :const:`PY_LLONG_MAX` or less
137+
than :const:`PY_LLONG_MIN`, set `*overflow` to ``1`` or ``-1``,
138+
respectively, and return ``-1``; otherwise, set `*overflow` to
139+
``0``. If any other exception occurs (for example a TypeError or
140+
MemoryError), then ``-1`` will be returned and ``*overflow`` will
141+
be ``0``.
142+
143+
.. versionadded:: 3.2
144+
145+
133146
.. cfunction:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong)
134147

135148
.. index::

Include/longobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG);
6262
PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *);
6363
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *);
6464
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *);
65+
PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLongAndOverflow(PyObject *, int *);
6566
#endif /* HAVE_LONG_LONG */
6667

6768
PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int);

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ Core and Builtins
192192
C-API
193193
-----
194194

195+
- Issue #7767: New function PyLong_AsLongLongAndOverflow added,
196+
analogous to PyLong_AsLongAndOverflow.
197+
195198
- Make PyUnicode_CompareWithASCIIString return not equal if the Python string
196199
has '\0' at the end.
197200

Modules/_testcapimodule.c

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,171 @@ test_long_and_overflow(PyObject *self)
524524
return Py_None;
525525
}
526526

527+
/* Test the PyLong_AsLongLongAndOverflow API. General conversion to
528+
PY_LONG_LONG is tested by test_long_api_inner. This test will
529+
concentrate on proper handling of overflow.
530+
*/
531+
532+
static PyObject *
533+
test_long_long_and_overflow(PyObject *self)
534+
{
535+
PyObject *num, *one, *temp;
536+
PY_LONG_LONG value;
537+
int overflow;
538+
539+
/* Test that overflow is set properly for a large value. */
540+
/* num is a number larger than PY_LLONG_MAX on a typical machine. */
541+
num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
542+
if (num == NULL)
543+
return NULL;
544+
overflow = 1234;
545+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
546+
Py_DECREF(num);
547+
if (value == -1 && PyErr_Occurred())
548+
return NULL;
549+
if (value != -1)
550+
return raiseTestError("test_long_long_and_overflow",
551+
"return value was not set to -1");
552+
if (overflow != 1)
553+
return raiseTestError("test_long_long_and_overflow",
554+
"overflow was not set to 1");
555+
556+
/* Same again, with num = PY_LLONG_MAX + 1 */
557+
num = PyLong_FromLongLong(PY_LLONG_MAX);
558+
if (num == NULL)
559+
return NULL;
560+
one = PyLong_FromLong(1L);
561+
if (one == NULL) {
562+
Py_DECREF(num);
563+
return NULL;
564+
}
565+
temp = PyNumber_Add(num, one);
566+
Py_DECREF(one);
567+
Py_DECREF(num);
568+
num = temp;
569+
if (num == NULL)
570+
return NULL;
571+
overflow = 0;
572+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
573+
Py_DECREF(num);
574+
if (value == -1 && PyErr_Occurred())
575+
return NULL;
576+
if (value != -1)
577+
return raiseTestError("test_long_long_and_overflow",
578+
"return value was not set to -1");
579+
if (overflow != 1)
580+
return raiseTestError("test_long_long_and_overflow",
581+
"overflow was not set to 1");
582+
583+
/* Test that overflow is set properly for a large negative value. */
584+
/* num is a number smaller than PY_LLONG_MIN on a typical platform */
585+
num = PyLong_FromString("-FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
586+
if (num == NULL)
587+
return NULL;
588+
overflow = 1234;
589+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
590+
Py_DECREF(num);
591+
if (value == -1 && PyErr_Occurred())
592+
return NULL;
593+
if (value != -1)
594+
return raiseTestError("test_long_long_and_overflow",
595+
"return value was not set to -1");
596+
if (overflow != -1)
597+
return raiseTestError("test_long_long_and_overflow",
598+
"overflow was not set to -1");
599+
600+
/* Same again, with num = PY_LLONG_MIN - 1 */
601+
num = PyLong_FromLongLong(PY_LLONG_MIN);
602+
if (num == NULL)
603+
return NULL;
604+
one = PyLong_FromLong(1L);
605+
if (one == NULL) {
606+
Py_DECREF(num);
607+
return NULL;
608+
}
609+
temp = PyNumber_Subtract(num, one);
610+
Py_DECREF(one);
611+
Py_DECREF(num);
612+
num = temp;
613+
if (num == NULL)
614+
return NULL;
615+
overflow = 0;
616+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
617+
Py_DECREF(num);
618+
if (value == -1 && PyErr_Occurred())
619+
return NULL;
620+
if (value != -1)
621+
return raiseTestError("test_long_long_and_overflow",
622+
"return value was not set to -1");
623+
if (overflow != -1)
624+
return raiseTestError("test_long_long_and_overflow",
625+
"overflow was not set to -1");
626+
627+
/* Test that overflow is cleared properly for small values. */
628+
num = PyLong_FromString("FF", NULL, 16);
629+
if (num == NULL)
630+
return NULL;
631+
overflow = 1234;
632+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
633+
Py_DECREF(num);
634+
if (value == -1 && PyErr_Occurred())
635+
return NULL;
636+
if (value != 0xFF)
637+
return raiseTestError("test_long_long_and_overflow",
638+
"expected return value 0xFF");
639+
if (overflow != 0)
640+
return raiseTestError("test_long_long_and_overflow",
641+
"overflow was not cleared");
642+
643+
num = PyLong_FromString("-FF", NULL, 16);
644+
if (num == NULL)
645+
return NULL;
646+
overflow = 0;
647+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
648+
Py_DECREF(num);
649+
if (value == -1 && PyErr_Occurred())
650+
return NULL;
651+
if (value != -0xFF)
652+
return raiseTestError("test_long_long_and_overflow",
653+
"expected return value 0xFF");
654+
if (overflow != 0)
655+
return raiseTestError("test_long_long_and_overflow",
656+
"overflow was set incorrectly");
657+
658+
num = PyLong_FromLongLong(PY_LLONG_MAX);
659+
if (num == NULL)
660+
return NULL;
661+
overflow = 1234;
662+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
663+
Py_DECREF(num);
664+
if (value == -1 && PyErr_Occurred())
665+
return NULL;
666+
if (value != PY_LLONG_MAX)
667+
return raiseTestError("test_long_long_and_overflow",
668+
"expected return value PY_LLONG_MAX");
669+
if (overflow != 0)
670+
return raiseTestError("test_long_long_and_overflow",
671+
"overflow was not cleared");
672+
673+
num = PyLong_FromLongLong(PY_LLONG_MIN);
674+
if (num == NULL)
675+
return NULL;
676+
overflow = 0;
677+
value = PyLong_AsLongLongAndOverflow(num, &overflow);
678+
Py_DECREF(num);
679+
if (value == -1 && PyErr_Occurred())
680+
return NULL;
681+
if (value != PY_LLONG_MIN)
682+
return raiseTestError("test_long_long_and_overflow",
683+
"expected return value PY_LLONG_MIN");
684+
if (overflow != 0)
685+
return raiseTestError("test_long_long_and_overflow",
686+
"overflow was not cleared");
687+
688+
Py_INCREF(Py_None);
689+
return Py_None;
690+
}
691+
527692
/* Test the L code for PyArg_ParseTuple. This should deliver a PY_LONG_LONG
528693
for both long and int arguments. The test may leak a little memory if
529694
it fails.
@@ -1791,6 +1956,8 @@ static PyMethodDef TestMethods[] = {
17911956
{"getargs_L", getargs_L, METH_VARARGS},
17921957
{"getargs_K", getargs_K, METH_VARARGS},
17931958
{"test_longlong_api", test_longlong_api, METH_NOARGS},
1959+
{"test_long_long_and_overflow",
1960+
(PyCFunction)test_long_long_and_overflow, METH_NOARGS},
17941961
{"test_L_code", (PyCFunction)test_L_code, METH_NOARGS},
17951962
{"codec_incrementalencoder",
17961963
(PyCFunction)codec_incrementalencoder, METH_VARARGS},

Objects/longobject.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ PyLong_AsVoidPtr(PyObject *vv)
971971
*/
972972

973973
#define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one
974+
#define PY_ABS_LLONG_MIN (0-(unsigned PY_LONG_LONG)PY_LLONG_MIN)
974975

975976
/* Create a new long int object from a C PY_LONG_LONG int. */
976977

@@ -1269,6 +1270,101 @@ PyLong_AsUnsignedLongLongMask(register PyObject *op)
12691270
}
12701271
#undef IS_LITTLE_ENDIAN
12711272

1273+
/* Get a C long long int from a Python long or Python int object.
1274+
On overflow, returns -1 and sets *overflow to 1 or -1 depending
1275+
on the sign of the result. Otherwise *overflow is 0.
1276+
1277+
For other errors (e.g., type error), returns -1 and sets an error
1278+
condition.
1279+
*/
1280+
1281+
PY_LONG_LONG
1282+
PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
1283+
{
1284+
/* This version by Tim Peters */
1285+
register PyLongObject *v;
1286+
unsigned PY_LONG_LONG x, prev;
1287+
PY_LONG_LONG res;
1288+
Py_ssize_t i;
1289+
int sign;
1290+
int do_decref = 0; /* if nb_int was called */
1291+
1292+
*overflow = 0;
1293+
if (vv == NULL) {
1294+
PyErr_BadInternalCall();
1295+
return -1;
1296+
}
1297+
1298+
if (!PyLong_Check(vv)) {
1299+
PyNumberMethods *nb;
1300+
nb = vv->ob_type->tp_as_number;
1301+
if (nb == NULL || nb->nb_int == NULL) {
1302+
PyErr_SetString(PyExc_TypeError,
1303+
"an integer is required");
1304+
return -1;
1305+
}
1306+
vv = (*nb->nb_int) (vv);
1307+
if (vv == NULL)
1308+
return -1;
1309+
do_decref = 1;
1310+
if (!PyLong_Check(vv)) {
1311+
Py_DECREF(vv);
1312+
PyErr_SetString(PyExc_TypeError,
1313+
"nb_int should return int object");
1314+
return -1;
1315+
}
1316+
}
1317+
1318+
res = -1;
1319+
v = (PyLongObject *)vv;
1320+
i = Py_SIZE(v);
1321+
1322+
switch (i) {
1323+
case -1:
1324+
res = -(sdigit)v->ob_digit[0];
1325+
break;
1326+
case 0:
1327+
res = 0;
1328+
break;
1329+
case 1:
1330+
res = v->ob_digit[0];
1331+
break;
1332+
default:
1333+
sign = 1;
1334+
x = 0;
1335+
if (i < 0) {
1336+
sign = -1;
1337+
i = -(i);
1338+
}
1339+
while (--i >= 0) {
1340+
prev = x;
1341+
x = (x << PyLong_SHIFT) + v->ob_digit[i];
1342+
if ((x >> PyLong_SHIFT) != prev) {
1343+
*overflow = sign;
1344+
goto exit;
1345+
}
1346+
}
1347+
/* Haven't lost any bits, but casting to long requires extra
1348+
* care (see comment above).
1349+
*/
1350+
if (x <= (unsigned PY_LONG_LONG)PY_LLONG_MAX) {
1351+
res = (PY_LONG_LONG)x * sign;
1352+
}
1353+
else if (sign < 0 && x == PY_ABS_LLONG_MIN) {
1354+
res = PY_LLONG_MIN;
1355+
}
1356+
else {
1357+
*overflow = sign;
1358+
/* res is already set to -1 */
1359+
}
1360+
}
1361+
exit:
1362+
if (do_decref) {
1363+
Py_DECREF(vv);
1364+
}
1365+
return res;
1366+
}
1367+
12721368
#endif /* HAVE_LONG_LONG */
12731369

12741370
#define CHECK_BINOP(v,w) \

0 commit comments

Comments
 (0)