summaryrefslogtreecommitdiff
path: root/src/fns.c
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2022-07-10 18:02:08 +0200
committerMattias EngdegÄrd <mattiase@acm.org>2022-07-10 18:20:37 +0200
commitcfda663282b788972c344e6733a8aa60a3e0f545 (patch)
tree988cf3745e6057b79180a659aa4c9071acf6a1da /src/fns.c
parent4bab499ed0d40d4e5ca68e5a17bcf5341125f734 (diff)
downloademacs-cfda663282b788972c344e6733a8aa60a3e0f545.tar.gz
Speed up string-to-unibyte
* src/character.h (str_to_unibyte): * src/character.c (str_to_unibyte): Remove. * src/fns.c (Fstring_to_unibyte): Ditch the call to str_to_unibyte and the unnecessary heap allocation. Write new, faster code. * test/src/fns-tests.el (fns--string-to-unibyte): New test.
Diffstat (limited to 'src/fns.c')
-rw-r--r--src/fns.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/src/fns.c b/src/fns.c
index 49d76a0e7c7..61ed01eee4e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -1413,19 +1413,24 @@ an error is signaled. */)
(Lisp_Object string)
{
CHECK_STRING (string);
+ if (!STRING_MULTIBYTE (string))
+ return string;
- if (STRING_MULTIBYTE (string))
+ ptrdiff_t chars = SCHARS (string);
+ Lisp_Object ret = make_uninit_string (chars);
+ unsigned char *src = SDATA (string);
+ unsigned char *dst = SDATA (ret);
+ for (ptrdiff_t i = 0; i < chars; i++)
{
- ptrdiff_t chars = SCHARS (string);
- unsigned char *str = xmalloc (chars);
- ptrdiff_t converted = str_to_unibyte (SDATA (string), str, chars);
-
- if (converted < chars)
- error ("Can't convert the %"pD"dth character to unibyte", converted);
- string = make_unibyte_string ((char *) str, chars);
- xfree (str);
+ unsigned char b = *src++;
+ if (b <= 0x7f)
+ *dst++ = b; /* ASCII */
+ else if (CHAR_BYTE8_HEAD_P (b))
+ *dst++ = 0x80 | (b & 1) << 6 | (*src++ & 0x3f); /* raw byte */
+ else
+ error ("Cannot convert character at index %"pD"d to unibyte", i);
}
- return string;
+ return ret;
}