summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/eval.c b/eval.c
index 92dd9f39..adff9db7 100644
--- a/eval.c
+++ b/eval.c
@@ -3806,6 +3806,18 @@ static val compares_with_eq(val obj)
return tnil(fixnump(obj) || chrp(obj) || symbolp(obj));
}
+static val hash_min_max(val env, val key, val value)
+{
+ cons_bind (minkey, maxkey, env);
+ if (!minkey || lt(key, minkey))
+ minkey = key;
+ if (!maxkey || gt(key, maxkey))
+ maxkey = key;
+ rplaca(env, minkey);
+ rplacd(env, maxkey);
+ return nil;
+}
+
static val me_case(val form, val menv)
{
val form_orig = form;
@@ -3818,7 +3830,11 @@ static val me_case(val form, val menv)
casesym == casequal_star_s);
int compat = (opt_compat && opt_compat <= 156 && !star);
val comp_eq_f = func_n1(compares_with_eq);
+ val integerp_f = func_n1(integerp);
+ val chrp_f = func_n1(chrp);
val all_keys_eq = t;
+ val all_keys_integer = t;
+ val all_keys_chr = t;
val hash_fallback_clause = nil;
val hash = nil;
val index = zero;
@@ -3868,12 +3884,20 @@ static val me_case(val form, val menv)
sethash(hash, keys, index);
if (!compares_with_eq(keys))
all_keys_eq = nil;
+ if (!integerp(keys))
+ all_keys_integer = nil;
+ if (!chrp(keys))
+ all_keys_chr = nil;
} else {
val iter;
for (iter = hash_keys; iter; iter = cdr(iter))
sethash(hash, car(iter), index);
if (!all_satisfy(keys, comp_eq_f, nil))
all_keys_eq = nil;
+ if (!all_satisfy(keys, integerp_f, nil))
+ all_keys_integer = nil;
+ if (!all_satisfy(keys, chrp_f, nil))
+ all_keys_chr = nil;
}
qtail = list_collect(qtail, forms);
@@ -3902,6 +3926,59 @@ static val me_case(val form, val menv)
if (form && atom(form))
eval_error(form_orig, lit("~s: improper form terminated by ~s"), casesym, form, nao);
+ if (!compat && (all_keys_integer || all_keys_chr)) {
+ val minmax = cons(nil, nil);
+ val nkeys = (maphash(func_f2(minmax, hash_min_max), hash),
+ (hash_count(hash)));
+ val minkey = if3(nkeys, car(minmax), zero);
+ val maxkey = if3(nkeys, cdr(minmax), zero);
+ val i, range = minus(maxkey, minkey);
+ val swres = gensym(lit("swres-"));
+ val uniq = list(quote_s, make_sym(lit("nohit")), nao);
+ val uniqf = cons(uniq, nil);
+
+ if (ge(nkeys, num_fast(6)) && gt(nkeys, divi(mul(range, three), four)) &&
+ ((casesym != caseq_s && casesym != caseq_star_s) ||
+ (!bignump(minkey) && !bignump(maxkey))))
+ {
+ list_collect_decl (indexed_clauses, rtail);
+
+ for (i = minkey; i <= maxkey; i = succ(i)) {
+ val lookup = gethash_e(hash, i);
+ rtail = list_collect(rtail, if3(lookup,
+ ref(hashforms, cdr(lookup)),
+ uniqf));
+ }
+
+ return list(let_s, list(list(tformsym, testform, nao),
+ list(swres, uniq, nao),
+ nao),
+ list(if_s,
+ list(and_s,
+ list(intern(if3(all_keys_integer,
+ lit("integerp"), lit("chrp")),
+ user_package),
+ tformsym, nao),
+ list(intern(lit("<="), user_package),
+ minkey, tformsym, maxkey, nao),
+ nao),
+ list(set_s,
+ swres,
+ list(switch_s,
+ if3(minkey == 0,
+ tformsym,
+ list(intern(lit("-"), user_package),
+ tformsym, minkey, nao)),
+ vec_list(indexed_clauses), nao),
+ nao), nao),
+ list(if_s,
+ list(eq_s, swres, uniq, nao),
+ cons(progn_s, cdr(hash_fallback_clause)),
+ swres,
+ nao), nao);
+ }
+ }
+
if (!compat && gt(hash_count(hash), num_fast(10)) &&
((casesym != caseq_s && casesym != caseq_star_s) || all_keys_eq))
{