]> git.eshelyaron.com Git - emacs.git/commitdiff
Simplify and speed up make-hash-table argument parsing
authorMattias EngdegÄrd <mattiase@acm.org>
Sun, 18 Aug 2024 12:20:36 +0000 (14:20 +0200)
committerEshel Yaron <me@eshelyaron.com>
Thu, 22 Aug 2024 07:27:22 +0000 (09:27 +0200)
* src/fns.c (get_key_arg): Remove.
(Fmake_hash_table): Traverse argument list once only.  Don't allocate a
helper array.  Use faster comparisons.

(cherry picked from commit 46f3452b30f39a69f610faab58c1490b34dd367d)

src/fns.c

index 7c0416f84ad6dbc5f0d46ecce2adf4164f931d33..7c2c86840fe291b80ec1ba77eabcbdcb48aec75b 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -4634,30 +4634,6 @@ next_almost_prime (EMACS_INT n)
       return n;
 }
 
-
-/* Find KEY in ARGS which has size NARGS.  Don't consider indices for
-   which USED[I] is non-zero.  If found at index I in ARGS, set
-   USED[I] and USED[I + 1] to 1, and return I + 1.  Otherwise return
-   0.  This function is used to extract a keyword/argument pair from
-   a DEFUN parameter list.  */
-
-static ptrdiff_t
-get_key_arg (Lisp_Object key, ptrdiff_t nargs, Lisp_Object *args, char *used)
-{
-  ptrdiff_t i;
-
-  for (i = 1; i < nargs; i++)
-    if (!used[i - 1] && EQ (args[i - 1], key))
-      {
-       used[i - 1] = 1;
-       used[i] = 1;
-       return i;
-      }
-
-  return 0;
-}
-
-
 /* Return a Lisp vector which has the same contents as VEC but has
    at least INCR_MIN more entries, where INCR_MIN is positive.
    If NITEMS_MAX is not -1, do not grow the vector to be any larger
@@ -5759,32 +5735,43 @@ and ignored.
 usage: (make-hash-table &rest KEYWORD-ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  USE_SAFE_ALLOCA;
+  Lisp_Object test_arg = Qnil;
+  Lisp_Object weakness_arg = Qnil;
+  Lisp_Object size_arg = Qnil;
+  Lisp_Object purecopy_arg = Qnil;
+
+  if (nargs & 1)
+    error ("Odd number of arguments");
+  while (nargs >= 2)
+    {
+      Lisp_Object arg = maybe_remove_pos_from_symbol (args[--nargs]);
+      Lisp_Object kw = maybe_remove_pos_from_symbol (args[--nargs]);
+      if (BASE_EQ (kw, QCtest))
+       test_arg = arg;
+      else if (BASE_EQ (kw, QCweakness))
+       weakness_arg = arg;
+      else if (BASE_EQ (kw, QCsize))
+       size_arg = arg;
+      else if (BASE_EQ (kw, QCpurecopy))
+       purecopy_arg = arg;
+      else if (BASE_EQ (kw, QCrehash_threshold) || BASE_EQ (kw, QCrehash_size))
+       ;  /* ignore obsolete keyword arguments */
+      else
+       signal_error ("Invalid keyword argument", kw);
+    }
 
-  /* The vector `used' is used to keep track of arguments that
-     have been consumed.  */
-  char *used = SAFE_ALLOCA (nargs * sizeof *used);
-  memset (used, 0, nargs * sizeof *used);
-
-  /* See if there's a `:test TEST' among the arguments.  */
-  ptrdiff_t i = get_key_arg (QCtest, nargs, args, used);
-  Lisp_Object test = i ? maybe_remove_pos_from_symbol (args[i]) : Qeql;
-  const struct hash_table_test *testdesc;
-  if (BASE_EQ (test, Qeq))
-    testdesc = &hashtest_eq;
-  else if (BASE_EQ (test, Qeql))
-    testdesc = &hashtest_eql;
-  else if (BASE_EQ (test, Qequal))
-    testdesc = &hashtest_equal;
+  const struct hash_table_test *test;
+  if (NILP (test_arg) || BASE_EQ (test_arg, Qeql))
+    test = &hashtest_eql;
+  else if (BASE_EQ (test_arg, Qeq))
+    test = &hashtest_eq;
+  else if (BASE_EQ (test_arg, Qequal))
+    test = &hashtest_equal;
   else
-    testdesc = get_hash_table_user_test (test);
-
-  /* See if there's a `:purecopy PURECOPY' argument.  */
-  i = get_key_arg (QCpurecopy, nargs, args, used);
-  bool purecopy = i && !NILP (args[i]);
-  /* See if there's a `:size SIZE' argument.  */
-  i = get_key_arg (QCsize, nargs, args, used);
-  Lisp_Object size_arg = i ? args[i] : Qnil;
+    test = get_hash_table_user_test (test_arg);
+
+  bool purecopy = !NILP (purecopy_arg);
+
   EMACS_INT size;
   if (NILP (size_arg))
     size = DEFAULT_HASH_SIZE;
@@ -5793,36 +5780,21 @@ usage: (make-hash-table &rest KEYWORD-ARGS)  */)
   else
     signal_error ("Invalid hash table size", size_arg);
 
-  /* Look for `:weakness WEAK'.  */
-  i = get_key_arg (QCweakness, nargs, args, used);
-  Lisp_Object weakness = i ? args[i] : Qnil;
   hash_table_weakness_t weak;
-  if (NILP (weakness))
+  if (NILP (weakness_arg))
     weak = Weak_None;
-  else if (EQ (weakness, Qkey))
+  else if (BASE_EQ (weakness_arg, Qkey))
     weak = Weak_Key;
-  else if (EQ (weakness, Qvalue))
+  else if (BASE_EQ (weakness_arg, Qvalue))
     weak = Weak_Value;
-  else if (EQ (weakness, Qkey_or_value))
+  else if (BASE_EQ (weakness_arg, Qkey_or_value))
     weak = Weak_Key_Or_Value;
-  else if (EQ (weakness, Qt) || EQ (weakness, Qkey_and_value))
+  else if (BASE_EQ (weakness_arg, Qt) || BASE_EQ (weakness_arg, Qkey_and_value))
     weak = Weak_Key_And_Value;
   else
-    signal_error ("Invalid hash table weakness", weakness);
+    signal_error ("Invalid hash table weakness", weakness_arg);
 
-  /* Now, all args should have been used up, or there's a problem.  */
-  for (i = 0; i < nargs; ++i)
-    if (!used[i])
-      {
-       /* Ignore obsolete arguments.  */
-       if (EQ (args[i], QCrehash_threshold) || EQ (args[i], QCrehash_size))
-         i++;
-       else
-         signal_error ("Invalid argument list", args[i]);
-      }
-
-  SAFE_FREE ();
-  return make_hash_table (testdesc, size, weak, purecopy);
+  return make_hash_table (test, size, weak, purecopy);
 }