Simplify and speed up make-hash-table argument parsing

* src/fns.c (get_key_arg): Remove.
(Fmake_hash_table): Traverse argument list once only.  Don't allocate a
helper array.  Use faster comparisons.
This commit is contained in:
Mattias Engdegård 2024-08-18 14:20:36 +02:00
parent 5d0e5f0865
commit 46f3452b30

108
src/fns.c
View file

@ -4637,30 +4637,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
@ -5762,32 +5738,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;
/* 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);
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);
}
/* 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);
test = get_hash_table_user_test (test_arg);
bool purecopy = !NILP (purecopy_arg);
/* 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;
EMACS_INT size;
if (NILP (size_arg))
size = DEFAULT_HASH_SIZE;
@ -5796,36 +5783,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);
}