| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3cceb38 commit 3079328
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1213,9 +1213,7 @@ Other Improvements | |||
| 1213 | 1213 | Significant Optimizations | |
| 1214 | 1214 | ========================= | |
| 1215 | 1215 | ||
| 1216 | - * The UTF-32 decoder is now 3x to 4x faster. The UTF-32 encoder is now 1.6x | ||
| 1217 | - to 3.5x faster. (Contributed by Serhiy Storchaka in :issue:`14625` and | ||
| 1218 | - :issue:`15027`.) | ||
| 1216 | + * The UTF-32 decoder is now 3x to 4x faster. | ||
| 1219 | 1217 | ||
| 1220 | 1218 | * The cost of hash collisions for sets is now reduced. Each hash table | |
| 1221 | 1219 | probe now checks a series of consecutive, adjacent key/hash pairs before | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,8 +10,6 @@ Release date: 2014-01-05 | |||
| 10 | 10 | Core and Builtins | |
| 11 | 11 | ----------------- | |
| 12 | 12 | ||
| 13 | - - Issue #15027: Rewrite the UTF-32 encoder. It is now 1.6x to 3.5x faster. | ||
| 14 | - | ||
| 15 | 13 | - Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. | |
| 16 | 14 | ||
| 17 | 15 | - Issue #19526: Exclude all new API from the stable ABI. Exceptions can be | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -718,93 +718,6 @@ STRINGLIB(utf16_encode)(const STRINGLIB_CHAR *in, | |||
| 718 | 718 | return len - (end - in + 1); | |
| 719 | 719 | #endif | |
| 720 | 720 | } | |
| 721 | - | ||
| 722 | - #if STRINGLIB_SIZEOF_CHAR == 1 | ||
| 723 | - # define SWAB4(CH, tmp) ((CH) << 24) /* high bytes are zero */ | ||
| 724 | - #elif STRINGLIB_SIZEOF_CHAR == 2 | ||
| 725 | - # define SWAB4(CH, tmp) (tmp = (CH), \ | ||
| 726 | - ((tmp & 0x00FFu) << 24) + ((tmp & 0xFF00u) << 8)) | ||
| 727 | - /* high bytes are zero */ | ||
| 728 | - #else | ||
| 729 | - # define SWAB4(CH, tmp) (tmp = (CH), \ | ||
| 730 | - tmp = ((tmp & 0x00FF00FFu) << 8) + ((tmp >> 8) & 0x00FF00FFu), \ | ||
| 731 | - ((tmp & 0x0000FFFFu) << 16) + ((tmp >> 16) & 0x0000FFFFu)) | ||
| 732 | - #endif | ||
| 733 | - Py_LOCAL_INLINE(Py_ssize_t) | ||
| 734 | - STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in, | ||
| 735 | - Py_ssize_t len, | ||
| 736 | - PY_UINT32_T **outptr, | ||
| 737 | - int native_ordering) | ||
| 738 | - { | ||
| 739 | - PY_UINT32_T *out = *outptr; | ||
| 740 | - const STRINGLIB_CHAR *end = in + len; | ||
| 741 | - if (native_ordering) { | ||
| 742 | - const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4); | ||
| 743 | - while (in < unrolled_end) { | ||
| 744 | - #if STRINGLIB_SIZEOF_CHAR > 1 | ||
| 745 | - /* check if any character is a surrogate character */ | ||
| 746 | - if (((in[0] ^ 0xd800) & | ||
| 747 | - (in[1] ^ 0xd800) & | ||
| 748 | - (in[2] ^ 0xd800) & | ||
| 749 | - (in[3] ^ 0xd800) & 0xf800) == 0) | ||
| 750 | - break; | ||
| 751 | - #endif | ||
| 752 | - out[0] = in[0]; | ||
| 753 | - out[1] = in[1]; | ||
| 754 | - out[2] = in[2]; | ||
| 755 | - out[3] = in[3]; | ||
| 756 | - in += 4; out += 4; | ||
| 757 | - } | ||
| 758 | - while (in < end) { | ||
| 759 | - Py_UCS4 ch; | ||
| 760 | - ch = *in++; | ||
| 761 | - #if STRINGLIB_SIZEOF_CHAR > 1 | ||
| 762 | - if (Py_UNICODE_IS_SURROGATE(ch)) { | ||
| 763 | - /* reject surrogate characters (U+DC800-U+DFFF) */ | ||
| 764 | - goto fail; | ||
| 765 | - } | ||
| 766 | - #endif | ||
| 767 | - *out++ = ch; | ||
| 768 | - } | ||
| 769 | - } else { | ||
| 770 | - const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4); | ||
| 771 | - while (in < unrolled_end) { | ||
| 772 | - #if STRINGLIB_SIZEOF_CHAR > 1 | ||
| 773 | - Py_UCS4 ch1, ch2, ch3, ch4; | ||
| 774 | - /* check if any character is a surrogate character */ | ||
| 775 | - if (((in[0] ^ 0xd800) & | ||
| 776 | - (in[1] ^ 0xd800) & | ||
| 777 | - (in[2] ^ 0xd800) & | ||
| 778 | - (in[3] ^ 0xd800) & 0xf800) == 0) | ||
| 779 | - break; | ||
| 780 | - #endif | ||
| 781 | - out[0] = SWAB4(in[0], ch1); | ||
| 782 | - out[1] = SWAB4(in[1], ch2); | ||
| 783 | - out[2] = SWAB4(in[2], ch3); | ||
| 784 | - out[3] = SWAB4(in[3], ch4); | ||
| 785 | - in += 4; out += 4; | ||
| 786 | - } | ||
| 787 | - while (in < end) { | ||
| 788 | - Py_UCS4 ch = *in++; | ||
| 789 | - #if STRINGLIB_SIZEOF_CHAR > 1 | ||
| 790 | - if (Py_UNICODE_IS_SURROGATE(ch)) { | ||
| 791 | - /* reject surrogate characters (U+DC800-U+DFFF) */ | ||
| 792 | - goto fail; | ||
| 793 | - } | ||
| 794 | - #endif | ||
| 795 | - *out++ = SWAB4(ch, ch); | ||
| 796 | - } | ||
| 797 | - } | ||
| 798 | - *outptr = out; | ||
| 799 | - return len; | ||
| 800 | - #if STRINGLIB_SIZEOF_CHAR > 1 | ||
| 801 | - fail: | ||
| 802 | - *outptr = out; | ||
| 803 | - return len - (end - in + 1); | ||
| 804 | - #endif | ||
| 805 | - } | ||
| 806 | - #undef SWAB4 | ||
| 807 | - | ||
| 808 | 721 | #endif | |
| 809 | 722 | ||
| 810 | 723 | #endif /* STRINGLIB_IS_UNICODE */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5085,22 +5085,32 @@ _PyUnicode_EncodeUTF32(PyObject *str, | |||
| 5085 | 5085 | const char *errors, | |
| 5086 | 5086 | int byteorder) | |
| 5087 | 5087 | { | |
| 5088 | - enum PyUnicode_Kind kind; | ||
| 5089 | - const void *data; | ||
| 5088 | + int kind; | ||
| 5089 | + void *data; | ||
| 5090 | 5090 | Py_ssize_t len; | |
| 5091 | 5091 | PyObject *v; | |
| 5092 | - PY_UINT32_T *out; | ||
| 5092 | + unsigned char *p; | ||
| 5093 | + Py_ssize_t nsize, i; | ||
| 5094 | + /* Offsets from p for storing byte pairs in the right order. */ | ||
| 5093 | 5095 | #if PY_LITTLE_ENDIAN | |
| 5094 | - int native_ordering = byteorder <= 0; | ||
| 5096 | + int iorder[] = {0, 1, 2, 3}; | ||
| 5095 | 5097 | #else | |
| 5096 | - int native_ordering = byteorder >= 0; | ||
| 5098 | + int iorder[] = {3, 2, 1, 0}; | ||
| 5097 | 5099 | #endif | |
| 5098 | 5100 | const char *encoding; | |
| 5099 | - Py_ssize_t nsize, pos; | ||
| 5100 | 5101 | PyObject *errorHandler = NULL; | |
| 5101 | 5102 | PyObject *exc = NULL; | |
| 5102 | 5103 | PyObject *rep = NULL; | |
| 5103 | 5104 | ||
| 5105 | + #define STORECHAR(CH) \ | ||
| 5106 | + do { \ | ||
| 5107 | + p[iorder[3]] = ((CH) >> 24) & 0xff; \ | ||
| 5108 | + p[iorder[2]] = ((CH) >> 16) & 0xff; \ | ||
| 5109 | + p[iorder[1]] = ((CH) >> 8) & 0xff; \ | ||
| 5110 | + p[iorder[0]] = (CH) & 0xff; \ | ||
| 5111 | + p += 4; \ | ||
| 5112 | + } while(0) | ||
| 5113 | + | ||
| 5104 | 5114 | if (!PyUnicode_Check(str)) { | |
| 5105 | 5115 | PyErr_BadArgument(); | |
| 5106 | 5116 | return NULL; | |
@@ -5111,61 +5121,67 @@ _PyUnicode_EncodeUTF32(PyObject *str, | |||
| 5111 | 5121 | data = PyUnicode_DATA(str); | |
| 5112 | 5122 | len = PyUnicode_GET_LENGTH(str); | |
| 5113 | 5123 | ||
| 5114 | - if (len > PY_SSIZE_T_MAX / 4 - (byteorder == 0)) | ||
| 5115 | - return PyErr_NoMemory(); | ||
| 5116 | 5124 | nsize = len + (byteorder == 0); | |
| 5125 | + if (nsize > PY_SSIZE_T_MAX / 4) | ||
| 5126 | + return PyErr_NoMemory(); | ||
| 5117 | 5127 | v = PyBytes_FromStringAndSize(NULL, nsize * 4); | |
| 5118 | 5128 | if (v == NULL) | |
| 5119 | 5129 | return NULL; | |
| 5120 | 5130 | ||
| 5121 | - /* output buffer is 4-bytes aligned */ | ||
| 5122 | - assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(v), 4)); | ||
| 5123 | - out = (PY_UINT32_T *)PyBytes_AS_STRING(v); | ||
| 5131 | + p = (unsigned char *)PyBytes_AS_STRING(v); | ||
| 5124 | 5132 | if (byteorder == 0) | |
| 5125 | - *out++ = 0xFEFF; | ||
| 5133 | + STORECHAR(0xFEFF); | ||
| 5126 | 5134 | if (len == 0) | |
| 5127 | - goto done; | ||
| 5135 | + return v; | ||
| 5128 | 5136 | ||
| 5129 | - if (byteorder == -1) | ||
| 5137 | + if (byteorder == -1) { | ||
| 5138 | + /* force LE */ | ||
| 5139 | + iorder[0] = 0; | ||
| 5140 | + iorder[1] = 1; | ||
| 5141 | + iorder[2] = 2; | ||
| 5142 | + iorder[3] = 3; | ||
| 5130 | 5143 | encoding = "utf-32-le"; | |
| 5131 | - else if (byteorder == 1) | ||
| 5144 | + } | ||
| 5145 | + else if (byteorder == 1) { | ||
| 5146 | + /* force BE */ | ||
| 5147 | + iorder[0] = 3; | ||
| 5148 | + iorder[1] = 2; | ||
| 5149 | + iorder[2] = 1; | ||
| 5150 | + iorder[3] = 0; | ||
| 5132 | 5151 | encoding = "utf-32-be"; | |
| 5152 | + } | ||
| 5133 | 5153 | else | |
| 5134 | 5154 | encoding = "utf-32"; | |
| 5135 | 5155 | ||
| 5136 | 5156 | if (kind == PyUnicode_1BYTE_KIND) { | |
| 5137 | - ucs1lib_utf32_encode((const Py_UCS1 *)data, len, &out, native_ordering); | ||
| 5138 | - goto done; | ||
| 5157 | + for (i = 0; i < len; i++) | ||
| 5158 | + STORECHAR(PyUnicode_READ(kind, data, i)); | ||
| 5159 | + return v; | ||
| 5139 | 5160 | } | |
| 5140 | 5161 | ||
| 5141 | - pos = 0; | ||
| 5142 | - while (pos < len) { | ||
| 5162 | + for (i = 0; i < len;) { | ||
| 5143 | 5163 | Py_ssize_t repsize, moreunits; | |
| 5144 | - | ||
| 5145 | - if (kind == PyUnicode_2BYTE_KIND) { | ||
| 5146 | - pos += ucs2lib_utf32_encode((const Py_UCS2 *)data + pos, len - pos, | ||
| 5147 | - &out, native_ordering); | ||
| 5148 | - } | ||
| 5149 | - else { | ||
| 5150 | - assert(kind == PyUnicode_4BYTE_KIND); | ||
| 5151 | - pos += ucs4lib_utf32_encode((const Py_UCS4 *)data + pos, len - pos, | ||
| 5152 | - &out, native_ordering); | ||
| 5164 | + Py_UCS4 ch = PyUnicode_READ(kind, data, i); | ||
| 5165 | + i++; | ||
| 5166 | + assert(ch <= MAX_UNICODE); | ||
| 5167 | + if (!Py_UNICODE_IS_SURROGATE(ch)) { | ||
| 5168 | + STORECHAR(ch); | ||
| 5169 | + continue; | ||
| 5153 | 5170 | } | |
| 5154 | - if (pos == len) | ||
| 5155 | - break; | ||
| 5156 | 5171 | ||
| 5157 | 5172 | rep = unicode_encode_call_errorhandler( | |
| 5158 | 5173 | errors, &errorHandler, | |
| 5159 | 5174 | encoding, "surrogates not allowed", | |
| 5160 | - str, &exc, pos, pos + 1, &pos); | ||
| 5175 | + str, &exc, i-1, i, &i); | ||
| 5176 | + | ||
| 5161 | 5177 | if (!rep) | |
| 5162 | 5178 | goto error; | |
| 5163 | 5179 | ||
| 5164 | 5180 | if (PyBytes_Check(rep)) { | |
| 5165 | 5181 | repsize = PyBytes_GET_SIZE(rep); | |
| 5166 | 5182 | if (repsize & 3) { | |
| 5167 | 5183 | raise_encode_exception(&exc, encoding, | |
| 5168 | - str, pos - 1, pos, | ||
| 5184 | + str, i - 1, i, | ||
| 5169 | 5185 | "surrogates not allowed"); | |
| 5170 | 5186 | goto error; | |
| 5171 | 5187 | } | |
@@ -5178,15 +5194,15 @@ _PyUnicode_EncodeUTF32(PyObject *str, | |||
| 5178 | 5194 | moreunits = repsize = PyUnicode_GET_LENGTH(rep); | |
| 5179 | 5195 | if (!PyUnicode_IS_ASCII(rep)) { | |
| 5180 | 5196 | raise_encode_exception(&exc, encoding, | |
| 5181 | - str, pos - 1, pos, | ||
| 5197 | + str, i - 1, i, | ||
| 5182 | 5198 | "surrogates not allowed"); | |
| 5183 | 5199 | goto error; | |
| 5184 | 5200 | } | |
| 5185 | 5201 | } | |
| 5186 | 5202 | ||
| 5187 | 5203 | /* four bytes are reserved for each surrogate */ | |
| 5188 | 5204 | if (moreunits > 1) { | |
| 5189 | - Py_ssize_t outpos = out - (PY_UINT32_T*) PyBytes_AS_STRING(v); | ||
| 5205 | + Py_ssize_t outpos = p - (unsigned char*) PyBytes_AS_STRING(v); | ||
| 5190 | 5206 | Py_ssize_t morebytes = 4 * (moreunits - 1); | |
| 5191 | 5207 | if (PyBytes_GET_SIZE(v) > PY_SSIZE_T_MAX - morebytes) { | |
| 5192 | 5208 | /* integer overflow */ | |
@@ -5195,16 +5211,20 @@ _PyUnicode_EncodeUTF32(PyObject *str, | |||
| 5195 | 5211 | } | |
| 5196 | 5212 | if (_PyBytes_Resize(&v, PyBytes_GET_SIZE(v) + morebytes) < 0) | |
| 5197 | 5213 | goto error; | |
| 5198 | - out = (PY_UINT32_T*) PyBytes_AS_STRING(v) + outpos; | ||
| 5214 | + p = (unsigned char*) PyBytes_AS_STRING(v) + outpos; | ||
| 5199 | 5215 | } | |
| 5200 | 5216 | ||
| 5201 | 5217 | if (PyBytes_Check(rep)) { | |
| 5202 | - Py_MEMCPY(out, PyBytes_AS_STRING(rep), repsize); | ||
| 5203 | - out += moreunits; | ||
| 5218 | + Py_MEMCPY(p, PyBytes_AS_STRING(rep), repsize); | ||
| 5219 | + p += repsize; | ||
| 5204 | 5220 | } else /* rep is unicode */ { | |
| 5221 | + const Py_UCS1 *repdata; | ||
| 5205 | 5222 | assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); | |
| 5206 | - ucs1lib_utf32_encode(PyUnicode_1BYTE_DATA(rep), repsize, | ||
| 5207 | - &out, native_ordering); | ||
| 5223 | + repdata = PyUnicode_1BYTE_DATA(rep); | ||
| 5224 | + while (repsize--) { | ||
| 5225 | + Py_UCS4 ch = *repdata++; | ||
| 5226 | + STORECHAR(ch); | ||
| 5227 | + } | ||
| 5208 | 5228 | } | |
| 5209 | 5229 | ||
| 5210 | 5230 | Py_CLEAR(rep); | |
@@ -5213,19 +5233,19 @@ _PyUnicode_EncodeUTF32(PyObject *str, | |||
| 5213 | 5233 | /* Cut back to size actually needed. This is necessary for, for example, | |
| 5214 | 5234 | encoding of a string containing isolated surrogates and the 'ignore' | |
| 5215 | 5235 | handler is used. */ | |
| 5216 | - nsize = (unsigned char*) out - (unsigned char*) PyBytes_AS_STRING(v); | ||
| 5236 | + nsize = p - (unsigned char*) PyBytes_AS_STRING(v); | ||
| 5217 | 5237 | if (nsize != PyBytes_GET_SIZE(v)) | |
| 5218 | 5238 | _PyBytes_Resize(&v, nsize); | |
| 5219 | 5239 | Py_XDECREF(errorHandler); | |
| 5220 | 5240 | Py_XDECREF(exc); | |
| 5221 | - done: | ||
| 5222 | 5241 | return v; | |
| 5223 | 5242 | error: | |
| 5224 | 5243 | Py_XDECREF(rep); | |
| 5225 | 5244 | Py_XDECREF(errorHandler); | |
| 5226 | 5245 | Py_XDECREF(exc); | |
| 5227 | 5246 | Py_XDECREF(v); | |
| 5228 | 5247 | return NULL; | |
| 5248 | + #undef STORECHAR | ||
| 5229 | 5249 | } | |
| 5230 | 5250 | ||
| 5231 | 5251 | PyObject * | |
| Back | FazBrowse Home | New Git URL |
0 commit comments