aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias EngdegÄrd2022-01-26 12:30:39 +0100
committerMattias EngdegÄrd2022-07-07 17:43:21 +0200
commit53c0690fa28f338071703f1567d2d1c4054416f0 (patch)
treedf9781443fed41354470ba90b589b3e4adfbef39 /src
parent9cd72b02b67e92e89b83791b66fe40c4b50d8357 (diff)
downloademacs-53c0690fa28f338071703f1567d2d1c4054416f0.tar.gz
emacs-53c0690fa28f338071703f1567d2d1c4054416f0.zip
Faster append and vconcat
By separating the code paths for append and vconcat, each becomes simpler and faster. * src/fns.c (concat_strings): Rename to... (concat_to_string): ...this. (concat): Split into concat_to_list and concat_to_vector. (concat_to_list, concat_to_vector): New, specialised and streamlined from earlier combined code. (concat2, concat3, Fappend, Fconcat, Fvconcat): Adjust calls.
Diffstat (limited to 'src')
-rw-r--r--src/fns.c225
1 files changed, 139 insertions, 86 deletions
diff --git a/src/fns.c b/src/fns.c
index f30b2f6fb3c..f4ba67b40e7 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -589,20 +589,21 @@ Do NOT use this function to compare file names for equality. */)
589#endif /* !__STDC_ISO_10646__, !WINDOWSNT */ 589#endif /* !__STDC_ISO_10646__, !WINDOWSNT */
590} 590}
591 591
592static Lisp_Object concat (ptrdiff_t nargs, Lisp_Object *args, 592static Lisp_Object concat_to_list (ptrdiff_t nargs, Lisp_Object *args,
593 Lisp_Object last_tail, bool vector_target); 593 Lisp_Object last_tail);
594static Lisp_Object concat_strings (ptrdiff_t nargs, Lisp_Object *args); 594static Lisp_Object concat_to_vector (ptrdiff_t nargs, Lisp_Object *args);
595static Lisp_Object concat_to_string (ptrdiff_t nargs, Lisp_Object *args);
595 596
596Lisp_Object 597Lisp_Object
597concat2 (Lisp_Object s1, Lisp_Object s2) 598concat2 (Lisp_Object s1, Lisp_Object s2)
598{ 599{
599 return concat_strings (2, ((Lisp_Object []) {s1, s2})); 600 return concat_to_string (2, ((Lisp_Object []) {s1, s2}));
600} 601}
601 602
602Lisp_Object 603Lisp_Object
603concat3 (Lisp_Object s1, Lisp_Object s2, Lisp_Object s3) 604concat3 (Lisp_Object s1, Lisp_Object s2, Lisp_Object s3)
604{ 605{
605 return concat_strings (3, ((Lisp_Object []) {s1, s2, s3})); 606 return concat_to_string (3, ((Lisp_Object []) {s1, s2, s3}));
606} 607}
607 608
608DEFUN ("append", Fappend, Sappend, 0, MANY, 0, 609DEFUN ("append", Fappend, Sappend, 0, MANY, 0,
@@ -615,7 +616,7 @@ usage: (append &rest SEQUENCES) */)
615{ 616{
616 if (nargs == 0) 617 if (nargs == 0)
617 return Qnil; 618 return Qnil;
618 return concat (nargs - 1, args, args[nargs - 1], false); 619 return concat_to_list (nargs - 1, args, args[nargs - 1]);
619} 620}
620 621
621DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0, 622DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
@@ -628,7 +629,7 @@ to be `eq'.
628usage: (concat &rest SEQUENCES) */) 629usage: (concat &rest SEQUENCES) */)
629 (ptrdiff_t nargs, Lisp_Object *args) 630 (ptrdiff_t nargs, Lisp_Object *args)
630{ 631{
631 return concat_strings (nargs, args); 632 return concat_to_string (nargs, args);
632} 633}
633 634
634DEFUN ("vconcat", Fvconcat, Svconcat, 0, MANY, 0, 635DEFUN ("vconcat", Fvconcat, Svconcat, 0, MANY, 0,
@@ -638,7 +639,7 @@ Each argument may be a list, vector or string.
638usage: (vconcat &rest SEQUENCES) */) 639usage: (vconcat &rest SEQUENCES) */)
639 (ptrdiff_t nargs, Lisp_Object *args) 640 (ptrdiff_t nargs, Lisp_Object *args)
640{ 641{
641 return concat (nargs, args, Qnil, true); 642 return concat_to_vector (nargs, args);
642} 643}
643 644
644 645
@@ -706,8 +707,8 @@ the same empty object instead of its copy. */)
706 wrong_type_argument (Qsequencep, arg); 707 wrong_type_argument (Qsequencep, arg);
707} 708}
708 709
709/* This structure holds information of an argument of `concat_strings' that is 710/* This structure holds information of an argument of `concat_to_string'
710 a string and has text properties to be copied. */ 711 that is a string and has text properties to be copied. */
711struct textprop_rec 712struct textprop_rec
712{ 713{
713 ptrdiff_t argnum; /* refer to ARGS (arguments of `concat') */ 714 ptrdiff_t argnum; /* refer to ARGS (arguments of `concat') */
@@ -716,7 +717,7 @@ struct textprop_rec
716}; 717};
717 718
718static Lisp_Object 719static Lisp_Object
719concat_strings (ptrdiff_t nargs, Lisp_Object *args) 720concat_to_string (ptrdiff_t nargs, Lisp_Object *args)
720{ 721{
721 USE_SAFE_ALLOCA; 722 USE_SAFE_ALLOCA;
722 723
@@ -912,19 +913,100 @@ concat_strings (ptrdiff_t nargs, Lisp_Object *args)
912 return result; 913 return result;
913} 914}
914 915
915/* Concatenate sequences into a list or vector. */ 916/* Concatenate sequences into a list. */
917Lisp_Object
918concat_to_list (ptrdiff_t nargs, Lisp_Object *args, Lisp_Object last_tail)
919{
920 /* Copy the contents of the args into the result. */
921 Lisp_Object result = Qnil;
922 Lisp_Object last = Qnil; /* Last cons in result if nonempty. */
923
924 for (ptrdiff_t i = 0; i < nargs; i++)
925 {
926 Lisp_Object arg = args[i];
927 /* List arguments are treated specially since this is the common case. */
928 if (CONSP (arg))
929 {
930 Lisp_Object head = Fcons (XCAR (arg), Qnil);
931 Lisp_Object prev = head;
932 arg = XCDR (arg);
933 FOR_EACH_TAIL (arg)
934 {
935 Lisp_Object next = Fcons (XCAR (arg), Qnil);
936 XSETCDR (prev, next);
937 prev = next;
938 }
939 CHECK_LIST_END (arg, arg);
940 if (NILP (result))
941 result = head;
942 else
943 XSETCDR (last, head);
944 last = prev;
945 }
946 else if (NILP (arg))
947 ;
948 else if (VECTORP (arg) || STRINGP (arg)
949 || BOOL_VECTOR_P (arg) || COMPILEDP (arg))
950 {
951 ptrdiff_t arglen = XFIXNUM (Flength (arg));
952 ptrdiff_t argindex_byte = 0;
916 953
954 /* Copy element by element. */
955 for (ptrdiff_t argindex = 0; argindex < arglen; argindex++)
956 {
957 /* Fetch next element of `arg' arg into `elt', or break if
958 `arg' is exhausted. */
959 Lisp_Object elt;
960 if (STRINGP (arg))
961 {
962 int c;
963 if (STRING_MULTIBYTE (arg))
964 {
965 ptrdiff_t char_idx = argindex;
966 c = fetch_string_char_advance_no_check (arg, &char_idx,
967 &argindex_byte);
968 }
969 else
970 c = SREF (arg, argindex);
971 elt = make_fixed_natnum (c);
972 }
973 else if (BOOL_VECTOR_P (arg))
974 elt = bool_vector_ref (arg, argindex);
975 else
976 elt = AREF (arg, argindex);
977
978 /* Store this element into the result. */
979 Lisp_Object node = Fcons (elt, Qnil);
980 if (NILP (result))
981 result = node;
982 else
983 XSETCDR (last, node);
984 last = node;
985 }
986 }
987 else
988 wrong_type_argument (Qsequencep, arg);
989 }
990
991 if (NILP (result))
992 result = last_tail;
993 else
994 XSETCDR (last, last_tail);
995
996 return result;
997}
998
999/* Concatenate sequences into a vector. */
917Lisp_Object 1000Lisp_Object
918concat (ptrdiff_t nargs, Lisp_Object *args, Lisp_Object last_tail, 1001concat_to_vector (ptrdiff_t nargs, Lisp_Object *args)
919 bool vector_target)
920{ 1002{
921 /* Check argument types and compute total length of arguments. */ 1003 /* Check argument types and compute total length of arguments. */
922 EMACS_INT result_len = 0; 1004 EMACS_INT result_len = 0;
923 for (ptrdiff_t i = 0; i < nargs; i++) 1005 for (ptrdiff_t i = 0; i < nargs; i++)
924 { 1006 {
925 Lisp_Object arg = args[i]; 1007 Lisp_Object arg = args[i];
926 if (!(CONSP (arg) || NILP (arg) || VECTORP (arg) || STRINGP (arg) 1008 if (!(VECTORP (arg) || CONSP (arg) || NILP (arg) || STRINGP (arg)
927 || COMPILEDP (arg) || BOOL_VECTOR_P (arg))) 1009 || BOOL_VECTOR_P (arg) || COMPILEDP (arg)))
928 wrong_type_argument (Qsequencep, arg); 1010 wrong_type_argument (Qsequencep, arg);
929 EMACS_INT len = XFIXNAT (Flength (arg)); 1011 EMACS_INT len = XFIXNAT (Flength (arg));
930 result_len += len; 1012 result_len += len;
@@ -932,90 +1014,61 @@ concat (ptrdiff_t nargs, Lisp_Object *args, Lisp_Object last_tail,
932 memory_full (SIZE_MAX); 1014 memory_full (SIZE_MAX);
933 } 1015 }
934 1016
935 /* When the target is a list, return the tail directly if all other 1017 /* Create the output vector. */
936 arguments are empty. */ 1018 Lisp_Object result = make_uninit_vector (result_len);
937 if (!vector_target && result_len == 0) 1019 Lisp_Object *dst = XVECTOR (result)->contents;
938 return last_tail;
939
940 /* Create the output object. */
941 Lisp_Object result = vector_target
942 ? make_nil_vector (result_len)
943 : Fmake_list (make_fixnum (result_len), Qnil);
944 1020
945 /* Copy the contents of the args into the result. */ 1021 /* Copy the contents of the args into the result. */
946 Lisp_Object tail = Qnil;
947 ptrdiff_t toindex = 0;
948 if (CONSP (result))
949 {
950 tail = result;
951 toindex = -1; /* -1 in toindex is flag we are making a list */
952 }
953
954 Lisp_Object prev = Qnil;
955 1022
956 for (ptrdiff_t i = 0; i < nargs; i++) 1023 for (ptrdiff_t i = 0; i < nargs; i++)
957 { 1024 {
958 ptrdiff_t arglen = 0;
959 ptrdiff_t argindex = 0;
960 ptrdiff_t argindex_byte = 0;
961
962 Lisp_Object arg = args[i]; 1025 Lisp_Object arg = args[i];
963 if (!CONSP (arg)) 1026 if (VECTORP (arg))
964 arglen = XFIXNUM (Flength (arg));
965
966 /* Copy element by element. */
967 while (1)
968 { 1027 {
969 /* Fetch next element of `arg' arg into `elt', or break if 1028 ptrdiff_t size = ASIZE (arg);
970 `arg' is exhausted. */ 1029 memcpy (dst, XVECTOR (arg)->contents, size * sizeof *dst);
971 Lisp_Object elt; 1030 dst += size;
972 if (CONSP (arg)) 1031 }
973 { 1032 else if (CONSP (arg))
974 elt = XCAR (arg); 1033 do
975 arg = XCDR (arg); 1034 {
976 } 1035 *dst++ = XCAR (arg);
977 else if (NILP (arg) || argindex >= arglen) 1036 arg = XCDR (arg);
978 break; 1037 }
979 else if (STRINGP (arg)) 1038 while (!NILP (arg));
1039 else if (NILP (arg))
1040 ;
1041 else if (STRINGP (arg))
1042 {
1043 ptrdiff_t size = SCHARS (arg);
1044 if (STRING_MULTIBYTE (arg))
980 { 1045 {
981 int c; 1046 ptrdiff_t byte = 0;
982 if (STRING_MULTIBYTE (arg)) 1047 for (ptrdiff_t i = 0; i < size;)
983 c = fetch_string_char_advance_no_check (arg, &argindex,
984 &argindex_byte);
985 else
986 { 1048 {
987 c = SREF (arg, argindex); 1049 int c = fetch_string_char_advance_no_check (arg, &i, &byte);
988 argindex++; 1050 *dst++ = make_fixnum (c);
989 } 1051 }
990 XSETFASTINT (elt, c);
991 }
992 else if (BOOL_VECTOR_P (arg))
993 {
994 elt = bool_vector_ref (arg, argindex);
995 argindex++;
996 }
997 else
998 {
999 elt = AREF (arg, argindex);
1000 argindex++;
1001 }
1002
1003 /* Store this element into the result. */
1004 if (toindex < 0)
1005 {
1006 XSETCAR (tail, elt);
1007 prev = tail;
1008 tail = XCDR (tail);
1009 } 1052 }
1010 else 1053 else
1011 { 1054 for (ptrdiff_t i = 0; i < size; i++)
1012 ASET (result, toindex, elt); 1055 *dst++ = make_fixnum (SREF (arg, i));
1013 toindex++; 1056 }
1014 } 1057 else if (BOOL_VECTOR_P (arg))
1058 {
1059 ptrdiff_t size = bool_vector_size (arg);
1060 for (ptrdiff_t i = 0; i < size; i++)
1061 *dst++ = bool_vector_ref (arg, i);
1062 }
1063 else
1064 {
1065 eassert (COMPILEDP (arg));
1066 ptrdiff_t size = PVSIZE (arg);
1067 memcpy (dst, XVECTOR (arg)->contents, size * sizeof *dst);
1068 dst += size;
1015 } 1069 }
1016 } 1070 }
1017 if (!NILP (prev)) 1071 eassert (dst == XVECTOR (result)->contents + result_len);
1018 XSETCDR (prev, last_tail);
1019 1072
1020 return result; 1073 return result;
1021} 1074}