From 80267bb55f9fdf809a1e2eb00ea36f58ba89c165 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 1 Dec 2017 19:30:36 -0800 Subject: args: keyword extraction mechanism. Implement a mechanism for extracting keyword arguments out of "struct args *" argument lists which avoids consing up an argument list and scanning it multiple times for multiple keywords. * args.c (args_for_each): New function. (struct args_bool_key, struct args_bool_ctx): New struct types. (args_key_check_store): New static function. (args_keys_extract_vl, args_key_extract): New functions. * args.h (args_for_each, args_keys_extract_vl, args_key_extract): Declared. --- args.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ args.h | 5 ++++ 2 files changed, 94 insertions(+) diff --git a/args.c b/args.c index ec4d3e4b..3c222d18 100644 --- a/args.c +++ b/args.c @@ -28,7 +28,9 @@ #include #include #include +#include #include "config.h" +#include ALLOCA_H #include "lib.h" #include "signal.h" #include "unwind.h" @@ -119,3 +121,90 @@ val args_copy_to_list(struct args *args) return out; } + +void args_for_each(struct args *args, + int (*fn)(val arg, int ix, mem_t *ctx), + mem_t *ctx) +{ + int i; + val iter; + + for (i = 0; i < args->fill; i++) + if (fn(args->arg[i], i, ctx)) + args->arg[i] = nil; + + for (iter = args->list; iter; iter = cdr(iter), i++) + if (fn(car(iter), i, ctx)) + rplaca(iter, nil); +} + +struct args_bool_key { + struct args_bool_key *next; + val key; + val arg_p; + val *store; +}; + +struct args_bool_ctx { + struct args_bool_key *akl; + val *next_arg_store; +}; + +static int args_key_check_store(val arg, int ix, mem_t *ctx) +{ + struct args_bool_ctx *acx = coerce(struct args_bool_ctx *, ctx); + struct args_bool_key **pakl, *akl; + val *store = 0; + + if (acx->next_arg_store != 0) { + *acx->next_arg_store = arg; + acx->next_arg_store = 0; + return 0; + } + + for (pakl = &acx->akl, akl = *pakl; + akl != 0; + pakl = &akl->next, akl = *pakl) + { + if (store != 0) + *store = arg; + if (akl->key == arg) { + if (akl->arg_p) + acx->next_arg_store = akl->store; + else + *akl->store = t; + *pakl = akl->next; + } + } + + return 0; +} + +void args_keys_extract_vl(struct args *args, va_list vl) +{ + struct args_bool_ctx acx = { 0 }; + + for (;;) { + val key; + struct args_bool_key *nakl; + if ((key = va_arg (vl, val)) == nil) + break; + nakl = coerce(struct args_bool_key *, alloca(sizeof *nakl)); + nakl->key = key; + nakl->arg_p = va_arg (vl, val); + nakl->store = va_arg (vl, val *); + nakl->next = acx.akl; + acx.akl = nakl; + } + + if (acx.akl != 0) + args_for_each(args, args_key_check_store, coerce(mem_t *, &acx)); +} + +void args_keys_extract(struct args *args, ...) +{ + va_list vl; + va_start (vl, args); + args_keys_extract_vl(args, vl); + va_end (vl); +} diff --git a/args.h b/args.h index 5877e44c..6e0036c0 100644 --- a/args.h +++ b/args.h @@ -186,3 +186,8 @@ struct args *args_copy_zap(struct args *to, struct args *from); struct args *args_cat_zap(struct args *to, struct args *from); struct args *args_cat_zap_from(struct args *to, struct args *from, cnum index); val args_copy_to_list(struct args *args); +void args_for_each(struct args *args, + int (*fn)(val arg, int ix, mem_t *ctx), + mem_t *ctx); +void args_keys_extract_vl(struct args *args, va_list); +void args_keys_extract(struct args *args, ...); -- cgit v1.2.3