diff options
Diffstat (limited to 'Objects/longobject.c')
| -rw-r--r-- | Objects/longobject.c | 212 | 
1 files changed, 181 insertions, 31 deletions
| diff --git a/Objects/longobject.c b/Objects/longobject.c index d821e4bfb6..70d8cfc6a7 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1582,10 +1582,12 @@ divrem1(PyLongObject *a, digit n, digit *prem)  static int  long_to_decimal_string_internal(PyObject *aa,                                  PyObject **p_output, -                                _PyUnicodeWriter *writer) +                                _PyUnicodeWriter *writer, +                                _PyBytesWriter *bytes_writer, +                                char **bytes_str)  {      PyLongObject *scratch, *a; -    PyObject *str; +    PyObject *str = NULL;      Py_ssize_t size, strlen, size_a, i, j;      digit *pout, *pin, rem, tenpow;      int negative; @@ -1662,7 +1664,13 @@ long_to_decimal_string_internal(PyObject *aa,              return -1;          }          kind = writer->kind; -        str = NULL; +    } +    else if (bytes_writer) { +        *bytes_str = _PyBytesWriter_Prepare(bytes_writer, *bytes_str, strlen); +        if (*bytes_str == NULL) { +            Py_DECREF(scratch); +            return -1; +        }      }      else {          str = PyUnicode_New(strlen, '9'); @@ -1673,13 +1681,8 @@ long_to_decimal_string_internal(PyObject *aa,          kind = PyUnicode_KIND(str);      } -#define WRITE_DIGITS(TYPE)                                            \ +#define WRITE_DIGITS(p)                                               \      do {                                                              \ -        if (writer)                                                   \ -            p = (TYPE*)PyUnicode_DATA(writer->buffer) + writer->pos + strlen; \ -        else                                                          \ -            p = (TYPE*)PyUnicode_DATA(str) + strlen;                  \ -                                                                      \          /* pout[0] through pout[size-2] contribute exactly            \             _PyLong_DECIMAL_SHIFT digits each */                       \          for (i=0; i < size - 1; i++) {                                \ @@ -1699,6 +1702,16 @@ long_to_decimal_string_internal(PyObject *aa,          /* and sign */                                                \          if (negative)                                                 \              *--p = '-';                                               \ +    } while (0) + +#define WRITE_UNICODE_DIGITS(TYPE)                                    \ +    do {                                                              \ +        if (writer)                                                   \ +            p = (TYPE*)PyUnicode_DATA(writer->buffer) + writer->pos + strlen; \ +        else                                                          \ +            p = (TYPE*)PyUnicode_DATA(str) + strlen;                  \ +                                                                      \ +        WRITE_DIGITS(p);                                              \                                                                        \          /* check we've counted correctly */                           \          if (writer)                                                   \ @@ -1708,25 +1721,34 @@ long_to_decimal_string_internal(PyObject *aa,      } while (0)      /* fill the string right-to-left */ -    if (kind == PyUnicode_1BYTE_KIND) { +    if (bytes_writer) { +        char *p = *bytes_str + strlen; +        WRITE_DIGITS(p); +        assert(p == *bytes_str); +    } +    else if (kind == PyUnicode_1BYTE_KIND) {          Py_UCS1 *p; -        WRITE_DIGITS(Py_UCS1); +        WRITE_UNICODE_DIGITS(Py_UCS1);      }      else if (kind == PyUnicode_2BYTE_KIND) {          Py_UCS2 *p; -        WRITE_DIGITS(Py_UCS2); +        WRITE_UNICODE_DIGITS(Py_UCS2);      }      else {          Py_UCS4 *p;          assert (kind == PyUnicode_4BYTE_KIND); -        WRITE_DIGITS(Py_UCS4); +        WRITE_UNICODE_DIGITS(Py_UCS4);      }  #undef WRITE_DIGITS +#undef WRITE_UNICODE_DIGITS      Py_DECREF(scratch);      if (writer) {          writer->pos += strlen;      } +    else if (bytes_writer) { +        (*bytes_str) += strlen; +    }      else {          assert(_PyUnicode_CheckConsistency(str, 1));          *p_output = (PyObject *)str; @@ -1738,7 +1760,7 @@ static PyObject *  long_to_decimal_string(PyObject *aa)  {      PyObject *v; -    if (long_to_decimal_string_internal(aa, &v, NULL) == -1) +    if (long_to_decimal_string_internal(aa, &v, NULL, NULL, NULL) == -1)          return NULL;      return v;  } @@ -1750,10 +1772,11 @@ long_to_decimal_string(PyObject *aa)  static int  long_format_binary(PyObject *aa, int base, int alternate, -                   PyObject **p_output, _PyUnicodeWriter *writer) +                   PyObject **p_output, _PyUnicodeWriter *writer, +                   _PyBytesWriter *bytes_writer, char **bytes_str)  {      PyLongObject *a = (PyLongObject *)aa; -    PyObject *v; +    PyObject *v = NULL;      Py_ssize_t sz;      Py_ssize_t size_a;      enum PyUnicode_Kind kind; @@ -1810,7 +1833,11 @@ long_format_binary(PyObject *aa, int base, int alternate,          if (_PyUnicodeWriter_Prepare(writer, sz, 'x') == -1)              return -1;          kind = writer->kind; -        v = NULL; +    } +    else if (bytes_writer) { +        *bytes_str = _PyBytesWriter_Prepare(bytes_writer, *bytes_str, sz); +        if (*bytes_str == NULL) +            return -1;      }      else {          v = PyUnicode_New(sz, 'x'); @@ -1819,13 +1846,8 @@ long_format_binary(PyObject *aa, int base, int alternate,          kind = PyUnicode_KIND(v);      } -#define WRITE_DIGITS(TYPE)                                              \ +#define WRITE_DIGITS(p)                                                 \      do {                                                                \ -        if (writer)                                                     \ -            p = (TYPE*)PyUnicode_DATA(writer->buffer) + writer->pos + sz; \ -        else                                                            \ -            p = (TYPE*)PyUnicode_DATA(v) + sz;                          \ -                                                                        \          if (size_a == 0) {                                              \              *--p = '0';                                                 \          }                                                               \ @@ -1860,30 +1882,50 @@ long_format_binary(PyObject *aa, int base, int alternate,          }                                                               \          if (negative)                                                   \              *--p = '-';                                                 \ +    } while (0) + +#define WRITE_UNICODE_DIGITS(TYPE)                                      \ +    do {                                                                \ +        if (writer)                                                     \ +            p = (TYPE*)PyUnicode_DATA(writer->buffer) + writer->pos + sz; \ +        else                                                            \ +            p = (TYPE*)PyUnicode_DATA(v) + sz;                          \ +                                                                        \ +        WRITE_DIGITS(p);                                                \ +                                                                        \          if (writer)                                                     \              assert(p == ((TYPE*)PyUnicode_DATA(writer->buffer) + writer->pos)); \          else                                                            \              assert(p == (TYPE*)PyUnicode_DATA(v));                      \      } while (0) -    if (kind == PyUnicode_1BYTE_KIND) { +    if (bytes_writer) { +        char *p = *bytes_str + sz; +        WRITE_DIGITS(p); +        assert(p == *bytes_str); +    } +    else if (kind == PyUnicode_1BYTE_KIND) {          Py_UCS1 *p; -        WRITE_DIGITS(Py_UCS1); +        WRITE_UNICODE_DIGITS(Py_UCS1);      }      else if (kind == PyUnicode_2BYTE_KIND) {          Py_UCS2 *p; -        WRITE_DIGITS(Py_UCS2); +        WRITE_UNICODE_DIGITS(Py_UCS2);      }      else {          Py_UCS4 *p;          assert (kind == PyUnicode_4BYTE_KIND); -        WRITE_DIGITS(Py_UCS4); +        WRITE_UNICODE_DIGITS(Py_UCS4);      }  #undef WRITE_DIGITS +#undef WRITE_UNICODE_DIGITS      if (writer) {          writer->pos += sz;      } +    else if (bytes_writer) { +        (*bytes_str) += sz; +    }      else {          assert(_PyUnicode_CheckConsistency(v, 1));          *p_output = v; @@ -1897,9 +1939,9 @@ _PyLong_Format(PyObject *obj, int base)      PyObject *str;      int err;      if (base == 10) -        err = long_to_decimal_string_internal(obj, &str, NULL); +        err = long_to_decimal_string_internal(obj, &str, NULL, NULL, NULL);      else -        err = long_format_binary(obj, base, 1, &str, NULL); +        err = long_format_binary(obj, base, 1, &str, NULL, NULL, NULL);      if (err == -1)          return NULL;      return str; @@ -1911,9 +1953,31 @@ _PyLong_FormatWriter(_PyUnicodeWriter *writer,                       int base, int alternate)  {      if (base == 10) -        return long_to_decimal_string_internal(obj, NULL, writer); +        return long_to_decimal_string_internal(obj, NULL, writer, +                                               NULL, NULL); +    else +        return long_format_binary(obj, base, alternate, NULL, writer, +                                  NULL, NULL); +} + +char* +_PyLong_FormatBytesWriter(_PyBytesWriter *writer, char *str, +                          PyObject *obj, +                          int base, int alternate) +{ +    char *str2; +    int res; +    str2 = str; +    if (base == 10) +        res = long_to_decimal_string_internal(obj, NULL, NULL, +                                              writer, &str2);      else -        return long_format_binary(obj, base, alternate, NULL, writer); +        res = long_format_binary(obj, base, alternate, NULL, NULL, +                                 writer, &str2); +    if (res < 0) +        return NULL; +    assert(str2 != NULL); +    return str2;  }  /* Table of digit values for 8-bit string -> integer conversion. @@ -2705,6 +2769,13 @@ PyLong_AsDouble(PyObject *v)          PyErr_SetString(PyExc_TypeError, "an integer is required");          return -1.0;      } +    if (Py_ABS(Py_SIZE(v)) <= 1) { +        /* Fast path; single digit long (31 bits) will cast safely +	   to double.  This improves performance of FP/long operations +	   by 20%. +        */ +        return (double)MEDIUM_VALUE((PyLongObject *)v); +    }      x = _PyLong_Frexp((PyLongObject *)v, &exponent);      if ((x == -1.0 && PyErr_Occurred()) || exponent > DBL_MAX_EXP) {          PyErr_SetString(PyExc_OverflowError, @@ -3431,6 +3502,52 @@ long_mul(PyLongObject *a, PyLongObject *b)      return (PyObject *)z;  } +/* Fast modulo division for single-digit longs. */ +static PyObject * +fast_mod(PyLongObject *a, PyLongObject *b) +{ +    sdigit left = a->ob_digit[0]; +    sdigit right = b->ob_digit[0]; +    sdigit mod; + +    assert(Py_ABS(Py_SIZE(a)) == 1); +    assert(Py_ABS(Py_SIZE(b)) == 1); + +    if (Py_SIZE(a) == Py_SIZE(b)) { +        /* 'a' and 'b' have the same sign. */ +        mod = left % right; +    } +    else { +        /* Either 'a' or 'b' is negative. */ +        mod = right - 1 - (left - 1) % right; +    } + +    return PyLong_FromLong(mod * (sdigit)Py_SIZE(b)); +} + +/* Fast floor division for single-digit longs. */ +static PyObject * +fast_floor_div(PyLongObject *a, PyLongObject *b) +{ +    sdigit left = a->ob_digit[0]; +    sdigit right = b->ob_digit[0]; +    sdigit div; + +    assert(Py_ABS(Py_SIZE(a)) == 1); +    assert(Py_ABS(Py_SIZE(b)) == 1); + +    if (Py_SIZE(a) == Py_SIZE(b)) { +        /* 'a' and 'b' have the same sign. */ +        div = left / right; +    } +    else { +        /* Either 'a' or 'b' is negative. */ +        div = -1 - (left - 1) / right; +    } + +    return PyLong_FromLong(div); +} +  /* 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 @@ -3458,6 +3575,30 @@ l_divmod(PyLongObject *v, PyLongObject *w,  {      PyLongObject *div, *mod; +    if (Py_ABS(Py_SIZE(v)) == 1 && Py_ABS(Py_SIZE(w)) == 1) { +        /* Fast path for single-digit longs */ +        div = NULL; +        if (pdiv != NULL) { +            div = (PyLongObject *)fast_floor_div(v, w); +            if (div == NULL) { +                return -1; +            } +        } +        if (pmod != NULL) { +            mod = (PyLongObject *)fast_mod(v, w); +            if (mod == NULL) { +                Py_XDECREF(div); +                return -1; +            } +            *pmod = mod; +        } +        if (pdiv != NULL) { +            /* We only want to set `*pdiv` when `*pmod` is +               set successfully. */ +            *pdiv = div; +        } +        return 0; +    }      if (long_divrem(v, w, &div, &mod) < 0)          return -1;      if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || @@ -3502,6 +3643,11 @@ long_div(PyObject *a, PyObject *b)      PyLongObject *div;      CHECK_BINOP(a, b); + +    if (Py_ABS(Py_SIZE(a)) == 1 && Py_ABS(Py_SIZE(b)) == 1) { +        return fast_floor_div((PyLongObject*)a, (PyLongObject*)b); +    } +      if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, NULL) < 0)          div = NULL;      return (PyObject *)div; @@ -3777,6 +3923,10 @@ long_mod(PyObject *a, PyObject *b)      CHECK_BINOP(a, b); +    if (Py_ABS(Py_SIZE(a)) == 1 && Py_ABS(Py_SIZE(b)) == 1) { +        return fast_mod((PyLongObject*)a, (PyLongObject*)b); +    } +      if (l_divmod((PyLongObject*)a, (PyLongObject*)b, NULL, &mod) < 0)          mod = NULL;      return (PyObject *)mod; | 
