86 lines
3.2 KiB
Diff
86 lines
3.2 KiB
Diff
# UNDF: UNDF-2026-000000265
|
|
diff --git a/vm_args.c b/vm_args.c
|
|
--- a/vm_args.c
|
|
+++ b/vm_args.c
|
|
@@ -299,30 +299,50 @@ static inline int
|
|
-args_setup_kw_parameters_lookup(const ID key, VALUE *ptr,
|
|
- const VALUE *const passed_keywords, VALUE *passed_values,
|
|
- const int passed_keyword_len)
|
|
-{
|
|
- int i;
|
|
- const VALUE keyname = ID2SYM(key);
|
|
-
|
|
- for (i=0; i<passed_keyword_len; i++) { /* O(passed_keyword_len) */
|
|
- if (keyname == passed_keywords[i]) {
|
|
- *ptr = passed_values[i];
|
|
- passed_values[i] = Qundef;
|
|
- return TRUE;
|
|
- }
|
|
- }
|
|
-
|
|
- return FALSE;
|
|
-}
|
|
+/* Build a temporary st_table from passed keyword symbol -> value-slot index.
|
|
+ * Replaces O(K * P) double-loop with O(K + P): one pass to build the map,
|
|
+ * one O(1) lookup per accepted keyword.
|
|
+ */
|
|
+static st_table *
|
|
+build_passed_kw_table(const VALUE *const passed_keywords,
|
|
+ const int passed_keyword_len)
|
|
+{
|
|
+ st_table *tbl = st_init_numtable_with_size(passed_keyword_len);
|
|
+ for (int i = 0; i < passed_keyword_len; i++) {
|
|
+ st_insert(tbl, (st_data_t)passed_keywords[i], (st_data_t)i);
|
|
+ }
|
|
+ return tbl;
|
|
+}
|
|
|
|
static void
|
|
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
|
|
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
|
|
VALUE *const locals)
|
|
{
|
|
const ID *acceptable_keywords = ISEQ_BODY(iseq)->param.keyword->table;
|
|
const int req_key_num = ISEQ_BODY(iseq)->param.keyword->required_num;
|
|
const int key_num = ISEQ_BODY(iseq)->param.keyword->num;
|
|
const VALUE * const default_values = ISEQ_BODY(iseq)->param.keyword->default_values;
|
|
VALUE missing = 0;
|
|
int i, di, found = 0;
|
|
int unspecified_bits = 0;
|
|
VALUE unspecified_bits_value = Qnil;
|
|
|
|
+ /* Build O(1) lookup map once — replaces O(K*P) nested loop */
|
|
+ st_table *kw_map = (passed_keyword_len > 0)
|
|
+ ? build_passed_kw_table(passed_keywords, passed_keyword_len)
|
|
+ : NULL;
|
|
+
|
|
for (i=0; i<req_key_num; i++) {
|
|
ID key = acceptable_keywords[i];
|
|
- if (args_setup_kw_parameters_lookup(key, &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
|
|
+ VALUE keyname = ID2SYM(key);
|
|
+ st_data_t idx;
|
|
+ if (kw_map && st_lookup(kw_map, (st_data_t)keyname, &idx)) {
|
|
+ locals[i] = passed_values[idx];
|
|
+ passed_values[idx] = Qundef;
|
|
found++;
|
|
- }
|
|
- else {
|
|
+ } else {
|
|
if (!missing) missing = rb_ary_hidden_new(1);
|
|
rb_ary_push(missing, ID2SYM(key));
|
|
}
|
|
}
|
|
|
|
if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
|
|
|
|
for (di=0; i<key_num; i++, di++) {
|
|
- if (args_setup_kw_parameters_lookup(acceptable_keywords[i], &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
|
|
+ VALUE keyname = ID2SYM(acceptable_keywords[i]);
|
|
+ st_data_t idx;
|
|
+ if (kw_map && st_lookup(kw_map, (st_data_t)keyname, &idx)) {
|
|
+ locals[i] = passed_values[idx];
|
|
+ passed_values[idx] = Qundef;
|
|
found++;
|
|
- }
|
|
- else {
|
|
+ } else {
|