diff options
author | Benjamin Peterson <benjamin@python.org> | 2014-03-30 19:52:22 -0400 |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2014-03-30 19:52:22 -0400 |
commit | 659ab1072a32c2e4ae1031cf29b18ba9adf7d2a8 (patch) | |
tree | 9052e39ad80e68449997f391e55b0fe96a25da62 /Objects/stringlib | |
parent | 07bbf159738fc0946c5e2f9cf7c281705c3a78b4 (diff) | |
parent | 8af714360dd2c85eb0f2ef7c653e2f7351fee129 (diff) | |
download | cpython-659ab1072a32c2e4ae1031cf29b18ba9adf7d2a8.tar.gz |
merge 3.2
Diffstat (limited to 'Objects/stringlib')
-rw-r--r-- | Objects/stringlib/asciilib.h | 30 | ||||
-rw-r--r-- | Objects/stringlib/codecs.h | 661 | ||||
-rw-r--r-- | Objects/stringlib/count.h | 9 | ||||
-rw-r--r-- | Objects/stringlib/eq.h | 16 | ||||
-rw-r--r-- | Objects/stringlib/fastsearch.h | 70 | ||||
-rw-r--r-- | Objects/stringlib/find.h | 89 | ||||
-rw-r--r-- | Objects/stringlib/find_max_char.h | 133 | ||||
-rw-r--r-- | Objects/stringlib/formatter.h | 1516 | ||||
-rw-r--r-- | Objects/stringlib/localeutil.h | 100 | ||||
-rw-r--r-- | Objects/stringlib/partition.h | 12 | ||||
-rw-r--r-- | Objects/stringlib/split.h | 26 | ||||
-rw-r--r-- | Objects/stringlib/stringdefs.h | 8 | ||||
-rw-r--r-- | Objects/stringlib/transmogrify.h | 10 | ||||
-rw-r--r-- | Objects/stringlib/ucs1lib.h | 31 | ||||
-rw-r--r-- | Objects/stringlib/ucs2lib.h | 30 | ||||
-rw-r--r-- | Objects/stringlib/ucs4lib.h | 30 | ||||
-rw-r--r-- | Objects/stringlib/undef.h | 12 | ||||
-rw-r--r-- | Objects/stringlib/unicode_format.h (renamed from Objects/stringlib/string_format.h) | 447 | ||||
-rw-r--r-- | Objects/stringlib/unicodedefs.h | 8 |
19 files changed, 1316 insertions, 1922 deletions
diff --git a/Objects/stringlib/asciilib.h b/Objects/stringlib/asciilib.h new file mode 100644 index 0000000000..f62813d2fd --- /dev/null +++ b/Objects/stringlib/asciilib.h @@ -0,0 +1,30 @@ +/* this is sort of a hack. there's at least one place (formatting + floats) where some stringlib code takes a different path if it's + compiled as unicode. */ +#define STRINGLIB_IS_UNICODE 1 + +#define FASTSEARCH asciilib_fastsearch +#define STRINGLIB(F) asciilib_##F +#define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_SIZEOF_CHAR 1 +#define STRINGLIB_MAX_CHAR 0x7Fu +#define STRINGLIB_CHAR Py_UCS1 +#define STRINGLIB_TYPE_NAME "unicode" +#define STRINGLIB_PARSE_CODE "U" +#define STRINGLIB_EMPTY unicode_empty +#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE +#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK +#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL +#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL +#define STRINGLIB_STR PyUnicode_1BYTE_DATA +#define STRINGLIB_LEN PyUnicode_GET_LENGTH +#define STRINGLIB_NEW(STR,LEN) _PyUnicode_FromASCII((char*)(STR),(LEN)) +#define STRINGLIB_RESIZE not_supported +#define STRINGLIB_CHECK PyUnicode_Check +#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact + +#define STRINGLIB_TOSTR PyObject_Str +#define STRINGLIB_TOASCII PyObject_ASCII + +#define _Py_InsertThousandsGrouping _PyUnicode_ascii_InsertThousandsGrouping + diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h new file mode 100644 index 0000000000..f353367013 --- /dev/null +++ b/Objects/stringlib/codecs.h @@ -0,0 +1,661 @@ +/* stringlib: codec implementations */ + +#if STRINGLIB_IS_UNICODE + +/* Mask to quickly check whether a C 'long' contains a + non-ASCII, UTF8-encoded char. */ +#if (SIZEOF_LONG == 8) +# define ASCII_CHAR_MASK 0x8080808080808080UL +#elif (SIZEOF_LONG == 4) +# define ASCII_CHAR_MASK 0x80808080UL +#else +# error C 'long' size should be either 4 or 8! +#endif + +/* 10xxxxxx */ +#define IS_CONTINUATION_BYTE(ch) ((ch) >= 0x80 && (ch) < 0xC0) + +Py_LOCAL_INLINE(Py_UCS4) +STRINGLIB(utf8_decode)(const char **inptr, const char *end, + STRINGLIB_CHAR *dest, + Py_ssize_t *outpos) +{ + Py_UCS4 ch; + const char *s = *inptr; + const char *aligned_end = (const char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); + STRINGLIB_CHAR *p = dest + *outpos; + + while (s < end) { + ch = (unsigned char)*s; + + if (ch < 0x80) { + /* Fast path for runs of ASCII characters. Given that common UTF-8 + input will consist of an overwhelming majority of ASCII + characters, we try to optimize for this case by checking + as many characters as a C 'long' can contain. + First, check if we can do an aligned read, as most CPUs have + a penalty for unaligned reads. + */ + if (_Py_IS_ALIGNED(s, SIZEOF_LONG)) { + /* Help register allocation */ + register const char *_s = s; + register STRINGLIB_CHAR *_p = p; + while (_s < aligned_end) { + /* Read a whole long at a time (either 4 or 8 bytes), + and do a fast unrolled copy if it only contains ASCII + characters. */ + unsigned long value = *(unsigned long *) _s; + if (value & ASCII_CHAR_MASK) + break; +#ifdef BYTEORDER_IS_LITTLE_ENDIAN + _p[0] = (STRINGLIB_CHAR)(value & 0xFFu); + _p[1] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu); + _p[2] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu); + _p[3] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu); +# if SIZEOF_LONG == 8 + _p[4] = (STRINGLIB_CHAR)((value >> 32) & 0xFFu); + _p[5] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu); + _p[6] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu); + _p[7] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu); +# endif +#else +# if SIZEOF_LONG == 8 + _p[0] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu); + _p[1] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu); + _p[2] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu); + _p[3] = (STRINGLIB_CHAR)((value >> 32) & 0xFFu); + _p[4] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu); + _p[5] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu); + _p[6] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu); + _p[7] = (STRINGLIB_CHAR)(value & 0xFFu); +# else + _p[0] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu); + _p[1] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu); + _p[2] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu); + _p[3] = (STRINGLIB_CHAR)(value & 0xFFu); +# endif +#endif + _s += SIZEOF_LONG; + _p += SIZEOF_LONG; + } + s = _s; + p = _p; + if (s == end) + break; + ch = (unsigned char)*s; + } + if (ch < 0x80) { + s++; + *p++ = ch; + continue; + } + } + + if (ch < 0xE0) { + /* \xC2\x80-\xDF\xBF -- 0080-07FF */ + Py_UCS4 ch2; + if (ch < 0xC2) { + /* invalid sequence + \x80-\xBF -- continuation byte + \xC0-\xC1 -- fake 0000-007F */ + goto InvalidStart; + } + if (end - s < 2) { + /* unexpected end of data: the caller will decide whether + it's an error or not */ + break; + } + ch2 = (unsigned char)s[1]; + if (!IS_CONTINUATION_BYTE(ch2)) + /* invalid continuation byte */ + goto InvalidContinuation1; + ch = (ch << 6) + ch2 - + ((0xC0 << 6) + 0x80); + assert ((ch > 0x007F) && (ch <= 0x07FF)); + s += 2; + if (STRINGLIB_MAX_CHAR <= 0x007F || + (STRINGLIB_MAX_CHAR < 0x07FF && ch > STRINGLIB_MAX_CHAR)) + /* Out-of-range */ + goto Return; + *p++ = ch; + continue; + } + + if (ch < 0xF0) { + /* \xE0\xA0\x80-\xEF\xBF\xBF -- 0800-FFFF */ + Py_UCS4 ch2, ch3; + if (end - s < 3) { + /* unexpected end of data: the caller will decide whether + it's an error or not */ + if (end - s < 2) + break; + ch2 = (unsigned char)s[1]; + if (!IS_CONTINUATION_BYTE(ch2) || + (ch2 < 0xA0 ? ch == 0xE0 : ch == 0xED)) + /* for clarification see comments below */ + goto InvalidContinuation1; + break; + } + ch2 = (unsigned char)s[1]; + ch3 = (unsigned char)s[2]; + if (!IS_CONTINUATION_BYTE(ch2)) { + /* invalid continuation byte */ + goto InvalidContinuation1; + } + if (ch == 0xE0) { + if (ch2 < 0xA0) + /* invalid sequence + \xE0\x80\x80-\xE0\x9F\xBF -- fake 0000-0800 */ + goto InvalidContinuation1; + } else if (ch == 0xED && ch2 >= 0xA0) { + /* Decoding UTF-8 sequences in range \xED\xA0\x80-\xED\xBF\xBF + will result in surrogates in range D800-DFFF. Surrogates are + not valid UTF-8 so they are rejected. + See http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf + (table 3-7) and http://www.rfc-editor.org/rfc/rfc3629.txt */ + goto InvalidContinuation1; + } + if (!IS_CONTINUATION_BYTE(ch3)) { + /* invalid continuation byte */ + goto InvalidContinuation2; + } + ch = (ch << 12) + (ch2 << 6) + ch3 - + ((0xE0 << 12) + (0x80 << 6) + 0x80); + assert ((ch > 0x07FF) && (ch <= 0xFFFF)); + s += 3; + if (STRINGLIB_MAX_CHAR <= 0x07FF || + (STRINGLIB_MAX_CHAR < 0xFFFF && ch > STRINGLIB_MAX_CHAR)) + /* Out-of-range */ + goto Return; + *p++ = ch; + continue; + } + + if (ch < 0xF5) { + /* \xF0\x90\x80\x80-\xF4\x8F\xBF\xBF -- 10000-10FFFF */ + Py_UCS4 ch2, ch3, ch4; + if (end - s < 4) { + /* unexpected end of data: the caller will decide whether + it's an error or not */ + if (end - s < 2) + break; + ch2 = (unsigned char)s[1]; + if (!IS_CONTINUATION_BYTE(ch2) || + (ch2 < 0x90 ? ch == 0xF0 : ch == 0xF4)) + /* for clarification see comments below */ + goto InvalidContinuation1; + if (end - s < 3) + break; + ch3 = (unsigned char)s[2]; + if (!IS_CONTINUATION_BYTE(ch3)) + goto InvalidContinuation2; + break; + } + ch2 = (unsigned char)s[1]; + ch3 = (unsigned char)s[2]; + ch4 = (unsigned char)s[3]; + if (!IS_CONTINUATION_BYTE(ch2)) { + /* invalid continuation byte */ + goto InvalidContinuation1; + } + if (ch == 0xF0) { + if (ch2 < 0x90) + /* invalid sequence + \xF0\x80\x80\x80-\xF0\x8F\xBF\xBF -- fake 0000-FFFF */ + goto InvalidContinuation1; + } else if (ch == 0xF4 && ch2 >= 0x90) { + /* invalid sequence + \xF4\x90\x80\80- -- 110000- overflow */ + goto InvalidContinuation1; + } + if (!IS_CONTINUATION_BYTE(ch3)) { + /* invalid continuation byte */ + goto InvalidContinuation2; + } + if (!IS_CONTINUATION_BYTE(ch4)) { + /* invalid continuation byte */ + goto InvalidContinuation3; + } + ch = (ch << 18) + (ch2 << 12) + (ch3 << 6) + ch4 - + ((0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80); + assert ((ch > 0xFFFF) && (ch <= 0x10FFFF)); + s += 4; + if (STRINGLIB_MAX_CHAR <= 0xFFFF || + (STRINGLIB_MAX_CHAR < 0x10FFFF && ch > STRINGLIB_MAX_CHAR)) + /* Out-of-range */ + goto Return; + *p++ = ch; + continue; + } + goto InvalidStart; + } + ch = 0; +Return: + *inptr = s; + *outpos = p - dest; + return ch; +InvalidStart: + ch = 1; + goto Return; +InvalidContinuation1: + ch = 2; + goto Return; +InvalidContinuation2: + ch = 3; + goto Return; +InvalidContinuation3: + ch = 4; + goto Return; +} + +#undef ASCII_CHAR_MASK + + +/* UTF-8 encoder specialized for a Unicode kind to avoid the slow + PyUnicode_READ() macro. Delete some parts of the code depending on the kind: + UCS-1 strings don't need to handle surrogates for example. */ +Py_LOCAL_INLINE(PyObject *) +STRINGLIB(utf8_encoder)(PyObject *unicode, + STRINGLIB_CHAR *data, + Py_ssize_t size, + const char *errors) +{ +#define MAX_SHORT_UNICHARS 300 /* largest size we'll do on the stack */ + + Py_ssize_t i; /* index into s of next input byte */ + PyObject *result; /* result string object */ + char *p; /* next free byte in output buffer */ + Py_ssize_t nallocated; /* number of result bytes allocated */ + Py_ssize_t nneeded; /* number of result bytes needed */ +#if STRINGLIB_SIZEOF_CHAR > 1 + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + PyObject *rep = NULL; +#endif +#if STRINGLIB_SIZEOF_CHAR == 1 + const Py_ssize_t max_char_size = 2; + char stackbuf[MAX_SHORT_UNICHARS * 2]; +#elif STRINGLIB_SIZEOF_CHAR == 2 + const Py_ssize_t max_char_size = 3; + char stackbuf[MAX_SHORT_UNICHARS * 3]; +#else /* STRINGLIB_SIZEOF_CHAR == 4 */ + const Py_ssize_t max_char_size = 4; + char stackbuf[MAX_SHORT_UNICHARS * 4]; +#endif + + assert(size >= 0); + + if (size <= MAX_SHORT_UNICHARS) { + /* Write into the stack buffer; nallocated can't overflow. + * At the end, we'll allocate exactly as much heap space as it + * turns out we need. + */ + nallocated = Py_SAFE_DOWNCAST(sizeof(stackbuf), size_t, int); + result = NULL; /* will allocate after we're done */ + p = stackbuf; + } + else { + if (size > PY_SSIZE_T_MAX / max_char_size) { + /* integer overflow */ + return PyErr_NoMemory(); + } + /* Overallocate on the heap, and give the excess back at the end. */ + nallocated = size * max_char_size; + result = PyBytes_FromStringAndSize(NULL, nallocated); + if (result == NULL) + return NULL; + p = PyBytes_AS_STRING(result); + } + + for (i = 0; i < size;) { + Py_UCS4 ch = data[i++]; + + if (ch < 0x80) { + /* Encode ASCII */ + *p++ = (char) ch; + + } + else +#if STRINGLIB_SIZEOF_CHAR > 1 + if (ch < 0x0800) +#endif + { + /* Encode Latin-1 */ + *p++ = (char)(0xc0 | (ch >> 6)); + *p++ = (char)(0x80 | (ch & 0x3f)); + } +#if STRINGLIB_SIZEOF_CHAR > 1 + else if (Py_UNICODE_IS_SURROGATE(ch)) { + Py_ssize_t newpos; + Py_ssize_t repsize, k, startpos; + startpos = i-1; + rep = unicode_encode_call_errorhandler( + errors, &errorHandler, "utf-8", "surrogates not allowed", + unicode, &exc, startpos, startpos+1, &newpos); + if (!rep) + goto error; + + if (PyBytes_Check(rep)) + repsize = PyBytes_GET_SIZE(rep); + else + repsize = PyUnicode_GET_LENGTH(rep); + + if (repsize > max_char_size) { + Py_ssize_t offset; + + if (result == NULL) + offset = p - stackbuf; + else + offset = p - PyBytes_AS_STRING(result); + + if (nallocated > PY_SSIZE_T_MAX - repsize + max_char_size) { + /* integer overflow */ + PyErr_NoMemory(); + goto error; + } + nallocated += repsize - max_char_size; + if (result != NULL) { + if (_PyBytes_Resize(&result, nallocated) < 0) + goto error; + } else { + result = PyBytes_FromStringAndSize(NULL, nallocated); + if (result == NULL) + goto error; + Py_MEMCPY(PyBytes_AS_STRING(result), stackbuf, offset); + } + p = PyBytes_AS_STRING(result) + offset; + } + + if (PyBytes_Check(rep)) { + char *prep = PyBytes_AS_STRING(rep); + for(k = repsize; k > 0; k--) + *p++ = *prep++; + } else /* rep is unicode */ { + enum PyUnicode_Kind repkind; + void *repdata; + + if (PyUnicode_READY(rep) < 0) + goto error; + repkind = PyUnicode_KIND(rep); + repdata = PyUnicode_DATA(rep); + + for(k=0; k<repsize; k++) { + Py_UCS4 c = PyUnicode_READ(repkind, repdata, k); + if (0x80 <= c) { + raise_encode_exception(&exc, "utf-8", + unicode, + i-1, i, + "surrogates not allowed"); + goto error; + } + *p++ = (char)c; + } + } + Py_CLEAR(rep); + } + else +#if STRINGLIB_SIZEOF_CHAR > 2 + if (ch < 0x10000) +#endif + { + *p++ = (char)(0xe0 | (ch >> 12)); + *p++ = (char)(0x80 | ((ch >> 6) & 0x3f)); + *p++ = (char)(0x80 | (ch & 0x3f)); + } +#if STRINGLIB_SIZEOF_CHAR > 2 + else /* ch >= 0x10000 */ + { + assert(ch <= MAX_UNICODE); + /* Encode UCS4 Unicode ordinals */ + *p++ = (char)(0xf0 | (ch >> 18)); + *p++ = (char)(0x80 | ((ch >> 12) & 0x3f)); + *p++ = (char)(0x80 | ((ch >> 6) & 0x3f)); + *p++ = (char)(0x80 | (ch & 0x3f)); + } +#endif /* STRINGLIB_SIZEOF_CHAR > 2 */ +#endif /* STRINGLIB_SIZEOF_CHAR > 1 */ + } + + if (result == NULL) { + /* This was stack allocated. */ + nneeded = p - stackbuf; + assert(nneeded <= nallocated); + result = PyBytes_FromStringAndSize(stackbuf, nneeded); + } + else { + /* Cut back to size actually needed. */ + nneeded = p - PyBytes_AS_STRING(result); + assert(nneeded <= nallocated); + _PyBytes_Resize(&result, nneeded); + } + +#if STRINGLIB_SIZEOF_CHAR > 1 + Py_XDECREF(errorHandler); + Py_XDECREF(exc); +#endif + return result; + +#if STRINGLIB_SIZEOF_CHAR > 1 + error: + Py_XDECREF(rep); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + Py_XDECREF(result); + return NULL; +#endif + +#undef MAX_SHORT_UNICHARS +} + +/* The pattern for constructing UCS2-repeated masks. */ +#if SIZEOF_LONG == 8 +# define UCS2_REPEAT_MASK 0x0001000100010001ul +#elif SIZEOF_LONG == 4 +# define UCS2_REPEAT_MASK 0x00010001ul +#else +# error C 'long' size should be either 4 or 8! +#endif + +/* The mask for fast checking. */ +#if STRINGLIB_SIZEOF_CHAR == 1 +/* The mask for fast checking of whether a C 'long' contains a + non-ASCII or non-Latin1 UTF16-encoded characters. */ +# define FAST_CHAR_MASK (UCS2_REPEAT_MASK * (0xFFFFu & ~STRINGLIB_MAX_CHAR)) +#else +/* The mask for fast checking of whether a C 'long' may contain + UTF16-encoded surrogate characters. This is an efficient heuristic, + assuming that non-surrogate characters with a code point >= 0x8000 are + rare in most input. +*/ +# define FAST_CHAR_MASK (UCS2_REPEAT_MASK * 0x8000u) +#endif +/* The mask for fast byte-swapping. */ +#define STRIPPED_MASK (UCS2_REPEAT_MASK * 0x00FFu) +/* Swap bytes. */ +#define SWAB(value) ((((value) >> 8) & STRIPPED_MASK) | \ + (((value) & STRIPPED_MASK) << 8)) + +Py_LOCAL_INLINE(Py_UCS4) +STRINGLIB(utf16_decode)(const unsigned char **inptr, const unsigned char *e, + STRINGLIB_CHAR *dest, Py_ssize_t *outpos, + int native_ordering) +{ + Py_UCS4 ch; + const unsigned char *aligned_end = + (const unsigned char *) _Py_ALIGN_DOWN(e, SIZEOF_LONG); + const unsigned char *q = *inptr; + STRINGLIB_CHAR *p = dest + *outpos; + /* Offsets from q for retrieving byte pairs in the right order. */ +#ifdef BYTEORDER_IS_LITTLE_ENDIAN + int ihi = !!native_ordering, ilo = !native_ordering; +#else + int ihi = !native_ordering, ilo = !!native_ordering; +#endif + --e; + + while (q < e) { + Py_UCS4 ch2; + /* First check for possible aligned read of a C 'long'. Unaligned + reads are more expensive, better to defer to another iteration. */ + if (_Py_IS_ALIGNED(q, SIZEOF_LONG)) { + /* Fast path for runs of in-range non-surrogate chars. */ + register const unsigned char *_q = q; + while (_q < aligned_end) { + unsigned long block = * (unsigned long *) _q; + if (native_ordering) { + /* Can use buffer directly */ + if (block & FAST_CHAR_MASK) + break; + } + else { + /* Need to byte-swap */ + if (block & SWAB(FAST_CHAR_MASK)) + break; +#if STRINGLIB_SIZEOF_CHAR == 1 + block >>= 8; +#else + block = SWAB(block); +#endif + } +#ifdef BYTEORDER_IS_LITTLE_ENDIAN +# if SIZEOF_LONG == 4 + p[0] = (STRINGLIB_CHAR)(block & 0xFFFFu); + p[1] = (STRINGLIB_CHAR)(block >> 16); +# elif SIZEOF_LONG == 8 + p[0] = (STRINGLIB_CHAR)(block & 0xFFFFu); + p[1] = (STRINGLIB_CHAR)((block >> 16) & 0xFFFFu); + p[2] = (STRINGLIB_CHAR)((block >> 32) & 0xFFFFu); + p[3] = (STRINGLIB_CHAR)(block >> 48); +# endif +#else +# if SIZEOF_LONG == 4 + p[0] = (STRINGLIB_CHAR)(block >> 16); + p[1] = (STRINGLIB_CHAR)(block & 0xFFFFu); +# elif SIZEOF_LONG == 8 + p[0] = (STRINGLIB_CHAR)(block >> 48); + p[1] = (STRINGLIB_CHAR)((block >> 32) & 0xFFFFu); + p[2] = (STRINGLIB_CHAR)((block >> 16) & 0xFFFFu); + p[3] = (STRINGLIB_CHAR)(block & 0xFFFFu); +# endif +#endif + _q += SIZEOF_LONG; + p += SIZEOF_LONG / 2; + } + q = _q; + if (q >= e) + break; + } + + ch = (q[ihi] << 8) | q[ilo]; + q += 2; + if (!Py_UNICODE_IS_SURROGATE(ch)) { +#if STRINGLIB_SIZEOF_CHAR < 2 + if (ch > STRINGLIB_MAX_CHAR) + /* Out-of-range */ + goto Return; +#endif + *p++ = (STRINGLIB_CHAR)ch; + continue; + } + + /* UTF-16 code pair: */ + if (q >= e) + goto UnexpectedEnd; + if (!Py_UNICODE_IS_HIGH_SURROGATE(ch)) + goto IllegalEncoding; + ch2 = (q[ihi] << 8) | q[ilo]; + q += 2; + if (!Py_UNICODE_IS_LOW_SURROGATE(ch2)) + goto IllegalSurrogate; + ch = Py_UNICODE_JOIN_SURROGATES(ch, ch2); +#if STRINGLIB_SIZEOF_CHAR < 4 + /* Out-of-range */ + goto Return; +#else + *p++ = (STRINGLIB_CHAR)ch; +#endif + } + ch = 0; +Return: + *inptr = q; + *outpos = p - dest; + return ch; +UnexpectedEnd: + ch = 1; + goto Return; +IllegalEncoding: + ch = 2; + goto Return; +IllegalSurrogate: + ch = 3; + goto Return; +} +#undef UCS2_REPEAT_MASK +#undef FAST_CHAR_MASK +#undef STRIPPED_MASK +#undef SWAB + + +Py_LOCAL_INLINE(void) +STRINGLIB(utf16_encode)(unsigned short *out, + const STRINGLIB_CHAR *in, + Py_ssize_t len, + int native_ordering) +{ + const STRINGLIB_CHAR *end = in + len; +#if STRINGLIB_SIZEOF_CHAR == 1 +# define SWAB2(CH) ((CH) << 8) +#else +# define SWAB2(CH) (((CH) << 8) | ((CH) >> 8)) +#endif +#if STRINGLIB_MAX_CHAR < 0x10000 + if (native_ordering) { +# if STRINGLIB_SIZEOF_CHAR == 2 + Py_MEMCPY(out, in, 2 * len); +# else + _PyUnicode_CONVERT_BYTES(STRINGLIB_CHAR, unsigned short, in, end, out); +# endif + } else { + const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4); + while (in < unrolled_end) { + out[0] = SWAB2(in[0]); + out[1] = SWAB2(in[1]); + out[2] = SWAB2(in[2]); + out[3] = SWAB2(in[3]); + in += 4; out += 4; + } + while (in < end) { + *out++ = SWAB2(*in); + ++in; + } + } +#else + if (native_ordering) { + while (in < end) { + Py_UCS4 ch = *in++; + if (ch < 0x10000) + *out++ = ch; + else { + out[0] = Py_UNICODE_HIGH_SURROGATE(ch); + out[1] = Py_UNICODE_LOW_SURROGATE(ch); + out += 2; + } + } + } else { + while (in < end) { + Py_UCS4 ch = *in++; + if (ch < 0x10000) + *out++ = SWAB2((Py_UCS2)ch); + else { + Py_UCS2 ch1 = Py_UNICODE_HIGH_SURROGATE(ch); + Py_UCS2 ch2 = Py_UNICODE_LOW_SURROGATE(ch); + out[0] = SWAB2(ch1); + out[1] = SWAB2(ch2); + out += 2; + } + } + } +#endif +#undef SWAB2 +} +#endif /* STRINGLIB_IS_UNICODE */ diff --git a/Objects/stringlib/count.h b/Objects/stringlib/count.h index de34f96b3e..f48500bf56 100644 --- a/Objects/stringlib/count.h +++ b/Objects/stringlib/count.h @@ -1,14 +1,11 @@ /* stringlib: count implementation */ -#ifndef STRINGLIB_COUNT_H -#define STRINGLIB_COUNT_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif Py_LOCAL_INLINE(Py_ssize_t) -stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(count)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t maxcount) { @@ -19,7 +16,7 @@ stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, if (sub_len == 0) return (str_len < maxcount) ? str_len + 1 : maxcount; - count = fastsearch(str, str_len, sub, sub_len, maxcount, FAST_COUNT); + count = FASTSEARCH(str, str_len, sub, sub_len, maxcount, FAST_COUNT); if (count < 0) return 0; /* no match */ @@ -27,4 +24,4 @@ stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, return count; } -#endif + diff --git a/Objects/stringlib/eq.h b/Objects/stringlib/eq.h index 3e7f5e86c6..3e5f510e36 100644 --- a/Objects/stringlib/eq.h +++ b/Objects/stringlib/eq.h @@ -9,13 +9,17 @@ unicode_eq(PyObject *aa, PyObject *bb) register PyUnicodeObject *a = (PyUnicodeObject *)aa; register PyUnicodeObject *b = (PyUnicodeObject *)bb; - if (a->length != b->length) + if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) { + assert(0 && "unicode_eq ready fail"); return 0; - if (a->length == 0) - return 1; - if (a->str[0] != b->str[0]) + } + + if (PyUnicode_GET_LENGTH(a) != PyUnicode_GET_LENGTH(b)) return 0; - if (a->length == 1) + if (PyUnicode_GET_LENGTH(a) == 0) return 1; - return memcmp(a->str, b->str, a->length * sizeof(Py_UNICODE)) == 0; + if (PyUnicode_KIND(a) != PyUnicode_KIND(b)) + return 0; + return memcmp(PyUnicode_1BYTE_DATA(a), PyUnicode_1BYTE_DATA(b), + PyUnicode_GET_LENGTH(a) * PyUnicode_KIND(a)) == 0; } diff --git a/Objects/stringlib/fastsearch.h b/Objects/stringlib/fastsearch.h index e231c587e4..55ac77dd70 100644 --- a/Objects/stringlib/fastsearch.h +++ b/Objects/stringlib/fastsearch.h @@ -1,6 +1,5 @@ /* stringlib: fastsearch implementation */ -#ifndef STRINGLIB_FASTSEARCH_H #define STRINGLIB_FASTSEARCH_H /* fast search/count implementation, based on a mix between boyer- @@ -33,8 +32,56 @@ #define STRINGLIB_BLOOM(mask, ch) \ ((mask & (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1))))) + +Py_LOCAL_INLINE(Py_ssize_t) +STRINGLIB(fastsearch_memchr_1char)(const STRINGLIB_CHAR* s, Py_ssize_t n, + STRINGLIB_CHAR ch, unsigned char needle, + Py_ssize_t maxcount, int mode) +{ + if (mode == FAST_SEARCH) { + const STRINGLIB_CHAR *ptr = s; + const STRINGLIB_CHAR *e = s + n; + while (ptr < e) { + void *candidate = memchr((const void *) ptr, needle, (e - ptr) * sizeof(STRINGLIB_CHAR)); + if (candidate == NULL) + return -1; + ptr = (const STRINGLIB_CHAR *) _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); + if (sizeof(STRINGLIB_CHAR) == 1 || *ptr == ch) + return (ptr - s); + /* False positive */ + ptr++; + } + return -1; + } +#ifdef HAVE_MEMRCHR + /* memrchr() is a GNU extension, available since glibc 2.1.91. + it doesn't seem as optimized as memchr(), but is still quite + faster than our hand-written loop in FASTSEARCH below */ + else if (mode == FAST_RSEARCH) { + while (n > 0) { + const STRINGLIB_CHAR *found; + void *candidate = memrchr((const void *) s, needle, n * sizeof(STRINGLIB_CHAR)); + if (candidate == NULL) + return -1; + found = (const STRINGLIB_CHAR *) _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); + n = found - s; + if (sizeof(STRINGLIB_CHAR) == 1 || *found == ch) + return n; + /* False positive */ + } + return -1; + } +#endif + else { + assert(0); /* Should never get here */ + return 0; + } + +#undef DO_MEMCHR +} + Py_LOCAL_INLINE(Py_ssize_t) -fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, +FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n, const STRINGLIB_CHAR* p, Py_ssize_t m, Py_ssize_t maxcount, int mode) { @@ -52,6 +99,24 @@ fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, if (m <= 0) return -1; /* use special case for 1-character strings */ + if (n > 10 && (mode == FAST_SEARCH +#ifdef HAVE_MEMRCHR + || mode == FAST_RSEARCH +#endif + )) { + /* use memchr if we can choose a needle without two many likely + false positives */ + unsigned char needle; + needle = p[0] & 0xff; +#if STRINGLIB_SIZEOF_CHAR > 1 + /* If looking for a multiple of 256, we'd have too + many false positives looking for the '\0' byte in UCS2 + and UCS4 representations. */ + if (needle != 0) +#endif + return STRINGLIB(fastsearch_memchr_1char) + (s, n, p[0], needle, maxcount, mode); + } if (mode == FAST_COUNT) { for (i = 0; i < n; i++) if (s[i] == p[0]) { @@ -157,4 +222,3 @@ fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, return count; } -#endif diff --git a/Objects/stringlib/find.h b/Objects/stringlib/find.h index ce615dcb8a..518e012b75 100644 --- a/Objects/stringlib/find.h +++ b/Objects/stringlib/find.h @@ -1,14 +1,11 @@ /* stringlib: find/index implementation */ -#ifndef STRINGLIB_FIND_H -#define STRINGLIB_FIND_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif Py_LOCAL_INLINE(Py_ssize_t) -stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(find)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t offset) { @@ -19,7 +16,7 @@ stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, if (sub_len == 0) return offset; - pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_SEARCH); + pos = FASTSEARCH(str, str_len, sub, sub_len, -1, FAST_SEARCH); if (pos >= 0) pos += offset; @@ -28,7 +25,7 @@ stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, } Py_LOCAL_INLINE(Py_ssize_t) -stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(rfind)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t offset) { @@ -39,7 +36,7 @@ stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, if (sub_len == 0) return str_len + offset; - pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_RSEARCH); + pos = FASTSEARCH(str, str_len, sub, sub_len, -1, FAST_RSEARCH); if (pos >= 0) pos += offset; @@ -63,29 +60,29 @@ stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, } Py_LOCAL_INLINE(Py_ssize_t) -stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(find_slice)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t start, Py_ssize_t end) { ADJUST_INDICES(start, end, str_len); - return stringlib_find(str + start, end - start, sub, sub_len, start); + return STRINGLIB(find)(str + start, end - start, sub, sub_len, start); } Py_LOCAL_INLINE(Py_ssize_t) -stringlib_rfind_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(rfind_slice)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t start, Py_ssize_t end) { ADJUST_INDICES(start, end, str_len); - return stringlib_rfind(str + start, end - start, sub, sub_len, start); + return STRINGLIB(rfind)(str + start, end - start, sub, sub_len, start); } #ifdef STRINGLIB_WANT_CONTAINS_OBJ Py_LOCAL_INLINE(int) -stringlib_contains_obj(PyObject* str, PyObject* sub) +STRINGLIB(contains_obj)(PyObject* str, PyObject* sub) { - return stringlib_find( + return STRINGLIB(find)( STRINGLIB_STR(str), STRINGLIB_LEN(str), STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0 ) != -1; @@ -98,14 +95,14 @@ This function is a helper for the "find" family (find, rfind, index, rindex) and for count, startswith and endswith, because they all have the same behaviour for the arguments. -It does not touch the variables received until it knows everything +It does not touch the variables received until it knows everything is ok. */ #define FORMAT_BUFFER_SIZE 50 Py_LOCAL_INLINE(int) -stringlib_parse_args_finds(const char * function_name, PyObject *args, +STRINGLIB(parse_args_finds)(const char * function_name, PyObject *args, PyObject **subobj, Py_ssize_t *start, Py_ssize_t *end) { @@ -148,28 +145,76 @@ first argument is a unicode object. Note that we receive a pointer to the pointer of the substring object, so when we create that object in this function we don't DECREF it, -because it continues living in the caller functions (those functions, +because it continues living in the caller functions (those functions, after finishing using the substring, must DECREF it). */ Py_LOCAL_INLINE(int) -stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, - PyUnicodeObject **substring, +STRINGLIB(parse_args_finds_unicode)(const char * function_name, PyObject *args, + PyObject **substring, Py_ssize_t *start, Py_ssize_t *end) { PyObject *tmp_substring; - if(stringlib_parse_args_finds(function_name, args, &tmp_substring, + if(STRINGLIB(parse_args_finds)(function_name, args, &tmp_substring, start, end)) { tmp_substring = PyUnicode_FromObject(tmp_substring); if (!tmp_substring) return 0; - *substring = (PyUnicodeObject *)tmp_substring; + *substring = tmp_substring; return 1; } return 0; } -#endif /* STRINGLIB_IS_UNICODE */ +#else /* !STRINGLIB_IS_UNICODE */ + +/* +Wraps stringlib_parse_args_finds() and additionally checks whether the +first argument is an integer in range(0, 256). + +If this is the case, writes the integer value to the byte parameter +and sets subobj to NULL. Otherwise, sets the first argument to subobj +and doesn't touch byte. The other parameters are similar to those of +stringlib_parse_args_finds(). +*/ + +Py_LOCAL_INLINE(int) +STRINGLIB(parse_args_finds_byte)(const char *function_name, PyObject *args, + PyObject **subobj, char *byte, + Py_ssize_t *start, Py_ssize_t *end) +{ + PyObject *tmp_subobj; + Py_ssize_t ival; + PyObject *err; + + if(!STRINGLIB(parse_args_finds)(function_name, args, &tmp_subobj, + start, end)) + return 0; -#endif /* STRINGLIB_FIND_H */ + if (!PyNumber_Check(tmp_subobj)) { + *subobj = tmp_subobj; + return 1; + } + + ival = PyNumber_AsSsize_t(tmp_subobj, PyExc_OverflowError); + if (ival == -1) { + err = PyErr_Occurred(); + if (err && !PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { + PyErr_Clear(); + *subobj = tmp_subobj; + return 1; + } + } + + if (ival < 0 || ival > 255) { + PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); + return 0; + } + + *subobj = NULL; + *byte = (char)ival; + return 1; +} + +#endif /* STRINGLIB_IS_UNICODE */ diff --git a/Objects/stringlib/find_max_char.h b/Objects/stringlib/find_max_char.h new file mode 100644 index 0000000000..06559c8a9f --- /dev/null +++ b/Objects/stringlib/find_max_char.h @@ -0,0 +1,133 @@ +/* Finding the optimal width of unicode characters in a buffer */ + +#if STRINGLIB_IS_UNICODE + +/* Mask to quickly check whether a C 'long' contains a + non-ASCII, UTF8-encoded char. */ +#if (SIZEOF_LONG == 8) +# define UCS1_ASCII_CHAR_MASK 0x8080808080808080UL +#elif (SIZEOF_LONG == 4) +# define UCS1_ASCII_CHAR_MASK 0x80808080UL +#else +# error C 'long' size should be either 4 or 8! +#endif + +#if STRINGLIB_SIZEOF_CHAR == 1 + +Py_LOCAL_INLINE(Py_UCS4) +STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end) +{ + const unsigned char *p = (const unsigned char *) begin; + const unsigned char *aligned_end = + (const unsigned char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); + + while (p < end) { + if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) { + /* Help register allocation */ + register const unsigned char *_p = p; + while (_p < aligned_end) { + unsigned long value = *(unsigned long *) _p; + if (value & UCS1_ASCII_CHAR_MASK) + return 255; + _p += SIZEOF_LONG; + } + p = _p; + if (p == end) + break; + } + if (*p++ & 0x80) + return 255; + } + return 127; +} + +#undef ASCII_CHAR_MASK + +#else /* STRINGLIB_SIZEOF_CHAR == 1 */ + +#define MASK_ASCII 0xFFFFFF80 +#define MASK_UCS1 0xFFFFFF00 +#define MASK_UCS2 0xFFFF0000 + +#define MAX_CHAR_ASCII 0x7f +#define MAX_CHAR_UCS1 0xff +#define MAX_CHAR_UCS2 0xffff +#define MAX_CHAR_UCS4 0x10ffff + +Py_LOCAL_INLINE(Py_UCS4) +STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end) +{ +#if STRINGLIB_SIZEOF_CHAR == 2 + const Py_UCS4 mask_limit = MASK_UCS1; + const Py_UCS4 max_char_limit = MAX_CHAR_UCS2; +#elif STRINGLIB_SIZEOF_CHAR == 4 + const Py_UCS4 mask_limit = MASK_UCS2; + const Py_UCS4 max_char_limit = MAX_CHAR_UCS4; +#else +#error Invalid STRINGLIB_SIZEOF_CHAR (must be 1, 2 or 4) +#endif + register Py_UCS4 mask; + Py_ssize_t n = end - begin; + const STRINGLIB_CHAR *p = begin; + const STRINGLIB_CHAR *unrolled_end = begin + _Py_SIZE_ROUND_DOWN(n, 4); + Py_UCS4 max_char; + + max_char = MAX_CHAR_ASCII; + mask = MASK_ASCII; + while (p < unrolled_end) { + STRINGLIB_CHAR bits = p[0] | p[1] | p[2] | p[3]; + if (bits & mask) { + if (mask == mask_limit) { + /* Limit reached */ + return max_char_limit; + } + if (mask == MASK_ASCII) { + max_char = MAX_CHAR_UCS1; + mask = MASK_UCS1; + } + else { + /* mask can't be MASK_UCS2 because of mask_limit above */ + assert(mask == MASK_UCS1); + max_char = MAX_CHAR_UCS2; + mask = MASK_UCS2; + } + /* We check the new mask on the same chars in the next iteration */ + continue; + } + p += 4; + } + while (p < end) { + if (p[0] & mask) { + if (mask == mask_limit) { + /* Limit reached */ + return max_char_limit; + } + if (mask == MASK_ASCII) { + max_char = MAX_CHAR_UCS1; + mask = MASK_UCS1; + } + else { + /* mask can't be MASK_UCS2 because of mask_limit above */ + assert(mask == MASK_UCS1); + max_char = MAX_CHAR_UCS2; + mask = MASK_UCS2; + } + /* We check the new mask on the same chars in the next iteration */ + continue; + } + p++; + } + return max_char; +} + +#undef MASK_ASCII +#undef MASK_UCS1 +#undef MASK_UCS2 +#undef MAX_CHAR_ASCII +#undef MAX_CHAR_UCS1 +#undef MAX_CHAR_UCS2 +#undef MAX_CHAR_UCS4 + +#endif /* STRINGLIB_SIZEOF_CHAR == 1 */ +#endif /* STRINGLIB_IS_UNICODE */ + diff --git a/Objects/stringlib/formatter.h b/Objects/stringlib/formatter.h deleted file mode 100644 index be0d897a91..0000000000 --- a/Objects/stringlib/formatter.h +++ /dev/null @@ -1,1516 +0,0 @@ -/* implements the string, long, and float formatters. that is, - string.__format__, etc. */ - -#include <locale.h> - -/* Before including this, you must include either: - stringlib/unicodedefs.h - stringlib/stringdefs.h - - Also, you should define the names: - FORMAT_STRING - FORMAT_LONG - FORMAT_FLOAT - FORMAT_COMPLEX - to be whatever you want the public names of these functions to - be. These are the only non-static functions defined here. -*/ - -/* Raises an exception about an unknown presentation type for this - * type. */ - -static void -unknown_presentation_type(STRINGLIB_CHAR presentation_type, - const char* type_name) -{ -#if STRINGLIB_IS_UNICODE - /* If STRINGLIB_CHAR is Py_UNICODE, %c might be out-of-range, - hence the two cases. If it is char, gcc complains that the - condition below is always true, hence the ifdef. */ - if (presentation_type > 32 && presentation_type < 128) -#endif - PyErr_Format(PyExc_ValueError, - "Unknown format code '%c' " - "for object of type '%.200s'", - (char)presentation_type, - type_name); -#if STRINGLIB_IS_UNICODE - else - PyErr_Format(PyExc_ValueError, - "Unknown format code '\\x%x' " - "for object of type '%.200s'", - (unsigned int)presentation_type, - type_name); -#endif -} - -static void -invalid_comma_type(STRINGLIB_CHAR presentation_type) -{ -#if STRINGLIB_IS_UNICODE - /* See comment in unknown_presentation_type */ - if (presentation_type > 32 && presentation_type < 128) -#endif - PyErr_Format(PyExc_ValueError, - "Cannot specify ',' with '%c'.", - (char)presentation_type); -#if STRINGLIB_IS_UNICODE - else - PyErr_Format(PyExc_ValueError, - "Cannot specify ',' with '\\x%x'.", - (unsigned int)presentation_type); -#endif -} - -/* - get_integer consumes 0 or more decimal digit characters from an - input string, updates *result with the corresponding positive - integer, and returns the number of digits consumed. - - returns -1 on error. -*/ -static int -get_integer(STRINGLIB_CHAR **ptr, STRINGLIB_CHAR *end, - Py_ssize_t *result) -{ - Py_ssize_t accumulator, digitval; - int numdigits; - accumulator = numdigits = 0; - for (;;(*ptr)++, numdigits++) { - if (*ptr >= end) - break; - digitval = STRINGLIB_TODECIMAL(**ptr); - if (digitval < 0) - break; - /* - Detect possible overflow before it happens: - - accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if - accumulator > (PY_SSIZE_T_MAX - digitval) / 10. - */ - if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) { - PyErr_Format(PyExc_ValueError, - "Too many decimal digits in format string"); - return -1; - } - accumulator = accumulator * 10 + digitval; - } - *result = accumulator; - return numdigits; -} - -/************************************************************************/ -/*********** standard format specifier parsing **************************/ -/************************************************************************/ - -/* returns true if this character is a specifier alignment token */ -Py_LOCAL_INLINE(int) -is_alignment_token(STRINGLIB_CHAR c) -{ - switch (c) { - case '<': case '>': case '=': case '^': - return 1; - default: - return 0; - } -} - -/* returns true if this character is a sign element */ -Py_LOCAL_INLINE(int) -is_sign_element(STRINGLIB_CHAR c) -{ - switch (c) { - case ' ': case '+': case '-': - return 1; - default: - return 0; - } -} - - -typedef struct { - STRINGLIB_CHAR fill_char; - STRINGLIB_CHAR align; - int alternate; - STRINGLIB_CHAR sign; - Py_ssize_t width; - int thousands_separators; - Py_ssize_t precision; - STRINGLIB_CHAR type; -} InternalFormatSpec; - - -#if 0 -/* Occassionally useful for debugging. Should normally be commented out. */ -static void -DEBUG_PRINT_FORMAT_SPEC(InternalFormatSpec *format) -{ - printf("internal format spec: fill_char %d\n", format->fill_char); - printf("internal format spec: align %d\n", format->align); - printf("internal format spec: alternate %d\n", format->alternate); - printf("internal format spec: sign %d\n", format->sign); - printf("internal format spec: width %zd\n", format->width); - printf("internal format spec: thousands_separators %d\n", - format->thousands_separators); - printf("internal format spec: precision %zd\n", format->precision); - printf("internal format spec: type %c\n", format->type); - printf("\n"); -} -#endif - - -/* - ptr points to the start of the format_spec, end points just past its end. - fills in format with the parsed information. - returns 1 on success, 0 on failure. - if failure, sets the exception -*/ -static int -parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len, - InternalFormatSpec *format, - char default_type, - char default_align) -{ - STRINGLIB_CHAR *ptr = format_spec; - STRINGLIB_CHAR *end = format_spec + format_spec_len; - - /* end-ptr is used throughout this code to specify the length of - the input string */ - - Py_ssize_t consumed; - int align_specified = 0; - - format->fill_char = '\0'; - format->align = default_align; - format->alternate = 0; - format->sign = '\0'; - format->width = -1; - format->thousands_separators = 0; - format->precision = -1; - format->type = default_type; - - /* If the second char is an alignment token, - then parse the fill char */ - if (end-ptr >= 2 && is_alignment_token(ptr[1])) { - format->align = ptr[1]; - format->fill_char = ptr[0]; - align_specified = 1; - ptr += 2; - } - else if (end-ptr >= 1 && is_alignment_token(ptr[0])) { - format->align = ptr[0]; - align_specified = 1; - ++ptr; - } - - /* Parse the various sign options */ - if (end-ptr >= 1 && is_sign_element(ptr[0])) { - format->sign = ptr[0]; - ++ptr; - } - - /* If the next character is #, we're in alternate mode. This only - applies to integers. */ - if (end-ptr >= 1 && ptr[0] == '#') { - format->alternate = 1; - ++ptr; - } - - /* The special case for 0-padding (backwards compat) */ - if (format->fill_char == '\0' && end-ptr >= 1 && ptr[0] == '0') { - format->fill_char = '0'; - if (!align_specified) { - format->align = '='; - } - ++ptr; - } - - consumed = get_integer(&ptr, end, &format->width); - if (consumed == -1) - /* Overflow error. Exception already set. */ - return 0; - - /* If consumed is 0, we didn't consume any characters for the - width. In that case, reset the width to -1, because - get_integer() will have set it to zero. -1 is how we record - that the width wasn't specified. */ - if (consumed == 0) - format->width = -1; - - /* Comma signifies add thousands separators */ - if (end-ptr && ptr[0] == ',') { - format->thousands_separators = 1; - ++ptr; - } - - /* Parse field precision */ - if (end-ptr && ptr[0] == '.') { - ++ptr; - - consumed = get_integer(&ptr, end, &format->precision); - if (consumed == -1) - /* Overflow error. Exception already set. */ - return 0; - - /* Not having a precision after a dot is an error. */ - if (consumed == 0) { - PyErr_Format(PyExc_ValueError, - "Format specifier missing precision"); - return 0; - } - - } - - /* Finally, parse the type field. */ - - if (end-ptr > 1) { - /* More than one char remain, invalid conversion spec. */ - PyErr_Format(PyExc_ValueError, "Invalid conversion specification"); - return 0; - } - - if (end-ptr == 1) { - format->type = ptr[0]; - ++ptr; - } - - /* Do as much validating as we can, just by looking at the format - specifier. Do not take into account what type of formatting - we're doing (int, float, string). */ - - if (format->thousands_separators) { - switch (format->type) { - case 'd': - case 'e': - case 'f': - case 'g': - case 'E': - case 'G': - case '%': - case 'F': - case '\0': - /* These are allowed. See PEP 378.*/ - break; - default: - invalid_comma_type(format->type); - return 0; - } - } - - return 1; -} - -/* Calculate the padding needed. */ -static void -calc_padding(Py_ssize_t nchars, Py_ssize_t width, STRINGLIB_CHAR align, - Py_ssize_t *n_lpadding, Py_ssize_t *n_rpadding, - Py_ssize_t *n_total) -{ - if (width >= 0) { - if (nchars > width) - *n_total = nchars; - else - *n_total = width; - } - else { - /* not specified, use all of the chars and no more */ - *n_total = nchars; - } - - /* Figure out how much leading space we need, based on the - aligning */ - if (align == '>') - *n_lpadding = *n_total - nchars; - else if (align == '^') - *n_lpadding = (*n_total - nchars) / 2; - else if (align == '<' || align == '=') - *n_lpadding = 0; - else { - /* We should never have an unspecified alignment. */ - *n_lpadding = 0; - assert(0); - } - - *n_rpadding = *n_total - nchars - *n_lpadding; -} - -/* Do the padding, and return a pointer to where the caller-supplied - content goes. */ -static STRINGLIB_CHAR * -fill_padding(STRINGLIB_CHAR *p, Py_ssize_t nchars, STRINGLIB_CHAR fill_char, - Py_ssize_t n_lpadding, Py_ssize_t n_rpadding) -{ - /* Pad on left. */ - if (n_lpadding) - STRINGLIB_FILL(p, fill_char, n_lpadding); - - /* Pad on right. */ - if (n_rpadding) - STRINGLIB_FILL(p + nchars + n_lpadding, fill_char, n_rpadding); - - /* Pointer to the user content. */ - return p + n_lpadding; -} - -#if defined FORMAT_FLOAT || defined FORMAT_LONG || defined FORMAT_COMPLEX -/************************************************************************/ -/*********** common routines for numeric formatting *********************/ -/************************************************************************/ - -/* Locale type codes. */ -#define LT_CURRENT_LOCALE 0 -#define LT_DEFAULT_LOCALE 1 -#define LT_NO_LOCALE 2 - -/* Locale info needed for formatting integers and the part of floats - before and including the decimal. Note that locales only support - 8-bit chars, not unicode. */ -typedef struct { - char *decimal_point; - char *thousands_sep; - char *grouping; -} LocaleInfo; - -/* describes the layout for an integer, see the comment in - calc_number_widths() for details */ -typedef struct { - Py_ssize_t n_lpadding; - Py_ssize_t n_prefix; - Py_ssize_t n_spadding; - Py_ssize_t n_rpadding; - char sign; - Py_ssize_t n_sign; /* number of digits needed for sign (0/1) */ - Py_ssize_t n_grouped_digits; /* Space taken up by the digits, including - any grouping chars. */ - Py_ssize_t n_decimal; /* 0 if only an integer */ - Py_ssize_t n_remainder; /* Digits in decimal and/or exponent part, - excluding the decimal itself, if - present. */ - - /* These 2 are not the widths of fields, but are needed by - STRINGLIB_GROUPING. */ - Py_ssize_t n_digits; /* The number of digits before a decimal - or exponent. */ - Py_ssize_t n_min_width; /* The min_width we used when we computed - the n_grouped_digits width. */ -} NumberFieldWidths; - - -/* Given a number of the form: - digits[remainder] - where ptr points to the start and end points to the end, find where - the integer part ends. This could be a decimal, an exponent, both, - or neither. - If a decimal point is present, set *has_decimal and increment - remainder beyond it. - Results are undefined (but shouldn't crash) for improperly - formatted strings. -*/ -static void -parse_number(STRINGLIB_CHAR *ptr, Py_ssize_t len, - Py_ssize_t *n_remainder, int *has_decimal) -{ - STRINGLIB_CHAR *end = ptr + len; - STRINGLIB_CHAR *remainder; - - while (ptr<end && Py_ISDIGIT(*ptr)) - ++ptr; - remainder = ptr; - - /* Does remainder start with a decimal point? */ - *has_decimal = ptr<end && *remainder == '.'; - - /* Skip the decimal point. */ - if (*has_decimal) - remainder++; - - *n_remainder = end - remainder; -} - -/* not all fields of format are used. for example, precision is - unused. should this take discrete params in order to be more clear - about what it does? or is passing a single format parameter easier - and more efficient enough to justify a little obfuscation? */ -static Py_ssize_t -calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix, - STRINGLIB_CHAR sign_char, STRINGLIB_CHAR *number, - Py_ssize_t n_number, Py_ssize_t n_remainder, - int has_decimal, const LocaleInfo *locale, - const InternalFormatSpec *format) -{ - Py_ssize_t n_non_digit_non_padding; - Py_ssize_t n_padding; - - spec->n_digits = n_number - n_remainder - (has_decimal?1:0); - spec->n_lpadding = 0; - spec->n_prefix = n_prefix; - spec->n_decimal = has_decimal ? strlen(locale->decimal_point) : 0; - spec->n_remainder = n_remainder; - spec->n_spadding = 0; - spec->n_rpadding = 0; - spec->sign = '\0'; - spec->n_sign = 0; - - /* the output will look like: - | | - | <lpadding> <sign> <prefix> <spadding> <grouped_digits> <decimal> <remainder> <rpadding> | - | | - - sign is computed from format->sign and the actual - sign of the number - - prefix is given (it's for the '0x' prefix) - - digits is already known - - the total width is either given, or computed from the - actual digits - - only one of lpadding, spadding, and rpadding can be non-zero, - and it's calculated from the width and other fields - */ - - /* compute the various parts we're going to write */ - switch (format->sign) { - case '+': - /* always put a + or - */ - spec->n_sign = 1; - spec->sign = (sign_char == '-' ? '-' : '+'); - break; - case ' ': - spec->n_sign = 1; - spec->sign = (sign_char == '-' ? '-' : ' '); - break; - default: - /* Not specified, or the default (-) */ - if (sign_char == '-') { - spec->n_sign = 1; - spec->sign = '-'; - } - } - - /* The number of chars used for non-digits and non-padding. */ - n_non_digit_non_padding = spec->n_sign + spec->n_prefix + spec->n_decimal + - spec->n_remainder; - - /* min_width can go negative, that's okay. format->width == -1 means - we don't care. */ - if (format->fill_char == '0' && format->align == '=') - spec->n_min_width = format->width - n_non_digit_non_padding; - else - spec->n_min_width = 0; - - if (spec->n_digits == 0) - /* This case only occurs when using 'c' formatting, we need - to special case it because the grouping code always wants - to have at least one character. */ - spec->n_grouped_digits = 0; - else - spec->n_grouped_digits = STRINGLIB_GROUPING(NULL, 0, NULL, - spec->n_digits, - spec->n_min_width, - locale->grouping, - locale->thousands_sep); - - /* Given the desired width and the total of digit and non-digit - space we consume, see if we need any padding. format->width can - be negative (meaning no padding), but this code still works in - that case. */ - n_padding = format->width - - (n_non_digit_non_padding + spec->n_grouped_digits); - if (n_padding > 0) { - /* Some padding is needed. Determine if it's left, space, or right. */ - switch (format->align) { - case '<': - spec->n_rpadding = n_padding; - break; - case '^': - spec->n_lpadding = n_padding / 2; - spec->n_rpadding = n_padding - spec->n_lpadding; - break; - case '=': - spec->n_spadding = n_padding; - break; - case '>': - spec->n_lpadding = n_padding; - break; - default: - /* Shouldn't get here, but treat it as '>' */ - spec->n_lpadding = n_padding; - assert(0); - break; - } - } - return spec->n_lpadding + spec->n_sign + spec->n_prefix + - spec->n_spadding + spec->n_grouped_digits + spec->n_decimal + - spec->n_remainder + spec->n_rpadding; -} - -/* Fill in the digit parts of a numbers's string representation, - as determined in calc_number_widths(). - No error checking, since we know the buffer is the correct size. */ -static void -fill_number(STRINGLIB_CHAR *buf, const NumberFieldWidths *spec, - STRINGLIB_CHAR *digits, Py_ssize_t n_digits, - STRINGLIB_CHAR *prefix, STRINGLIB_CHAR fill_char, - LocaleInfo *locale, int toupper) -{ - /* Used to keep track of digits, decimal, and remainder. */ - STRINGLIB_CHAR *p = digits; - -#ifndef NDEBUG - Py_ssize_t r; -#endif - - if (spec->n_lpadding) { - STRINGLIB_FILL(buf, fill_char, spec->n_lpadding); - buf += spec->n_lpadding; - } - if (spec->n_sign == 1) { - *buf++ = spec->sign; - } - if (spec->n_prefix) { - memmove(buf, - prefix, - spec->n_prefix * sizeof(STRINGLIB_CHAR)); - if (toupper) { - Py_ssize_t t; - for (t = 0; t < spec->n_prefix; ++t) - buf[t] = STRINGLIB_TOUPPER(buf[t]); - } - buf += spec->n_prefix; - } - if (spec->n_spadding) { - STRINGLIB_FILL(buf, fill_char, spec->n_spadding); - buf += spec->n_spadding; - } - - /* Only for type 'c' special case, it has no digits. */ - if (spec->n_digits != 0) { - /* Fill the digits with InsertThousandsGrouping. */ -#ifndef NDEBUG - r = -#endif - STRINGLIB_GROUPING(buf, spec->n_grouped_digits, digits, - spec->n_digits, spec->n_min_width, - locale->grouping, locale->thousands_sep); -#ifndef NDEBUG - assert(r == spec->n_grouped_digits); -#endif - p += spec->n_digits; - } - if (toupper) { - Py_ssize_t t; - for (t = 0; t < spec->n_grouped_digits; ++t) - buf[t] = STRINGLIB_TOUPPER(buf[t]); - } - buf += spec->n_grouped_digits; - - if (spec->n_decimal) { - Py_ssize_t t; - for (t = 0; t < spec->n_decimal; ++t) - buf[t] = locale->decimal_point[t]; - buf += spec->n_decimal; - p += 1; - } - - if (spec->n_remainder) { - memcpy(buf, p, spec->n_remainder * sizeof(STRINGLIB_CHAR)); - buf += spec->n_remainder; - p += spec->n_remainder; - } - - if (spec->n_rpadding) { - STRINGLIB_FILL(buf, fill_char, spec->n_rpadding); - buf += spec->n_rpadding; - } -} - -static char no_grouping[1] = {CHAR_MAX}; - -/* Find the decimal point character(s?), thousands_separator(s?), and - grouping description, either for the current locale if type is - LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE, or - none if LT_NO_LOCALE. */ -static void -get_locale_info(int type, LocaleInfo *locale_info) -{ - switch (type) { - case LT_CURRENT_LOCALE: { - struct lconv *locale_data = localeconv(); - locale_info->decimal_point = locale_data->decimal_point; - locale_info->thousands_sep = locale_data->thousands_sep; - locale_info->grouping = locale_data->grouping; - break; - } - case LT_DEFAULT_LOCALE: - locale_info->decimal_point = "."; - locale_info->thousands_sep = ","; - locale_info->grouping = "\3"; /* Group every 3 characters. The - (implicit) trailing 0 means repeat - infinitely. */ - break; - case LT_NO_LOCALE: - locale_info->decimal_point = "."; - locale_info->thousands_sep = ""; - locale_info->grouping = no_grouping; - break; - default: - assert(0); - } -} - -#endif /* FORMAT_FLOAT || FORMAT_LONG || FORMAT_COMPLEX */ - -/************************************************************************/ -/*********** string formatting ******************************************/ -/************************************************************************/ - -static PyObject * -format_string_internal(PyObject *value, const InternalFormatSpec *format) -{ - Py_ssize_t lpad; - Py_ssize_t rpad; - Py_ssize_t total; - STRINGLIB_CHAR *p; - Py_ssize_t len = STRINGLIB_LEN(value); - PyObject *result = NULL; - - /* sign is not allowed on strings */ - if (format->sign != '\0') { - PyErr_SetString(PyExc_ValueError, - "Sign not allowed in string format specifier"); - goto done; - } - - /* alternate is not allowed on strings */ - if (format->alternate) { - PyErr_SetString(PyExc_ValueError, - "Alternate form (#) not allowed in string format " - "specifier"); - goto done; - } - - /* '=' alignment not allowed on strings */ - if (format->align == '=') { - PyErr_SetString(PyExc_ValueError, - "'=' alignment not allowed " - "in string format specifier"); - goto done; - } - - /* if precision is specified, output no more that format.precision - characters */ - if (format->precision >= 0 && len >= format->precision) { - len = format->precision; - } - - calc_padding(len, format->width, format->align, &lpad, &rpad, &total); - - /* allocate the resulting string */ - result = STRINGLIB_NEW(NULL, total); - if (result == NULL) - goto done; - - /* Write into that space. First the padding. */ - p = fill_padding(STRINGLIB_STR(result), len, - format->fill_char=='\0'?' ':format->fill_char, - lpad, rpad); - - /* Then the source string. */ - memcpy(p, STRINGLIB_STR(value), len * sizeof(STRINGLIB_CHAR)); - -done: - return result; -} - - -/************************************************************************/ -/*********** long formatting ********************************************/ -/************************************************************************/ - -#if defined FORMAT_LONG || defined FORMAT_INT -typedef PyObject* -(*IntOrLongToString)(PyObject *value, int base); - -static PyObject * -format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format, - IntOrLongToString tostring) -{ - PyObject *result = NULL; - PyObject *tmp = NULL; - STRINGLIB_CHAR *pnumeric_chars; - STRINGLIB_CHAR numeric_char; - STRINGLIB_CHAR sign_char = '\0'; - Py_ssize_t n_digits; /* count of digits need from the computed - string */ - Py_ssize_t n_remainder = 0; /* Used only for 'c' formatting, which - produces non-digits */ - Py_ssize_t n_prefix = 0; /* Count of prefix chars, (e.g., '0x') */ - Py_ssize_t n_total; - STRINGLIB_CHAR *prefix = NULL; - NumberFieldWidths spec; - long x; - - /* Locale settings, either from the actual locale or - from a hard-code pseudo-locale */ - LocaleInfo locale; - - /* no precision allowed on integers */ - if (format->precision != -1) { - PyErr_SetString(PyExc_ValueError, - "Precision not allowed in integer format specifier"); - goto done; - } - - /* special case for character formatting */ - if (format->type == 'c') { - /* error to specify a sign */ - if (format->sign != '\0') { - PyErr_SetString(PyExc_ValueError, - "Sign not allowed with integer" - " format specifier 'c'"); - goto done; - } - - /* taken from unicodeobject.c formatchar() */ - /* Integer input truncated to a character */ -/* XXX: won't work for int */ - x = PyLong_AsLong(value); - if (x == -1 && PyErr_Occurred()) - goto done; -#ifdef Py_UNICODE_WIDE - if (x < 0 || x > 0x10ffff) { - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x110000) " - "(wide Python build)"); - goto done; - } -#else - if (x < 0 || x > 0xffff) { - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x10000) " - "(narrow Python build)"); - goto done; - } -#endif - numeric_char = (STRINGLIB_CHAR)x; - pnumeric_chars = &numeric_char; - n_digits = 1; - - /* As a sort-of hack, we tell calc_number_widths that we only - have "remainder" characters. calc_number_widths thinks - these are characters that don't get formatted, only copied - into the output string. We do this for 'c' formatting, - because the characters are likely to be non-digits. */ - n_remainder = 1; - } - else { - int base; - int leading_chars_to_skip = 0; /* Number of characters added by - PyNumber_ToBase that we want to - skip over. */ - - /* Compute the base and how many characters will be added by - PyNumber_ToBase */ - switch (format->type) { - case 'b': - base = 2; - leading_chars_to_skip = 2; /* 0b */ - break; - case 'o': - base = 8; - leading_chars_to_skip = 2; /* 0o */ - break; - case 'x': - case 'X': - base = 16; - leading_chars_to_skip = 2; /* 0x */ - break; - default: /* shouldn't be needed, but stops a compiler warning */ - case 'd': - case 'n': - base = 10; - break; - } - - /* The number of prefix chars is the same as the leading - chars to skip */ - if (format->alternate) - n_prefix = leading_chars_to_skip; - - /* Do the hard part, converting to a string in a given base */ - tmp = tostring(value, base); - if (tmp == NULL) - goto done; - - pnumeric_chars = STRINGLIB_STR(tmp); - n_digits = STRINGLIB_LEN(tmp); - - prefix = pnumeric_chars; - - /* Remember not to modify what pnumeric_chars points to. it - might be interned. Only modify it after we copy it into a - newly allocated output buffer. */ - - /* Is a sign character present in the output? If so, remember it - and skip it */ - if (pnumeric_chars[0] == '-') { - sign_char = pnumeric_chars[0]; - ++prefix; - ++leading_chars_to_skip; - } - - /* Skip over the leading chars (0x, 0b, etc.) */ - n_digits -= leading_chars_to_skip; - pnumeric_chars += leading_chars_to_skip; - } - - /* Determine the grouping, separator, and decimal point, if any. */ - get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), - &locale); - - /* Calculate how much memory we'll need. */ - n_total = calc_number_widths(&spec, n_prefix, sign_char, pnumeric_chars, - n_digits, n_remainder, 0, &locale, format); - - /* Allocate the memory. */ - result = STRINGLIB_NEW(NULL, n_total); - if (!result) - goto done; - - /* Populate the memory. */ - fill_number(STRINGLIB_STR(result), &spec, pnumeric_chars, n_digits, - prefix, format->fill_char == '\0' ? ' ' : format->fill_char, - &locale, format->type == 'X'); - -done: - Py_XDECREF(tmp); - return result; -} -#endif /* defined FORMAT_LONG || defined FORMAT_INT */ - -/************************************************************************/ -/*********** float formatting *******************************************/ -/************************************************************************/ - -#ifdef FORMAT_FLOAT -#if STRINGLIB_IS_UNICODE -static void -strtounicode(Py_UNICODE *buffer, const char *charbuffer, Py_ssize_t len) -{ - Py_ssize_t i; - for (i = 0; i < len; ++i) - buffer[i] = (Py_UNICODE)charbuffer[i]; -} -#endif - -/* much of this is taken from unicodeobject.c */ -static PyObject * -format_float_internal(PyObject *value, - const InternalFormatSpec *format) -{ - char *buf = NULL; /* buffer returned from PyOS_double_to_string */ - Py_ssize_t n_digits; - Py_ssize_t n_remainder; - Py_ssize_t n_total; - int has_decimal; - double val; - Py_ssize_t precision = format->precision; - Py_ssize_t default_precision = 6; - STRINGLIB_CHAR type = format->type; - int add_pct = 0; - STRINGLIB_CHAR *p; - NumberFieldWidths spec; - int flags = 0; - PyObject *result = NULL; - STRINGLIB_CHAR sign_char = '\0'; - int float_type; /* Used to see if we have a nan, inf, or regular float. */ - -#if STRINGLIB_IS_UNICODE - Py_UNICODE *unicode_tmp = NULL; -#endif - - /* Locale settings, either from the actual locale or - from a hard-code pseudo-locale */ - LocaleInfo locale; - - if (format->alternate) - flags |= Py_DTSF_ALT; - - if (type == '\0') { - /* Omitted type specifier. Behaves in the same way as repr(x) - and str(x) if no precision is given, else like 'g', but with - at least one digit after the decimal point. */ - flags |= Py_DTSF_ADD_DOT_0; - type = 'r'; - default_precision = 0; - } - - if (type == 'n') - /* 'n' is the same as 'g', except for the locale used to - format the result. We take care of that later. */ - type = 'g'; - - val = PyFloat_AsDouble(value); - if (val == -1.0 && PyErr_Occurred()) - goto done; - - if (type == '%') { - type = 'f'; - val *= 100; - add_pct = 1; - } - - if (precision < 0) - precision = default_precision; - else if (type == 'r') - type = 'g'; - - /* Cast "type", because if we're in unicode we need to pass a - 8-bit char. This is safe, because we've restricted what "type" - can be. */ - buf = PyOS_double_to_string(val, (char)type, precision, flags, - &float_type); - if (buf == NULL) - goto done; - n_digits = strlen(buf); - - if (add_pct) { - /* We know that buf has a trailing zero (since we just called - strlen() on it), and we don't use that fact any more. So we - can just write over the trailing zero. */ - buf[n_digits] = '%'; - n_digits += 1; - } - - /* Since there is no unicode version of PyOS_double_to_string, - just use the 8 bit version and then convert to unicode. */ -#if STRINGLIB_IS_UNICODE - unicode_tmp = (Py_UNICODE*)PyMem_Malloc((n_digits)*sizeof(Py_UNICODE)); - if (unicode_tmp == NULL) { - PyErr_NoMemory(); - goto done; - } - strtounicode(unicode_tmp, buf, n_digits); - p = unicode_tmp; -#else - p = buf; -#endif - - /* Is a sign character present in the output? If so, remember it - and skip it */ - if (*p == '-') { - sign_char = *p; - ++p; - --n_digits; - } - - /* Determine if we have any "remainder" (after the digits, might include - decimal or exponent or both (or neither)) */ - parse_number(p, n_digits, &n_remainder, &has_decimal); - - /* Determine the grouping, separator, and decimal point, if any. */ - get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), - &locale); - - /* Calculate how much memory we'll need. */ - n_total = calc_number_widths(&spec, 0, sign_char, p, n_digits, - n_remainder, has_decimal, &locale, format); - - /* Allocate the memory. */ - result = STRINGLIB_NEW(NULL, n_total); - if (result == NULL) - goto done; - - /* Populate the memory. */ - fill_number(STRINGLIB_STR(result), &spec, p, n_digits, NULL, - format->fill_char == '\0' ? ' ' : format->fill_char, &locale, - 0); - -done: - PyMem_Free(buf); -#if STRINGLIB_IS_UNICODE - PyMem_Free(unicode_tmp); -#endif - return result; -} -#endif /* FORMAT_FLOAT */ - -/************************************************************************/ -/*********** complex formatting *****************************************/ -/************************************************************************/ - -#ifdef FORMAT_COMPLEX - -static PyObject * -format_complex_internal(PyObject *value, - const InternalFormatSpec *format) -{ - double re; - double im; - char *re_buf = NULL; /* buffer returned from PyOS_double_to_string */ - char *im_buf = NULL; /* buffer returned from PyOS_double_to_string */ - - InternalFormatSpec tmp_format = *format; - Py_ssize_t n_re_digits; - Py_ssize_t n_im_digits; - Py_ssize_t n_re_remainder; - Py_ssize_t n_im_remainder; - Py_ssize_t n_re_total; - Py_ssize_t n_im_total; - int re_has_decimal; - int im_has_decimal; - Py_ssize_t precision = format->precision; - Py_ssize_t default_precision = 6; - STRINGLIB_CHAR type = format->type; - STRINGLIB_CHAR *p_re; - STRINGLIB_CHAR *p_im; - NumberFieldWidths re_spec; - NumberFieldWidths im_spec; - int flags = 0; - PyObject *result = NULL; - STRINGLIB_CHAR *p; - STRINGLIB_CHAR re_sign_char = '\0'; - STRINGLIB_CHAR im_sign_char = '\0'; - int re_float_type; /* Used to see if we have a nan, inf, or regular float. */ - int im_float_type; - int add_parens = 0; - int skip_re = 0; - Py_ssize_t lpad; - Py_ssize_t rpad; - Py_ssize_t total; - -#if STRINGLIB_IS_UNICODE - Py_UNICODE *re_unicode_tmp = NULL; - Py_UNICODE *im_unicode_tmp = NULL; -#endif - - /* Locale settings, either from the actual locale or - from a hard-code pseudo-locale */ - LocaleInfo locale; - - /* Zero padding is not allowed. */ - if (format->fill_char == '0') { - PyErr_SetString(PyExc_ValueError, - "Zero padding is not allowed in complex format " - "specifier"); - goto done; - } - - /* Neither is '=' alignment . */ - if (format->align == '=') { - PyErr_SetString(PyExc_ValueError, - "'=' alignment flag is not allowed in complex format " - "specifier"); - goto done; - } - - re = PyComplex_RealAsDouble(value); - if (re == -1.0 && PyErr_Occurred()) - goto done; - im = PyComplex_ImagAsDouble(value); - if (im == -1.0 && PyErr_Occurred()) - goto done; - - if (format->alternate) - flags |= Py_DTSF_ALT; - - if (type == '\0') { - /* Omitted type specifier. Should be like str(self). */ - type = 'r'; - default_precision = 0; - if (re == 0.0 && copysign(1.0, re) == 1.0) - skip_re = 1; - else - add_parens = 1; - } - - if (type == 'n') - /* 'n' is the same as 'g', except for the locale used to - format the result. We take care of that later. */ - type = 'g'; - - if (precision < 0) - precision = default_precision; - else if (type == 'r') - type = 'g'; - - /* Cast "type", because if we're in unicode we need to pass a - 8-bit char. This is safe, because we've restricted what "type" - can be. */ - re_buf = PyOS_double_to_string(re, (char)type, precision, flags, - &re_float_type); - if (re_buf == NULL) - goto done; - im_buf = PyOS_double_to_string(im, (char)type, precision, flags, - &im_float_type); - if (im_buf == NULL) - goto done; - - n_re_digits = strlen(re_buf); - n_im_digits = strlen(im_buf); - - /* Since there is no unicode version of PyOS_double_to_string, - just use the 8 bit version and then convert to unicode. */ -#if STRINGLIB_IS_UNICODE - re_unicode_tmp = (Py_UNICODE*)PyMem_Malloc((n_re_digits)*sizeof(Py_UNICODE)); - if (re_unicode_tmp == NULL) { - PyErr_NoMemory(); - goto done; - } - strtounicode(re_unicode_tmp, re_buf, n_re_digits); - p_re = re_unicode_tmp; - - im_unicode_tmp = (Py_UNICODE*)PyMem_Malloc((n_im_digits)*sizeof(Py_UNICODE)); - if (im_unicode_tmp == NULL) { - PyErr_NoMemory(); - goto done; - } - strtounicode(im_unicode_tmp, im_buf, n_im_digits); - p_im = im_unicode_tmp; -#else - p_re = re_buf; - p_im = im_buf; -#endif - - /* Is a sign character present in the output? If so, remember it - and skip it */ - if (*p_re == '-') { - re_sign_char = *p_re; - ++p_re; - --n_re_digits; - } - if (*p_im == '-') { - im_sign_char = *p_im; - ++p_im; - --n_im_digits; - } - - /* Determine if we have any "remainder" (after the digits, might include - decimal or exponent or both (or neither)) */ - parse_number(p_re, n_re_digits, &n_re_remainder, &re_has_decimal); - parse_number(p_im, n_im_digits, &n_im_remainder, &im_has_decimal); - - /* Determine the grouping, separator, and decimal point, if any. */ - get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), - &locale); - - /* Turn off any padding. We'll do it later after we've composed - the numbers without padding. */ - tmp_format.fill_char = '\0'; - tmp_format.align = '<'; - tmp_format.width = -1; - - /* Calculate how much memory we'll need. */ - n_re_total = calc_number_widths(&re_spec, 0, re_sign_char, p_re, - n_re_digits, n_re_remainder, - re_has_decimal, &locale, &tmp_format); - - /* Same formatting, but always include a sign, unless the real part is - * going to be omitted, in which case we use whatever sign convention was - * requested by the original format. */ - if (!skip_re) - tmp_format.sign = '+'; - n_im_total = calc_number_widths(&im_spec, 0, im_sign_char, p_im, - n_im_digits, n_im_remainder, - im_has_decimal, &locale, &tmp_format); - - if (skip_re) - n_re_total = 0; - - /* Add 1 for the 'j', and optionally 2 for parens. */ - calc_padding(n_re_total + n_im_total + 1 + add_parens * 2, - format->width, format->align, &lpad, &rpad, &total); - - result = STRINGLIB_NEW(NULL, total); - if (result == NULL) - goto done; - - /* Populate the memory. First, the padding. */ - p = fill_padding(STRINGLIB_STR(result), - n_re_total + n_im_total + 1 + add_parens * 2, - format->fill_char=='\0' ? ' ' : format->fill_char, - lpad, rpad); - - if (add_parens) - *p++ = '('; - - if (!skip_re) { - fill_number(p, &re_spec, p_re, n_re_digits, NULL, 0, &locale, 0); - p += n_re_total; - } - fill_number(p, &im_spec, p_im, n_im_digits, NULL, 0, &locale, 0); - p += n_im_total; - *p++ = 'j'; - - if (add_parens) - *p++ = ')'; - -done: - PyMem_Free(re_buf); - PyMem_Free(im_buf); -#if STRINGLIB_IS_UNICODE - PyMem_Free(re_unicode_tmp); - PyMem_Free(im_unicode_tmp); -#endif - return result; -} -#endif /* FORMAT_COMPLEX */ - -/************************************************************************/ -/*********** built in formatters ****************************************/ -/************************************************************************/ -PyObject * -FORMAT_STRING(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - InternalFormatSpec format; - PyObject *result = NULL; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, format_spec_len, - &format, 's', '<')) - goto done; - - /* type conversion? */ - switch (format.type) { - case 's': - /* no type conversion needed, already a string. do the formatting */ - result = format_string_internal(obj, &format); - break; - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -done: - return result; -} - -#if defined FORMAT_LONG || defined FORMAT_INT -static PyObject* -format_int_or_long(PyObject* obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len, - IntOrLongToString tostring) -{ - PyObject *result = NULL; - PyObject *tmp = NULL; - InternalFormatSpec format; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, - format_spec_len, - &format, 'd', '>')) - goto done; - - /* type conversion? */ - switch (format.type) { - case 'b': - case 'c': - case 'd': - case 'o': - case 'x': - case 'X': - case 'n': - /* no type conversion needed, already an int (or long). do - the formatting */ - result = format_int_or_long_internal(obj, &format, tostring); - break; - - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case '%': - /* convert to float */ - tmp = PyNumber_Float(obj); - if (tmp == NULL) - goto done; - result = format_float_internal(tmp, &format); - break; - - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -done: - Py_XDECREF(tmp); - return result; -} -#endif /* FORMAT_LONG || defined FORMAT_INT */ - -#ifdef FORMAT_LONG -/* Need to define long_format as a function that will convert a long - to a string. In 3.0, _PyLong_Format has the correct signature. In - 2.x, we need to fudge a few parameters */ -#if PY_VERSION_HEX >= 0x03000000 -#define long_format _PyLong_Format -#else -static PyObject* -long_format(PyObject* value, int base) -{ - /* Convert to base, don't add trailing 'L', and use the new octal - format. We already know this is a long object */ - assert(PyLong_Check(value)); - /* convert to base, don't add 'L', and use the new octal format */ - return _PyLong_Format(value, base, 0, 1); -} -#endif - -PyObject * -FORMAT_LONG(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - return format_int_or_long(obj, format_spec, format_spec_len, - long_format); -} -#endif /* FORMAT_LONG */ - -#ifdef FORMAT_INT -/* this is only used for 2.x, not 3.0 */ -static PyObject* -int_format(PyObject* value, int base) -{ - /* Convert to base, and use the new octal format. We already - know this is an int object */ - assert(PyInt_Check(value)); - return _PyInt_Format((PyIntObject*)value, base, 1); -} - -PyObject * -FORMAT_INT(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - return format_int_or_long(obj, format_spec, format_spec_len, - int_format); -} -#endif /* FORMAT_INT */ - -#ifdef FORMAT_FLOAT -PyObject * -FORMAT_FLOAT(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - PyObject *result = NULL; - InternalFormatSpec format; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, - format_spec_len, - &format, '\0', '>')) - goto done; - - /* type conversion? */ - switch (format.type) { - case '\0': /* No format code: like 'g', but with at least one decimal. */ - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case 'n': - case '%': - /* no conversion, already a float. do the formatting */ - result = format_float_internal(obj, &format); - break; - - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -done: - return result; -} -#endif /* FORMAT_FLOAT */ - -#ifdef FORMAT_COMPLEX -PyObject * -FORMAT_COMPLEX(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - PyObject *result = NULL; - InternalFormatSpec format; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, - format_spec_len, - &format, '\0', '>')) - goto done; - - /* type conversion? */ - switch (format.type) { - case '\0': /* No format code: like 'g', but with at least one decimal. */ - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case 'n': - /* no conversion, already a complex. do the formatting */ - result = format_complex_internal(obj, &format); - break; - - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -done: - return result; -} -#endif /* FORMAT_COMPLEX */ diff --git a/Objects/stringlib/localeutil.h b/Objects/stringlib/localeutil.h index f548133875..6e2f07342c 100644 --- a/Objects/stringlib/localeutil.h +++ b/Objects/stringlib/localeutil.h @@ -1,21 +1,19 @@ /* stringlib: locale related helpers implementation */ -#ifndef STRINGLIB_LOCALEUTIL_H -#define STRINGLIB_LOCALEUTIL_H - #include <locale.h> -#define MAX(x, y) ((x) < (y) ? (y) : (x)) -#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#ifndef STRINGLIB_IS_UNICODE +# error "localeutil is specific to Unicode" +#endif typedef struct { const char *grouping; char previous; Py_ssize_t i; /* Where we're currently pointing in grouping. */ -} GroupGenerator; +} STRINGLIB(GroupGenerator); static void -_GroupGenerator_init(GroupGenerator *self, const char *grouping) +STRINGLIB(GroupGenerator_init)(STRINGLIB(GroupGenerator) *self, const char *grouping) { self->grouping = grouping; self->i = 0; @@ -24,7 +22,7 @@ _GroupGenerator_init(GroupGenerator *self, const char *grouping) /* Returns the next grouping, or 0 to signify end. */ static Py_ssize_t -_GroupGenerator_next(GroupGenerator *self) +STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self) { /* Note that we don't really do much error checking here. If a grouping string contains just CHAR_MAX, for example, then just @@ -48,27 +46,18 @@ _GroupGenerator_next(GroupGenerator *self) /* Fill in some digits, leading zeros, and thousands separator. All are optional, depending on when we're called. */ static void -fill(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end, - Py_ssize_t n_chars, Py_ssize_t n_zeros, const char* thousands_sep, +STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end, + Py_ssize_t n_chars, Py_ssize_t n_zeros, STRINGLIB_CHAR* thousands_sep, Py_ssize_t thousands_sep_len) { -#if STRINGLIB_IS_UNICODE Py_ssize_t i; -#endif if (thousands_sep) { *buffer_end -= thousands_sep_len; /* Copy the thousands_sep chars into the buffer. */ -#if STRINGLIB_IS_UNICODE - /* Convert from the char's of the thousands_sep from - the locale into unicode. */ - for (i = 0; i < thousands_sep_len; ++i) - (*buffer_end)[i] = thousands_sep[i]; -#else - /* No conversion, just memcpy the thousands_sep. */ - memcpy(*buffer_end, thousands_sep, thousands_sep_len); -#endif + memcpy(*buffer_end, thousands_sep, + thousands_sep_len * STRINGLIB_SIZEOF_CHAR); } *buffer_end -= n_chars; @@ -76,11 +65,12 @@ fill(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end, memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR)); *buffer_end -= n_zeros; - STRINGLIB_FILL(*buffer_end, '0', n_zeros); + for (i = 0; i < n_zeros; i++) + (*buffer_end)[i] = '0'; } /** - * _Py_InsertThousandsGrouping: + * InsertThousandsGrouping: * @buffer: A pointer to the start of a string. * @n_buffer: Number of characters in @buffer. * @digits: A pointer to the digits we're reading from. If count @@ -109,14 +99,16 @@ fill(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end, * As closely as possible, this code mimics the logic in decimal.py's _insert_thousands_sep(). **/ -Py_ssize_t -_Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, - Py_ssize_t n_buffer, - STRINGLIB_CHAR *digits, - Py_ssize_t n_digits, - Py_ssize_t min_width, - const char *grouping, - const char *thousands_sep) +static Py_ssize_t +STRINGLIB(InsertThousandsGrouping)( + STRINGLIB_CHAR *buffer, + Py_ssize_t n_buffer, + STRINGLIB_CHAR *digits, + Py_ssize_t n_digits, + Py_ssize_t min_width, + const char *grouping, + STRINGLIB_CHAR *thousands_sep, + Py_ssize_t thousands_sep_len) { Py_ssize_t count = 0; Py_ssize_t n_zeros; @@ -128,23 +120,22 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, STRINGLIB_CHAR *digits_end = NULL; Py_ssize_t l; Py_ssize_t n_chars; - Py_ssize_t thousands_sep_len = strlen(thousands_sep); Py_ssize_t remaining = n_digits; /* Number of chars remaining to be looked at */ /* A generator that returns all of the grouping widths, until it returns 0. */ - GroupGenerator groupgen; - _GroupGenerator_init(&groupgen, grouping); + STRINGLIB(GroupGenerator) groupgen; + STRINGLIB(GroupGenerator_init)(&groupgen, grouping); if (buffer) { buffer_end = buffer + n_buffer; digits_end = digits + n_digits; } - while ((l = _GroupGenerator_next(&groupgen)) > 0) { - l = MIN(l, MAX(MAX(remaining, min_width), 1)); - n_zeros = MAX(0, l - remaining); - n_chars = MAX(0, MIN(remaining, l)); + while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) { + l = Py_MIN(l, Py_MAX(Py_MAX(remaining, min_width), 1)); + n_zeros = Py_MAX(0, l - remaining); + n_chars = Py_MAX(0, Py_MIN(remaining, l)); /* Use n_zero zero's and n_chars chars */ @@ -153,7 +144,7 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, if (buffer) { /* Copy into the output buffer. */ - fill(&digits_end, &buffer_end, n_chars, n_zeros, + STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros, use_separator ? thousands_sep : NULL, thousands_sep_len); } @@ -172,41 +163,18 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, if (!loop_broken) { /* We left the loop without using a break statement. */ - l = MAX(MAX(remaining, min_width), 1); - n_zeros = MAX(0, l - remaining); - n_chars = MAX(0, MIN(remaining, l)); + l = Py_MAX(Py_MAX(remaining, min_width), 1); + n_zeros = Py_MAX(0, l - remaining); + n_chars = Py_MAX(0, Py_MIN(remaining, l)); /* Use n_zero zero's and n_chars chars */ count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars; if (buffer) { /* Copy into the output buffer. */ - fill(&digits_end, &buffer_end, n_chars, n_zeros, + STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros, use_separator ? thousands_sep : NULL, thousands_sep_len); } } return count; } -/** - * _Py_InsertThousandsGroupingLocale: - * @buffer: A pointer to the start of a string. - * @n_digits: The number of digits in the string, in which we want - * to put the grouping chars. - * - * Reads thee current locale and calls _Py_InsertThousandsGrouping(). - **/ -Py_ssize_t -_Py_InsertThousandsGroupingLocale(STRINGLIB_CHAR *buffer, - Py_ssize_t n_buffer, - STRINGLIB_CHAR *digits, - Py_ssize_t n_digits, - Py_ssize_t min_width) -{ - struct lconv *locale_data = localeconv(); - const char *grouping = locale_data->grouping; - const char *thousands_sep = locale_data->thousands_sep; - - return _Py_InsertThousandsGrouping(buffer, n_buffer, digits, n_digits, - min_width, grouping, thousands_sep); -} -#endif /* STRINGLIB_LOCALEUTIL_H */ diff --git a/Objects/stringlib/partition.h b/Objects/stringlib/partition.h index 0170bddbf0..40cb5129d5 100644 --- a/Objects/stringlib/partition.h +++ b/Objects/stringlib/partition.h @@ -1,14 +1,11 @@ /* stringlib: partition implementation */ -#ifndef STRINGLIB_PARTITION_H -#define STRINGLIB_PARTITION_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif Py_LOCAL_INLINE(PyObject*) -stringlib_partition(PyObject* str_obj, +STRINGLIB(partition)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len) @@ -25,7 +22,7 @@ stringlib_partition(PyObject* str_obj, if (!out) return NULL; - pos = fastsearch(str, str_len, sep, sep_len, -1, FAST_SEARCH); + pos = FASTSEARCH(str, str_len, sep, sep_len, -1, FAST_SEARCH); if (pos < 0) { #if STRINGLIB_MUTABLE @@ -58,7 +55,7 @@ stringlib_partition(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject*) -stringlib_rpartition(PyObject* str_obj, +STRINGLIB(rpartition)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len) @@ -75,7 +72,7 @@ stringlib_rpartition(PyObject* str_obj, if (!out) return NULL; - pos = fastsearch(str, str_len, sep, sep_len, -1, FAST_RSEARCH); + pos = FASTSEARCH(str, str_len, sep, sep_len, -1, FAST_RSEARCH); if (pos < 0) { #if STRINGLIB_MUTABLE @@ -107,4 +104,3 @@ stringlib_rpartition(PyObject* str_obj, return out; } -#endif diff --git a/Objects/stringlib/split.h b/Objects/stringlib/split.h index 60e77674f0..947dd28e6c 100644 --- a/Objects/stringlib/split.h +++ b/Objects/stringlib/split.h @@ -1,8 +1,5 @@ /* stringlib: split implementation */ -#ifndef STRINGLIB_SPLIT_H -#define STRINGLIB_SPLIT_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif @@ -54,7 +51,7 @@ #define FIX_PREALLOC_SIZE(list) Py_SIZE(list) = count Py_LOCAL_INLINE(PyObject *) -stringlib_split_whitespace(PyObject* str_obj, +STRINGLIB(split_whitespace)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, Py_ssize_t maxcount) { @@ -102,7 +99,7 @@ stringlib_split_whitespace(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_split_char(PyObject* str_obj, +STRINGLIB(split_char)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR ch, Py_ssize_t maxcount) @@ -145,7 +142,7 @@ stringlib_split_char(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_split(PyObject* str_obj, +STRINGLIB(split)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len, Py_ssize_t maxcount) @@ -158,7 +155,7 @@ stringlib_split(PyObject* str_obj, return NULL; } else if (sep_len == 1) - return stringlib_split_char(str_obj, str, str_len, sep[0], maxcount); + return STRINGLIB(split_char)(str_obj, str, str_len, sep[0], maxcount); list = PyList_New(PREALLOC_SIZE(maxcount)); if (list == NULL) @@ -166,7 +163,7 @@ stringlib_split(PyObject* str_obj, i = j = 0; while (maxcount-- > 0) { - pos = fastsearch(str+i, str_len-i, sep, sep_len, -1, FAST_SEARCH); + pos = FASTSEARCH(str+i, str_len-i, sep, sep_len, -1, FAST_SEARCH); if (pos < 0) break; j = i + pos; @@ -193,7 +190,7 @@ stringlib_split(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_rsplit_whitespace(PyObject* str_obj, +STRINGLIB(rsplit_whitespace)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, Py_ssize_t maxcount) { @@ -243,7 +240,7 @@ stringlib_rsplit_whitespace(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_rsplit_char(PyObject* str_obj, +STRINGLIB(rsplit_char)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR ch, Py_ssize_t maxcount) @@ -287,7 +284,7 @@ stringlib_rsplit_char(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_rsplit(PyObject* str_obj, +STRINGLIB(rsplit)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len, Py_ssize_t maxcount) @@ -300,7 +297,7 @@ stringlib_rsplit(PyObject* str_obj, return NULL; } else if (sep_len == 1) - return stringlib_rsplit_char(str_obj, str, str_len, sep[0], maxcount); + return STRINGLIB(rsplit_char)(str_obj, str, str_len, sep[0], maxcount); list = PyList_New(PREALLOC_SIZE(maxcount)); if (list == NULL) @@ -308,7 +305,7 @@ stringlib_rsplit(PyObject* str_obj, j = str_len; while (maxcount-- > 0) { - pos = fastsearch(str, j, sep, sep_len, -1, FAST_RSEARCH); + pos = FASTSEARCH(str, j, sep, sep_len, -1, FAST_RSEARCH); if (pos < 0) break; SPLIT_ADD(str, pos + sep_len, j); @@ -336,7 +333,7 @@ stringlib_rsplit(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_splitlines(PyObject* str_obj, +STRINGLIB(splitlines)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, int keepends) { @@ -391,4 +388,3 @@ stringlib_splitlines(PyObject* str_obj, return NULL; } -#endif diff --git a/Objects/stringlib/stringdefs.h b/Objects/stringlib/stringdefs.h index 1c49426ff6..7bb91a7a5b 100644 --- a/Objects/stringlib/stringdefs.h +++ b/Objects/stringlib/stringdefs.h @@ -6,7 +6,10 @@ compiled as unicode. */ #define STRINGLIB_IS_UNICODE 0 +#define FASTSEARCH fastsearch +#define STRINGLIB(F) stringlib_##F #define STRINGLIB_OBJECT PyBytesObject +#define STRINGLIB_SIZEOF_CHAR 1 #define STRINGLIB_CHAR char #define STRINGLIB_TYPE_NAME "string" #define STRINGLIB_PARSE_CODE "S" @@ -15,9 +18,6 @@ #define STRINGLIB_ISLINEBREAK(x) ((x == '\n') || (x == '\r')) #define STRINGLIB_ISDECIMAL(x) ((x >= '0') && (x <= '9')) #define STRINGLIB_TODECIMAL(x) (STRINGLIB_ISDECIMAL(x) ? (x - '0') : -1) -#define STRINGLIB_TOUPPER Py_TOUPPER -#define STRINGLIB_TOLOWER Py_TOLOWER -#define STRINGLIB_FILL memset #define STRINGLIB_STR PyBytes_AS_STRING #define STRINGLIB_LEN PyBytes_GET_SIZE #define STRINGLIB_NEW PyBytes_FromStringAndSize @@ -25,7 +25,5 @@ #define STRINGLIB_CHECK PyBytes_Check #define STRINGLIB_CHECK_EXACT PyBytes_CheckExact #define STRINGLIB_TOSTR PyObject_Str -#define STRINGLIB_GROUPING _PyBytes_InsertThousandsGrouping -#define STRINGLIB_GROUPING_LOCALE _PyBytes_InsertThousandsGroupingLocale #define STRINGLIB_TOASCII PyObject_Repr #endif /* !STRINGLIB_STRINGDEFS_H */ diff --git a/Objects/stringlib/transmogrify.h b/Objects/stringlib/transmogrify.h index be595a62ef..cbd7144b0e 100644 --- a/Objects/stringlib/transmogrify.h +++ b/Objects/stringlib/transmogrify.h @@ -18,10 +18,10 @@ stringlib_expandtabs(PyObject *self, PyObject *args) Py_ssize_t i, j; PyObject *u; int tabsize = 8; - + if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize)) return NULL; - + /* First pass: determine size of output string */ i = j = 0; e = STRINGLIB_STR(self) + STRINGLIB_LEN(self); @@ -46,15 +46,15 @@ stringlib_expandtabs(PyObject *self, PyObject *args) } } } - + if (i > PY_SSIZE_T_MAX - j) goto overflow; - + /* Second pass: create output string and fill it */ u = STRINGLIB_NEW(NULL, i + j); if (!u) return NULL; - + j = 0; q = STRINGLIB_STR(u); diff --git a/Objects/stringlib/ucs1lib.h b/Objects/stringlib/ucs1lib.h new file mode 100644 index 0000000000..e8c6fcb85f --- /dev/null +++ b/Objects/stringlib/ucs1lib.h @@ -0,0 +1,31 @@ +/* this is sort of a hack. there's at least one place (formatting + floats) where some stringlib code takes a different path if it's + compiled as unicode. */ +#define STRINGLIB_IS_UNICODE 1 + +#define FASTSEARCH ucs1lib_fastsearch +#define STRINGLIB(F) ucs1lib_##F +#define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_SIZEOF_CHAR 1 +#define STRINGLIB_MAX_CHAR 0xFFu +#define STRINGLIB_CHAR Py_UCS1 +#define STRINGLIB_TYPE_NAME "unicode" +#define STRINGLIB_PARSE_CODE "U" +#define STRINGLIB_EMPTY unicode_empty +#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE +#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK +#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL +#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL +#define STRINGLIB_STR PyUnicode_1BYTE_DATA +#define STRINGLIB_LEN PyUnicode_GET_LENGTH +#define STRINGLIB_NEW _PyUnicode_FromUCS1 +#define STRINGLIB_RESIZE not_supported +#define STRINGLIB_CHECK PyUnicode_Check +#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact + +#define STRINGLIB_TOSTR PyObject_Str +#define STRINGLIB_TOASCII PyObject_ASCII + +#define _Py_InsertThousandsGrouping _PyUnicode_ucs1_InsertThousandsGrouping + + diff --git a/Objects/stringlib/ucs2lib.h b/Objects/stringlib/ucs2lib.h new file mode 100644 index 0000000000..45e572963d --- /dev/null +++ b/Objects/stringlib/ucs2lib.h @@ -0,0 +1,30 @@ +/* this is sort of a hack. there's at least one place (formatting + floats) where some stringlib code takes a different path if it's + compiled as unicode. */ +#define STRINGLIB_IS_UNICODE 1 + +#define FASTSEARCH ucs2lib_fastsearch +#define STRINGLIB(F) ucs2lib_##F +#define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_SIZEOF_CHAR 2 +#define STRINGLIB_MAX_CHAR 0xFFFFu +#define STRINGLIB_CHAR Py_UCS2 +#define STRINGLIB_TYPE_NAME "unicode" +#define STRINGLIB_PARSE_CODE "U" +#define STRINGLIB_EMPTY unicode_empty +#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE +#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK +#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL +#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL +#define STRINGLIB_STR PyUnicode_2BYTE_DATA +#define STRINGLIB_LEN PyUnicode_GET_LENGTH +#define STRINGLIB_NEW _PyUnicode_FromUCS2 +#define STRINGLIB_RESIZE not_supported +#define STRINGLIB_CHECK PyUnicode_Check +#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact + +#define STRINGLIB_TOSTR PyObject_Str +#define STRINGLIB_TOASCII PyObject_ASCII + +#define _Py_InsertThousandsGrouping _PyUnicode_ucs2_InsertThousandsGrouping + diff --git a/Objects/stringlib/ucs4lib.h b/Objects/stringlib/ucs4lib.h new file mode 100644 index 0000000000..647a27e233 --- /dev/null +++ b/Objects/stringlib/ucs4lib.h @@ -0,0 +1,30 @@ +/* this is sort of a hack. there's at least one place (formatting + floats) where some stringlib code takes a different path if it's + compiled as unicode. */ +#define STRINGLIB_IS_UNICODE 1 + +#define FASTSEARCH ucs4lib_fastsearch +#define STRINGLIB(F) ucs4lib_##F +#define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_SIZEOF_CHAR 4 +#define STRINGLIB_MAX_CHAR 0x10FFFFu +#define STRINGLIB_CHAR Py_UCS4 +#define STRINGLIB_TYPE_NAME "unicode" +#define STRINGLIB_PARSE_CODE "U" +#define STRINGLIB_EMPTY unicode_empty +#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE +#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK +#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL +#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL +#define STRINGLIB_STR PyUnicode_4BYTE_DATA +#define STRINGLIB_LEN PyUnicode_GET_LENGTH +#define STRINGLIB_NEW _PyUnicode_FromUCS4 +#define STRINGLIB_RESIZE not_supported +#define STRINGLIB_CHECK PyUnicode_Check +#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact + +#define STRINGLIB_TOSTR PyObject_Str +#define STRINGLIB_TOASCII PyObject_ASCII + +#define _Py_InsertThousandsGrouping _PyUnicode_ucs4_InsertThousandsGrouping + diff --git a/Objects/stringlib/undef.h b/Objects/stringlib/undef.h new file mode 100644 index 0000000000..03117ec443 --- /dev/null +++ b/Objects/stringlib/undef.h @@ -0,0 +1,12 @@ +#undef FASTSEARCH +#undef STRINGLIB +#undef STRINGLIB_SIZEOF_CHAR +#undef STRINGLIB_MAX_CHAR +#undef STRINGLIB_CHAR +#undef STRINGLIB_STR +#undef STRINGLIB_LEN +#undef STRINGLIB_NEW +#undef STRINGLIB_RESIZE +#undef _Py_InsertThousandsGrouping +#undef STRINGLIB_IS_UNICODE + diff --git a/Objects/stringlib/string_format.h b/Objects/stringlib/unicode_format.h index c46bdc2656..d4719a578b 100644 --- a/Objects/stringlib/string_format.h +++ b/Objects/stringlib/unicode_format.h @@ -1,22 +1,7 @@ /* - string_format.h -- implementation of string.format(). - - It uses the Objects/stringlib conventions, so that it can be - compiled for both unicode and string objects. + unicode_format.h -- implementation of str.format(). */ - -/* Defines for Python 2.6 compatibility */ -#if PY_VERSION_HEX < 0x03000000 -#define PyLong_FromSsize_t _PyLong_FromSsize_t -#endif - -/* Defines for more efficiently reallocating the string buffer */ -#define INITIAL_SIZE_INCREMENT 100 -#define SIZE_MULTIPLIER 2 -#define MAX_SIZE_INCREMENT 3200 - - /************************************************************************/ /*********** Global data structures and forward declarations *********/ /************************************************************************/ @@ -26,8 +11,8 @@ unicode pointers. */ typedef struct { - STRINGLIB_CHAR *ptr; - STRINGLIB_CHAR *end; + PyObject *str; /* borrowed reference */ + Py_ssize_t start, end; } SubString; @@ -64,34 +49,32 @@ AutoNumber_Init(AutoNumber *auto_number) /* fill in a SubString from a pointer and length */ Py_LOCAL_INLINE(void) -SubString_init(SubString *str, STRINGLIB_CHAR *p, Py_ssize_t len) +SubString_init(SubString *str, PyObject *s, Py_ssize_t start, Py_ssize_t end) { - str->ptr = p; - if (p == NULL) - str->end = NULL; - else - str->end = str->ptr + len; + str->str = s; + str->start = start; + str->end = end; } -/* return a new string. if str->ptr is NULL, return None */ +/* return a new string. if str->str is NULL, return None */ Py_LOCAL_INLINE(PyObject *) SubString_new_object(SubString *str) { - if (str->ptr == NULL) { + if (str->str == NULL) { Py_INCREF(Py_None); return Py_None; } - return STRINGLIB_NEW(str->ptr, str->end - str->ptr); + return PyUnicode_Substring(str->str, str->start, str->end); } -/* return a new string. if str->ptr is NULL, return None */ +/* return a new string. if str->str is NULL, return None */ Py_LOCAL_INLINE(PyObject *) SubString_new_object_or_empty(SubString *str) { - if (str->ptr == NULL) { - return STRINGLIB_NEW(NULL, 0); + if (str->str == NULL) { + return PyUnicode_New(0, 0); } - return STRINGLIB_NEW(str->ptr, str->end - str->ptr); + return SubString_new_object(str); } /* Return 1 if an error has been detected switching between automatic @@ -121,74 +104,6 @@ autonumber_state_error(AutoNumberState state, int field_name_is_empty) /************************************************************************/ -/*********** Output string management functions ****************/ -/************************************************************************/ - -typedef struct { - STRINGLIB_CHAR *ptr; - STRINGLIB_CHAR *end; - PyObject *obj; - Py_ssize_t size_increment; -} OutputString; - -/* initialize an OutputString object, reserving size characters */ -static int -output_initialize(OutputString *output, Py_ssize_t size) -{ - output->obj = STRINGLIB_NEW(NULL, size); - if (output->obj == NULL) - return 0; - - output->ptr = STRINGLIB_STR(output->obj); - output->end = STRINGLIB_LEN(output->obj) + output->ptr; - output->size_increment = INITIAL_SIZE_INCREMENT; - - return 1; -} - -/* - output_extend reallocates the output string buffer. - It returns a status: 0 for a failed reallocation, - 1 for success. -*/ - -static int -output_extend(OutputString *output, Py_ssize_t count) -{ - STRINGLIB_CHAR *startptr = STRINGLIB_STR(output->obj); - Py_ssize_t curlen = output->ptr - startptr; - Py_ssize_t maxlen = curlen + count + output->size_increment; - - if (STRINGLIB_RESIZE(&output->obj, maxlen) < 0) - return 0; - startptr = STRINGLIB_STR(output->obj); - output->ptr = startptr + curlen; - output->end = startptr + maxlen; - if (output->size_increment < MAX_SIZE_INCREMENT) - output->size_increment *= SIZE_MULTIPLIER; - return 1; -} - -/* - output_data dumps characters into our output string - buffer. - - In some cases, it has to reallocate the string. - - It returns a status: 0 for a failed reallocation, - 1 for success. -*/ -static int -output_data(OutputString *output, const STRINGLIB_CHAR *s, Py_ssize_t count) -{ - if ((count > output->end - output->ptr) && !output_extend(output, count)) - return 0; - memcpy(output->ptr, s, count * sizeof(STRINGLIB_CHAR)); - output->ptr += count; - return 1; -} - -/************************************************************************/ /*********** Format string parsing -- integers and identifiers *********/ /************************************************************************/ @@ -197,14 +112,14 @@ get_integer(const SubString *str) { Py_ssize_t accumulator = 0; Py_ssize_t digitval; - STRINGLIB_CHAR *p; + Py_ssize_t i; /* empty string is an error */ - if (str->ptr >= str->end) + if (str->start >= str->end) return -1; - for (p = str->ptr; p < str->end; p++) { - digitval = STRINGLIB_TODECIMAL(*p); + for (i = str->start; i < str->end; i++) { + digitval = Py_UNICODE_TODECIMAL(PyUnicode_READ_CHAR(str->str, i)); if (digitval < 0) return -1; /* @@ -279,34 +194,36 @@ typedef struct { lifetime of the iterator. can be empty */ SubString str; - /* pointer to where we are inside field_name */ - STRINGLIB_CHAR *ptr; + /* index to where we are inside field_name */ + Py_ssize_t index; } FieldNameIterator; static int -FieldNameIterator_init(FieldNameIterator *self, STRINGLIB_CHAR *ptr, - Py_ssize_t len) +FieldNameIterator_init(FieldNameIterator *self, PyObject *s, + Py_ssize_t start, Py_ssize_t end) { - SubString_init(&self->str, ptr, len); - self->ptr = self->str.ptr; + SubString_init(&self->str, s, start, end); + self->index = start; return 1; } static int _FieldNameIterator_attr(FieldNameIterator *self, SubString *name) { - STRINGLIB_CHAR c; + Py_UCS4 c; - name->ptr = self->ptr; + name->str = self->str.str; + name->start = self->index; /* return everything until '.' or '[' */ - while (self->ptr < self->str.end) { - switch (c = *self->ptr++) { + while (self->index < self->str.end) { + c = PyUnicode_READ_CHAR(self->str.str, self->index++); + switch (c) { case '[': case '.': /* backup so that we this character will be seen next time */ - self->ptr--; + self->index--; break; default: continue; @@ -314,7 +231,7 @@ _FieldNameIterator_attr(FieldNameIterator *self, SubString *name) break; } /* end of string is okay */ - name->end = self->ptr; + name->end = self->index; return 1; } @@ -322,13 +239,15 @@ static int _FieldNameIterator_item(FieldNameIterator *self, SubString *name) { int bracket_seen = 0; - STRINGLIB_CHAR c; + Py_UCS4 c; - name->ptr = self->ptr; + name->str = self->str.str; + name->start = self->index; /* return everything until ']' */ - while (self->ptr < self->str.end) { - switch (c = *self->ptr++) { + while (self->index < self->str.end) { + c = PyUnicode_READ_CHAR(self->str.str, self->index++); + switch (c) { case ']': bracket_seen = 1; break; @@ -345,7 +264,7 @@ _FieldNameIterator_item(FieldNameIterator *self, SubString *name) /* end of string is okay */ /* don't include the ']' */ - name->end = self->ptr-1; + name->end = self->index-1; return 1; } @@ -355,10 +274,10 @@ FieldNameIterator_next(FieldNameIterator *self, int *is_attribute, Py_ssize_t *name_idx, SubString *name) { /* check at end of input */ - if (self->ptr >= self->str.end) + if (self->index >= self->str.end) return 1; - switch (*self->ptr++) { + switch (PyUnicode_READ_CHAR(self->str.str, self->index++)) { case '.': *is_attribute = 1; if (_FieldNameIterator_attr(self, name) == 0) @@ -381,7 +300,7 @@ FieldNameIterator_next(FieldNameIterator *self, int *is_attribute, } /* empty string is an error */ - if (name->ptr == name->end) { + if (name->start == name->end) { PyErr_SetString(PyExc_ValueError, "Empty attribute in format string"); return 0; } @@ -397,24 +316,23 @@ FieldNameIterator_next(FieldNameIterator *self, int *is_attribute, 'rest' is an iterator to return the rest */ static int -field_name_split(STRINGLIB_CHAR *ptr, Py_ssize_t len, SubString *first, +field_name_split(PyObject *str, Py_ssize_t start, Py_ssize_t end, SubString *first, Py_ssize_t *first_idx, FieldNameIterator *rest, AutoNumber *auto_number) { - STRINGLIB_CHAR c; - STRINGLIB_CHAR *p = ptr; - STRINGLIB_CHAR *end = ptr + len; + Py_UCS4 c; + Py_ssize_t i = start; int field_name_is_empty; int using_numeric_index; /* find the part up until the first '.' or '[' */ - while (p < end) { - switch (c = *p++) { + while (i < end) { + switch (c = PyUnicode_READ_CHAR(str, i++)) { case '[': case '.': /* backup so that we this character is available to the "rest" iterator */ - p--; + i--; break; default: continue; @@ -423,15 +341,15 @@ field_name_split(STRINGLIB_CHAR *ptr, Py_ssize_t len, SubString *first, } /* set up the return values */ - SubString_init(first, ptr, p - ptr); - FieldNameIterator_init(rest, p, end - p); + SubString_init(first, str, start, i); + FieldNameIterator_init(rest, str, i, end); /* see if "first" is an integer, in which case it's used as an index */ *first_idx = get_integer(first); if (*first_idx == -1 && PyErr_Occurred()) return 0; - field_name_is_empty = first->ptr >= first->end; + field_name_is_empty = first->start >= first->end; /* If the field name is omitted or if we have a numeric index specified, then we're doing numeric indexing into args. */ @@ -486,7 +404,7 @@ get_field_object(SubString *input, PyObject *args, PyObject *kwargs, Py_ssize_t index; FieldNameIterator rest; - if (!field_name_split(input->ptr, input->end - input->ptr, &first, + if (!field_name_split(input->str, input->start, input->end, &first, &index, &rest, auto_number)) { goto error; } @@ -570,39 +488,41 @@ error: appends to the output. */ static int -render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output) +render_field(PyObject *fieldobj, SubString *format_spec, _PyUnicodeWriter *writer) { int ok = 0; PyObject *result = NULL; PyObject *format_spec_object = NULL; - PyObject *(*formatter)(PyObject *, STRINGLIB_CHAR *, Py_ssize_t) = NULL; - STRINGLIB_CHAR* format_spec_start = format_spec->ptr ? - format_spec->ptr : NULL; - Py_ssize_t format_spec_len = format_spec->ptr ? - format_spec->end - format_spec->ptr : 0; + int (*formatter) (_PyUnicodeWriter*, PyObject *, PyObject *, Py_ssize_t, Py_ssize_t) = NULL; + int err; /* If we know the type exactly, skip the lookup of __format__ and just call the formatter directly. */ if (PyUnicode_CheckExact(fieldobj)) - formatter = _PyUnicode_FormatAdvanced; + formatter = _PyUnicode_FormatAdvancedWriter; else if (PyLong_CheckExact(fieldobj)) - formatter =_PyLong_FormatAdvanced; + formatter = _PyLong_FormatAdvancedWriter; else if (PyFloat_CheckExact(fieldobj)) - formatter = _PyFloat_FormatAdvanced; - - /* XXX: for 2.6, convert format_spec to the appropriate type - (unicode, str) */ + formatter = _PyFloat_FormatAdvancedWriter; + else if (PyComplex_CheckExact(fieldobj)) + formatter = _PyComplex_FormatAdvancedWriter; if (formatter) { /* we know exactly which formatter will be called when __format__ is looked up, so call it directly, instead. */ - result = formatter(fieldobj, format_spec_start, format_spec_len); + err = formatter(writer, fieldobj, format_spec->str, + format_spec->start, format_spec->end); + return (err == 0); } else { /* We need to create an object out of the pointers we have, because __format__ takes a string/unicode object for format_spec. */ - format_spec_object = STRINGLIB_NEW(format_spec_start, - format_spec_len); + if (format_spec->str) + format_spec_object = PyUnicode_Substring(format_spec->str, + format_spec->start, + format_spec->end); + else + format_spec_object = PyUnicode_New(0, 0); if (format_spec_object == NULL) goto done; @@ -611,24 +531,10 @@ render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output) if (result == NULL) goto done; -#if PY_VERSION_HEX >= 0x03000000 - assert(PyUnicode_Check(result)); -#else - assert(PyBytes_Check(result) || PyUnicode_Check(result)); - - /* Convert result to our type. We could be str, and result could - be unicode */ - { - PyObject *tmp = STRINGLIB_TOSTR(result); - if (tmp == NULL) - goto done; - Py_DECREF(result); - result = tmp; - } -#endif + if (_PyUnicodeWriter_WriteStr(writer, result) == -1) + goto done; + ok = 1; - ok = output_data(output, - STRINGLIB_STR(result), STRINGLIB_LEN(result)); done: Py_XDECREF(format_spec_object); Py_XDECREF(result); @@ -637,23 +543,24 @@ done: static int parse_field(SubString *str, SubString *field_name, SubString *format_spec, - STRINGLIB_CHAR *conversion) + Py_UCS4 *conversion) { /* Note this function works if the field name is zero length, which is good. Zero length field names are handled later, in field_name_split. */ - STRINGLIB_CHAR c = 0; + Py_UCS4 c = 0; /* initialize these, as they may be empty */ *conversion = '\0'; - SubString_init(format_spec, NULL, 0); + SubString_init(format_spec, NULL, 0, 0); /* Search for the field name. it's terminated by the end of the string, or a ':' or '!' */ - field_name->ptr = str->ptr; - while (str->ptr < str->end) { - switch (c = *(str->ptr++)) { + field_name->str = str->str; + field_name->start = str->start; + while (str->start < str->end) { + switch ((c = PyUnicode_READ_CHAR(str->str, str->start++))) { case ':': case '!': break; @@ -666,26 +573,27 @@ parse_field(SubString *str, SubString *field_name, SubString *format_spec, if (c == '!' || c == ':') { /* we have a format specifier and/or a conversion */ /* don't include the last character */ - field_name->end = str->ptr-1; + field_name->end = str->start-1; /* the format specifier is the rest of the string */ - format_spec->ptr = str->ptr; + format_spec->str = str->str; + format_spec->start = str->start; format_spec->end = str->end; /* see if there's a conversion specifier */ if (c == '!') { /* there must be another character present */ - if (format_spec->ptr >= format_spec->end) { + if (format_spec->start >= format_spec->end) { PyErr_SetString(PyExc_ValueError, "end of format while looking for conversion " "specifier"); return 0; } - *conversion = *(format_spec->ptr++); + *conversion = PyUnicode_READ_CHAR(format_spec->str, format_spec->start++); /* if there is another character, it must be a colon */ - if (format_spec->ptr < format_spec->end) { - c = *(format_spec->ptr++); + if (format_spec->start < format_spec->end) { + c = PyUnicode_READ_CHAR(format_spec->str, format_spec->start++); if (c != ':') { PyErr_SetString(PyExc_ValueError, "expected ':' after format specifier"); @@ -696,7 +604,7 @@ parse_field(SubString *str, SubString *field_name, SubString *format_spec, } else /* end of string, there's no format_spec or conversion */ - field_name->end = str->ptr; + field_name->end = str->start; return 1; } @@ -715,9 +623,10 @@ typedef struct { } MarkupIterator; static int -MarkupIterator_init(MarkupIterator *self, STRINGLIB_CHAR *ptr, Py_ssize_t len) +MarkupIterator_init(MarkupIterator *self, PyObject *str, + Py_ssize_t start, Py_ssize_t end) { - SubString_init(&self->str, ptr, len); + SubString_init(&self->str, str, start, end); return 1; } @@ -726,30 +635,30 @@ MarkupIterator_init(MarkupIterator *self, STRINGLIB_CHAR *ptr, Py_ssize_t len) static int MarkupIterator_next(MarkupIterator *self, SubString *literal, int *field_present, SubString *field_name, - SubString *format_spec, STRINGLIB_CHAR *conversion, + SubString *format_spec, Py_UCS4 *conversion, int *format_spec_needs_expanding) { - int at_end; - STRINGLIB_CHAR c = 0; - STRINGLIB_CHAR *start; + int at_end, hit_format_spec; + Py_UCS4 c = 0; + Py_ssize_t start; int count; Py_ssize_t len; int markup_follows = 0; /* initialize all of the output variables */ - SubString_init(literal, NULL, 0); - SubString_init(field_name, NULL, 0); - SubString_init(format_spec, NULL, 0); + SubString_init(literal, NULL, 0, 0); + SubString_init(field_name, NULL, 0, 0); + SubString_init(format_spec, NULL, 0, 0); *conversion = '\0'; *format_spec_needs_expanding = 0; *field_present = 0; /* No more input, end of iterator. This is the normal exit path. */ - if (self->str.ptr >= self->str.end) + if (self->str.start >= self->str.end) return 1; - start = self->str.ptr; + start = self->str.start; /* First read any literal text. Read until the end of string, an escaped '{' or '}', or an unescaped '{'. In order to never @@ -758,8 +667,8 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, including the brace, but no format object. The next time through, we'll return the rest of the literal, skipping past the second consecutive brace. */ - while (self->str.ptr < self->str.end) { - switch (c = *(self->str.ptr++)) { + while (self->str.start < self->str.end) { + switch (c = PyUnicode_READ_CHAR(self->str.str, self->str.start++)) { case '{': case '}': markup_follows = 1; @@ -770,10 +679,12 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, break; } - at_end = self->str.ptr >= self->str.end; - len = self->str.ptr - start; + at_end = self->str.start >= self->str.end; + len = self->str.start - start; - if ((c == '}') && (at_end || (c != *self->str.ptr))) { + if ((c == '}') && (at_end || + (c != PyUnicode_READ_CHAR(self->str.str, + self->str.start)))) { PyErr_SetString(PyExc_ValueError, "Single '}' encountered " "in format string"); return 0; @@ -784,10 +695,10 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, return 0; } if (!at_end) { - if (c == *self->str.ptr) { + if (c == PyUnicode_READ_CHAR(self->str.str, self->str.start)) { /* escaped } or {, skip it in the input. there is no markup object following us, just this literal text */ - self->str.ptr++; + self->str.start++; markup_follows = 0; } else @@ -795,7 +706,8 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, } /* record the literal text */ - literal->ptr = start; + literal->str = self->str.str; + literal->start = start; literal->end = start + len; if (!markup_follows) @@ -807,16 +719,24 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, *field_present = 1; count = 1; - start = self->str.ptr; + start = self->str.start; /* we know we can't have a zero length string, so don't worry about that case */ - while (self->str.ptr < self->str.end) { - switch (c = *(self->str.ptr++)) { + hit_format_spec = 0; + while (self->str.start < self->str.end) { + switch (c = PyUnicode_READ_CHAR(self->str.str, self->str.start++)) { + case ':': + if (!hit_format_spec) { + count = 1; + hit_format_spec = 1; + } + break; case '{': /* the format spec needs to be recursively expanded. this is an optimization, and not strictly needed */ - *format_spec_needs_expanding = 1; + if (hit_format_spec) + *format_spec_needs_expanding = 1; count++; break; case '}': @@ -825,7 +745,7 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, /* we're done. parse and get out */ SubString s; - SubString_init(&s, start, self->str.ptr - 1 - start); + SubString_init(&s, self->str.str, start, self->str.start - 1); if (parse_field(&s, field_name, format_spec, conversion) == 0) return 0; @@ -844,7 +764,7 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, /* do the !r or !s conversion on obj */ static PyObject * -do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) +do_conversion(PyObject *obj, Py_UCS4 conversion) { /* XXX in pre-3.0, do we need to convert this to unicode, since it might have returned a string? */ @@ -852,11 +772,9 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) case 'r': return PyObject_Repr(obj); case 's': - return STRINGLIB_TOSTR(obj); -#if PY_VERSION_HEX >= 0x03000000 + return PyObject_Str(obj); case 'a': - return STRINGLIB_TOASCII(obj); -#endif + return PyObject_ASCII(obj); default: if (conversion > 32 && conversion < 127) { /* It's the ASCII subrange; casting to char is safe @@ -888,8 +806,8 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) static int output_markup(SubString *field_name, SubString *format_spec, - int format_spec_needs_expanding, STRINGLIB_CHAR conversion, - OutputString *output, PyObject *args, PyObject *kwargs, + int format_spec_needs_expanding, Py_UCS4 conversion, + _PyUnicodeWriter *writer, PyObject *args, PyObject *kwargs, int recursion_depth, AutoNumber *auto_number) { PyObject *tmp = NULL; @@ -905,7 +823,7 @@ output_markup(SubString *field_name, SubString *format_spec, if (conversion != '\0') { tmp = do_conversion(fieldobj, conversion); - if (tmp == NULL) + if (tmp == NULL || PyUnicode_READY(tmp) == -1) goto done; /* do the assignment, transferring ownership: fieldobj = tmp */ @@ -918,20 +836,19 @@ output_markup(SubString *field_name, SubString *format_spec, if (format_spec_needs_expanding) { tmp = build_string(format_spec, args, kwargs, recursion_depth-1, auto_number); - if (tmp == NULL) + if (tmp == NULL || PyUnicode_READY(tmp) == -1) goto done; /* note that in the case we're expanding the format string, tmp must be kept around until after the call to render_field. */ - SubString_init(&expanded_format_spec, - STRINGLIB_STR(tmp), STRINGLIB_LEN(tmp)); + SubString_init(&expanded_format_spec, tmp, 0, PyUnicode_GET_LENGTH(tmp)); actual_format_spec = &expanded_format_spec; } else actual_format_spec = format_spec; - if (render_field(fieldobj, actual_format_spec, output) == 0) + if (render_field(fieldobj, actual_format_spec, writer) == 0) goto done; result = 1; @@ -951,7 +868,7 @@ done: */ static int do_markup(SubString *input, PyObject *args, PyObject *kwargs, - OutputString *output, int recursion_depth, AutoNumber *auto_number) + _PyUnicodeWriter *writer, int recursion_depth, AutoNumber *auto_number) { MarkupIterator iter; int format_spec_needs_expanding; @@ -960,20 +877,35 @@ do_markup(SubString *input, PyObject *args, PyObject *kwargs, SubString literal; SubString field_name; SubString format_spec; - STRINGLIB_CHAR conversion; + Py_UCS4 conversion, maxchar; + Py_ssize_t sublen; + int err; - MarkupIterator_init(&iter, input->ptr, input->end - input->ptr); + MarkupIterator_init(&iter, input->str, input->start, input->end); while ((result = MarkupIterator_next(&iter, &literal, &field_present, &field_name, &format_spec, &conversion, &format_spec_needs_expanding)) == 2) { - if (!output_data(output, literal.ptr, literal.end - literal.ptr)) - return 0; - if (field_present) + sublen = literal.end - literal.start; + if (sublen) { + maxchar = _PyUnicode_FindMaxChar(literal.str, + literal.start, literal.end); + err = _PyUnicodeWriter_Prepare(writer, sublen, maxchar); + if (err == -1) + return 0; + _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, + literal.str, literal.start, sublen); + writer->pos += sublen; + } + + if (field_present) { + if (iter.str.start == iter.str.end) + writer->overallocate = 0; if (!output_markup(&field_name, &format_spec, - format_spec_needs_expanding, conversion, output, + format_spec_needs_expanding, conversion, writer, args, kwargs, recursion_depth, auto_number)) return 0; + } } return result; } @@ -987,43 +919,26 @@ static PyObject * build_string(SubString *input, PyObject *args, PyObject *kwargs, int recursion_depth, AutoNumber *auto_number) { - OutputString output; - PyObject *result = NULL; - Py_ssize_t count; - - output.obj = NULL; /* needed so cleanup code always works */ + _PyUnicodeWriter writer; + Py_ssize_t minlen; /* check the recursion level */ if (recursion_depth <= 0) { PyErr_SetString(PyExc_ValueError, "Max string recursion exceeded"); - goto done; + return NULL; } - /* initial size is the length of the format string, plus the size - increment. seems like a reasonable default */ - if (!output_initialize(&output, - input->end - input->ptr + - INITIAL_SIZE_INCREMENT)) - goto done; + minlen = PyUnicode_GET_LENGTH(input->str) + 100; + _PyUnicodeWriter_Init(&writer, minlen); - if (!do_markup(input, args, kwargs, &output, recursion_depth, + if (!do_markup(input, args, kwargs, &writer, recursion_depth, auto_number)) { - goto done; - } - - count = output.ptr - STRINGLIB_STR(output.obj); - if (STRINGLIB_RESIZE(&output.obj, count) < 0) { - goto done; + _PyUnicodeWriter_Dealloc(&writer); + return NULL; } - /* transfer ownership to result */ - result = output.obj; - output.obj = NULL; - -done: - Py_XDECREF(output.obj); - return result; + return _PyUnicodeWriter_Finish(&writer); } /************************************************************************/ @@ -1044,8 +959,11 @@ do_string_format(PyObject *self, PyObject *args, PyObject *kwargs) AutoNumber auto_number; + if (PyUnicode_READY(self) == -1) + return NULL; + AutoNumber_Init(&auto_number); - SubString_init(&input, STRINGLIB_STR(self), STRINGLIB_LEN(self)); + SubString_init(&input, self, 0, PyUnicode_GET_LENGTH(self)); return build_string(&input, args, kwargs, recursion_depth, &auto_number); } @@ -1067,9 +985,7 @@ do_string_format_map(PyObject *self, PyObject *obj) typedef struct { PyObject_HEAD - - STRINGLIB_OBJECT *str; - + PyObject *str; MarkupIterator it_markup; } formatteriterobject; @@ -1094,7 +1010,7 @@ formatteriter_next(formatteriterobject *it) SubString literal; SubString field_name; SubString format_spec; - STRINGLIB_CHAR conversion; + Py_UCS4 conversion; int format_spec_needs_expanding; int field_present; int result = MarkupIterator_next(&it->it_markup, &literal, &field_present, @@ -1138,7 +1054,8 @@ formatteriter_next(formatteriterobject *it) Py_INCREF(conversion_str); } else - conversion_str = STRINGLIB_NEW(&conversion, 1); + conversion_str = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, + &conversion, 1); if (conversion_str == NULL) goto done; @@ -1195,7 +1112,7 @@ static PyTypeObject PyFormatterIter_Type = { describing the parsed elements. It's a wrapper around stringlib/string_format.h's MarkupIterator */ static PyObject * -formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) +formatter_parser(PyObject *ignored, PyObject *self) { formatteriterobject *it; @@ -1204,6 +1121,9 @@ formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) return NULL; } + if (PyUnicode_READY(self) == -1) + return NULL; + it = PyObject_New(formatteriterobject, &PyFormatterIter_Type); if (it == NULL) return NULL; @@ -1213,10 +1133,7 @@ formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) it->str = self; /* initialize the contained MarkupIterator */ - MarkupIterator_init(&it->it_markup, - STRINGLIB_STR(self), - STRINGLIB_LEN(self)); - + MarkupIterator_init(&it->it_markup, (PyObject*)self, 0, PyUnicode_GET_LENGTH(self)); return (PyObject *)it; } @@ -1232,9 +1149,7 @@ formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) typedef struct { PyObject_HEAD - - STRINGLIB_OBJECT *str; - + PyObject *str; FieldNameIterator it_field; } fieldnameiterobject; @@ -1335,7 +1250,7 @@ static PyTypeObject PyFieldNameIter_Type = { field_name_split. The iterator it returns is a FieldNameIterator */ static PyObject * -formatter_field_name_split(PyObject *ignored, STRINGLIB_OBJECT *self) +formatter_field_name_split(PyObject *ignored, PyObject *self) { SubString first; Py_ssize_t first_idx; @@ -1349,6 +1264,9 @@ formatter_field_name_split(PyObject *ignored, STRINGLIB_OBJECT *self) return NULL; } + if (PyUnicode_READY(self) == -1) + return NULL; + it = PyObject_New(fieldnameiterobject, &PyFieldNameIter_Type); if (it == NULL) return NULL; @@ -1360,8 +1278,7 @@ formatter_field_name_split(PyObject *ignored, STRINGLIB_OBJECT *self) /* Pass in auto_number = NULL. We'll return an empty string for first_obj in that case. */ - if (!field_name_split(STRINGLIB_STR(self), - STRINGLIB_LEN(self), + if (!field_name_split((PyObject*)self, 0, PyUnicode_GET_LENGTH(self), &first, &first_idx, &it->it_field, NULL)) goto done; diff --git a/Objects/stringlib/unicodedefs.h b/Objects/stringlib/unicodedefs.h index 09dae6dc9e..f16f21e60c 100644 --- a/Objects/stringlib/unicodedefs.h +++ b/Objects/stringlib/unicodedefs.h @@ -6,7 +6,10 @@ compiled as unicode. */ #define STRINGLIB_IS_UNICODE 1 +#define FASTSEARCH fastsearch +#define STRINGLIB(F) stringlib_##F #define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_SIZEOF_CHAR Py_UNICODE_SIZE #define STRINGLIB_CHAR Py_UNICODE #define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_PARSE_CODE "U" @@ -15,17 +18,12 @@ #define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK #define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL #define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL -#define STRINGLIB_TOUPPER Py_UNICODE_TOUPPER -#define STRINGLIB_TOLOWER Py_UNICODE_TOLOWER -#define STRINGLIB_FILL Py_UNICODE_FILL #define STRINGLIB_STR PyUnicode_AS_UNICODE #define STRINGLIB_LEN PyUnicode_GET_SIZE #define STRINGLIB_NEW PyUnicode_FromUnicode #define STRINGLIB_RESIZE PyUnicode_Resize #define STRINGLIB_CHECK PyUnicode_Check #define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact -#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping -#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale #if PY_VERSION_HEX < 0x03000000 #define STRINGLIB_TOSTR PyObject_Unicode |