summaryrefslogtreecommitdiffstats
path: root/Objects/longobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/longobject.c')
-rw-r--r--Objects/longobject.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 304fabf..cf859cc 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -39,6 +39,9 @@ medium_value(PyLongObject *x)
#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits; use sys.set_int_max_str_digits() to increase the limit"
#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit"
+/* If defined, use algorithms from the _pylong.py module */
+#define WITH_PYLONG_MODULE 1
+
static inline void
_Py_DECREF_INT(PyLongObject *op)
{
@@ -1732,6 +1735,69 @@ rem1(PyLongObject *a, digit n)
);
}
+#ifdef WITH_PYLONG_MODULE
+/* asymptotically faster long_to_decimal_string, using _pylong.py */
+static int
+pylong_int_to_decimal_string(PyObject *aa,
+ PyObject **p_output,
+ _PyUnicodeWriter *writer,
+ _PyBytesWriter *bytes_writer,
+ char **bytes_str)
+{
+ PyObject *s = NULL;
+ PyObject *mod = PyImport_ImportModule("_pylong");
+ if (mod == NULL) {
+ return -1;
+ }
+ s = PyObject_CallMethod(mod, "int_to_decimal_string", "O", aa);
+ if (s == NULL) {
+ goto error;
+ }
+ assert(PyUnicode_Check(s));
+ if (writer) {
+ Py_ssize_t size = PyUnicode_GET_LENGTH(s);
+ if (_PyUnicodeWriter_Prepare(writer, size, '9') == -1) {
+ goto error;
+ }
+ if (_PyUnicodeWriter_WriteStr(writer, s) < 0) {
+ goto error;
+ }
+ goto success;
+ }
+ else if (bytes_writer) {
+ Py_ssize_t size = PyUnicode_GET_LENGTH(s);
+ const void *data = PyUnicode_DATA(s);
+ int kind = PyUnicode_KIND(s);
+ *bytes_str = _PyBytesWriter_Prepare(bytes_writer, *bytes_str, size);
+ if (*bytes_str == NULL) {
+ goto error;
+ }
+ char *p = *bytes_str;
+ for (Py_ssize_t i=0; i < size; i++) {
+ Py_UCS4 ch = PyUnicode_READ(kind, data, i);
+ *p++ = (char) ch;
+ }
+ (*bytes_str) = p;
+ goto success;
+ }
+ else {
+ *p_output = (PyObject *)s;
+ Py_INCREF(s);
+ goto success;
+ }
+
+error:
+ Py_DECREF(mod);
+ Py_XDECREF(s);
+ return -1;
+
+success:
+ Py_DECREF(mod);
+ Py_DECREF(s);
+ return 0;
+}
+#endif /* WITH_PYLONG_MODULE */
+
/* Convert an integer to a base 10 string. Returns a new non-shared
string. (Return value is non-shared so that callers can modify the
returned value if necessary.) */
@@ -1776,6 +1842,17 @@ long_to_decimal_string_internal(PyObject *aa,
}
}
+#if WITH_PYLONG_MODULE
+ if (size_a > 1000) {
+ /* Switch to _pylong.int_to_decimal_string(). */
+ return pylong_int_to_decimal_string(aa,
+ p_output,
+ writer,
+ bytes_writer,
+ bytes_str);
+ }
+#endif
+
/* quick and dirty upper bound for the number of digits
required to express a in base _PyLong_DECIMAL_BASE:
@@ -2272,6 +2349,39 @@ long_from_binary_base(const char *start, const char *end, Py_ssize_t digits, int
return 0;
}
+static PyObject *long_neg(PyLongObject *v);
+
+#ifdef WITH_PYLONG_MODULE
+/* asymptotically faster str-to-long conversion for base 10, using _pylong.py */
+static int
+pylong_int_from_string(const char *start, const char *end, PyLongObject **res)
+{
+ PyObject *mod = PyImport_ImportModule("_pylong");
+ if (mod == NULL) {
+ goto error;
+ }
+ PyObject *s = PyUnicode_FromStringAndSize(start, end-start);
+ if (s == NULL) {
+ goto error;
+ }
+ PyObject *result = PyObject_CallMethod(mod, "int_from_string", "O", s);
+ Py_DECREF(s);
+ Py_DECREF(mod);
+ if (result == NULL) {
+ goto error;
+ }
+ if (!PyLong_Check(result)) {
+ PyErr_SetString(PyExc_TypeError, "an integer is required");
+ goto error;
+ }
+ *res = (PyLongObject *)result;
+ return 0;
+error:
+ *res = NULL;
+ return 0;
+}
+#endif /* WITH_PYLONG_MODULE */
+
/***
long_from_non_binary_base: parameters and return values are the same as
long_from_binary_base.
@@ -2586,6 +2696,12 @@ long_from_string_base(const char **str, int base, PyLongObject **res)
return 0;
}
}
+#if WITH_PYLONG_MODULE
+ if (digits > 6000 && base == 10) {
+ /* Switch to _pylong.int_from_string() */
+ return pylong_int_from_string(start, end, res);
+ }
+#endif
/* Use the quadratic algorithm for non binary bases. */
return long_from_non_binary_base(start, end, digits, base, res);
}
@@ -3913,6 +4029,48 @@ fast_floor_div(PyLongObject *a, PyLongObject *b)
return PyLong_FromLong(div);
}
+#ifdef WITH_PYLONG_MODULE
+/* asymptotically faster divmod, using _pylong.py */
+static int
+pylong_int_divmod(PyLongObject *v, PyLongObject *w,
+ PyLongObject **pdiv, PyLongObject **pmod)
+{
+ PyObject *mod = PyImport_ImportModule("_pylong");
+ if (mod == NULL) {
+ return -1;
+ }
+ PyObject *result = PyObject_CallMethod(mod, "int_divmod", "OO", v, w);
+ Py_DECREF(mod);
+ if (result == NULL) {
+ return -1;
+ }
+ if (!PyTuple_Check(result)) {
+ Py_DECREF(result);
+ PyErr_SetString(PyExc_ValueError,
+ "tuple is required from int_divmod()");
+ return -1;
+ }
+ PyObject *q = PyTuple_GET_ITEM(result, 0);
+ PyObject *r = PyTuple_GET_ITEM(result, 1);
+ if (!PyLong_Check(q) || !PyLong_Check(r)) {
+ Py_DECREF(result);
+ PyErr_SetString(PyExc_ValueError,
+ "tuple of int is required from int_divmod()");
+ return -1;
+ }
+ if (pdiv != NULL) {
+ Py_INCREF(q);
+ *pdiv = (PyLongObject *)q;
+ }
+ if (pmod != NULL) {
+ Py_INCREF(r);
+ *pmod = (PyLongObject *)r;
+ }
+ Py_DECREF(result);
+ return 0;
+}
+#endif /* WITH_PYLONG_MODULE */
+
/* The / and % operators are now defined in terms of divmod().
The expression a mod b has the value a - b*floor(a/b).
The long_divrem function gives the remainder after division of
@@ -3964,6 +4122,18 @@ l_divmod(PyLongObject *v, PyLongObject *w,
}
return 0;
}
+#if WITH_PYLONG_MODULE
+ Py_ssize_t size_v = Py_ABS(Py_SIZE(v)); /* digits in numerator */
+ Py_ssize_t size_w = Py_ABS(Py_SIZE(w)); /* digits in denominator */
+ if (size_w > 300 && (size_v - size_w) > 150) {
+ /* Switch to _pylong.int_divmod(). If the quotient is small then
+ "schoolbook" division is linear-time so don't use in that case.
+ These limits are empirically determined and should be slightly
+ conservative so that _pylong is used in cases it is likely
+ to be faster. See Tools/scripts/divmod_threshold.py. */
+ return pylong_int_divmod(v, w, pdiv, pmod);
+ }
+#endif
if (long_divrem(v, w, &div, &mod) < 0)
return -1;
if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) ||