[Python-checkins] r54212 - sandbox/trunk/pep3101/unicodeformat.c
eric.smith
python-checkins at python.org
Wed Mar 7 23:07:13 CET 2007
Author: eric.smith
Date: Wed Mar 7 23:07:08 2007
New Revision: 54212
Modified:
sandbox/trunk/pep3101/unicodeformat.c
Log:
Removed longintrepr.h. I no longer look at PyLong internals; instead everything works through functions exported by PyLong, although some begin with underscores like _PyLong_Sign(). The only code this affected is the base 2 output for longs in _format_long_binary().
Modified: sandbox/trunk/pep3101/unicodeformat.c
==============================================================================
--- sandbox/trunk/pep3101/unicodeformat.c (original)
+++ sandbox/trunk/pep3101/unicodeformat.c Wed Mar 7 23:07:08 2007
@@ -20,9 +20,6 @@
#define C_UNICODE 1
#endif
-/* we need access to a PyLongObject's internals */
-#include "longintrepr.h"
-
#if C_UNICODE
#define CH_TYPE Py_UNICODE
#define CH_TYPE_ISDECIMAL Py_UNICODE_ISDECIMAL
@@ -1115,21 +1112,33 @@
return p_digits;
}
+/* call _PyLong_AsByteArray to get the bytes, then do the formatting.
+ note that for negative numbers, the byte array will be two's
+ complement, and we need to undo that. */
static int
-_format_long_binary(PyObject *v, FmtState *fs, const InternalFormatSpec *format)
-{
- /* we know that v is a PyLongObject */
+_format_long_binary(PyObject *v, FmtState *fs, const
+InternalFormatSpec *format) { /* we know that v is a PyLongObject */
PyLongObject* l = (PyLongObject*)v;
IntegerFieldWidths spec;
CH_TYPE *pbuf;
CH_TYPE *start;
- char sign = _PyLong_Sign(v) >= 0 ? '\0' : '-';
+
+ size_t bytes_required;
+ int is_negative = _PyLong_Sign(v) < 0;
+ unsigned char* byte_buffer;
+ unsigned char* start_byte_buffer;
+ char sign = is_negative ? '-' : '\0';
Py_ssize_t n_digits = _PyLong_NumBits(v);
- Py_ssize_t i;
+ int is_zero = n_digits == 0;
+ int carry_bit;
- /* special case for zero */
- if (l->ob_size == 0)
+ /* check for error getting number of bits */
+ if (n_digits < 0)
+ return 0;
+
+ /* special case for zero. it takes one digit, despite having zero bits */
+ if (is_zero)
n_digits = 1;
_calc_integer_widths(&spec, sign, n_digits, format);
@@ -1143,24 +1152,71 @@
format->fill_char == '\0' ? ' ' : format->fill_char);
/* degenerate case for zero. handle it and get out */
- if (l->ob_size == 0) {
+ if (is_zero) {
*pbuf = '0';
return 1;
}
- /* finally, fill in the digits, starting at the right and working left */
+ /* copy the bytes into the output buffer. we know they'll fit,
+ because we have enough space for a textual representation */
+
+ /* how many bytes this long will require. we allocate on extra
+ bit (by not subtracting 1 from the number of bits) because the
+ sign bit might be needed */
+ bytes_required = n_digits / 8 + 1;
+ byte_buffer = (unsigned char*)start; /* where to put the bytes */
+ start_byte_buffer = byte_buffer;
+ /* use little endian so we can start at the lsb and overwrite as we
+ go higher */
+ if (_PyLong_AsByteArray(l, byte_buffer, bytes_required, 0, 1) < 0)
+ return 0;
+
+ /* adjust byte_buffer to point to the end of the string of digits */
+ byte_buffer += bytes_required - 1;
+ /* and adjust the output pointer to point to the end of the
+ CH_TYPE output buffer */
pbuf = start + n_digits - 1;
- for (i = 0; i < ABS(l->ob_size); i++) {
- Py_ssize_t j;
- digit d = l->ob_digit[i];
- for (j = 0; j < SHIFT; j++, d >>= 1) {
- if (d & 1)
+ carry_bit = 1; /* two's complement setup */
+
+ /* finally, fill in the digits, starting at the right and working
+ left */
+ while (1) {
+ int j;
+ unsigned char byte = *byte_buffer;
+
+ /* this test is just trying to make sure we don't go past the
+ beginning of the byte buffer. IIRC, it's illegal to
+ decrement a pointer past the beginning of what it points
+ to. not that it probably matters, but let's be as
+ conformant as possible */
+ if (byte_buffer != start_byte_buffer)
+ byte_buffer--;
+
+ /* two's complement algorithm */
+ if (is_negative) {
+ byte = ~byte;
+ if (byte == 0xff && carry_bit) {
+ /* this is the only case where the carry bit will be
+ set */
+ byte = 0;
+ carry_bit = 1;
+ } else {
+ /* we know adding won't overflow */
+ byte += carry_bit;
+ carry_bit = 0;
+ }
+ }
+
+ /* loop over each bit. this could be sped up with a table
+ lookup, but the mid-byte termination makes it complex */
+ for (j = 0; j < 8; j++, byte >>= 1) {
+ if (byte & 1)
*pbuf = '1';
else
*pbuf = '0';
- /* see if we're done mid-digit */
+ /* see if we're done mid-byte */
if (pbuf == start)
goto DONE;
pbuf--;
More information about the Python-checkins
mailing list