From 5ca792c40efae607ccf1e5d6aee8ff2c57991b2a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 1 Jun 2021 13:01:19 +0900 Subject: [PATCH] [ruamoko] Add some stdlib function wrappers For now, just bsearch (normal and fuzzy), qsort, and prefixsum (not in C's stdlib that I know of, but I think having native implementations of float and int prefix sums will be useful. --- include/rua_internal.h | 2 + libs/ruamoko/Makemodule.am | 1 + libs/ruamoko/rua_stdlib.c | 172 ++++++++++++++++++++++++++++++++++ ruamoko/include/Makemodule.am | 1 + ruamoko/include/stdlib.h | 17 ++++ ruamoko/lib/Makemodule.am | 1 + ruamoko/lib/stdlib.r | 11 +++ 7 files changed, 205 insertions(+) create mode 100644 libs/ruamoko/rua_stdlib.c create mode 100644 ruamoko/include/stdlib.h create mode 100644 ruamoko/lib/stdlib.r diff --git a/include/rua_internal.h b/include/rua_internal.h index 7bde98a77..c5aba3569 100644 --- a/include/rua_internal.h +++ b/include/rua_internal.h @@ -55,6 +55,8 @@ void RUA_Script_Init (progs_t *pr, int secure); void RUA_Set_Init (progs_t *pr, int secure); +void RUA_Stdlib_Init (struct progs_s *pr, int secure); + void RUA_String_Init (struct progs_s *pr, int secure); void RUA_QFile_Init (struct progs_s *pr, int secure); diff --git a/libs/ruamoko/Makemodule.am b/libs/ruamoko/Makemodule.am index c3ed37383..e684d1391 100644 --- a/libs/ruamoko/Makemodule.am +++ b/libs/ruamoko/Makemodule.am @@ -23,4 +23,5 @@ libs_ruamoko_libQFruamoko_la_SOURCES= \ libs/ruamoko/rua_runtime.c \ libs/ruamoko/rua_script.c \ libs/ruamoko/rua_set.c \ + libs/ruamoko/rua_stdlib.c \ libs/ruamoko/rua_string.c diff --git a/libs/ruamoko/rua_stdlib.c b/libs/ruamoko/rua_stdlib.c new file mode 100644 index 000000000..8c375e405 --- /dev/null +++ b/libs/ruamoko/rua_stdlib.c @@ -0,0 +1,172 @@ +/* + bi_stdlib.c + + QuakeC stdlib api + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/5/31 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define _GNU_SOURCE // for qsort_r + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include +#include + +#include "compat.h" +#include "qfalloca.h" + +#if defined(_WIN32) && defined(HAVE_MALLOC_H) +#include +#endif + +#include "QF/fbsearch.h" +#include "QF/progs.h" + +#include "rua_internal.h" + +typedef struct { + progs_t *pr; + func_t func; +} function_t; + +static int +int_compare (const void *_a, const void *_b) +{ + const int *a = _a; + const int *b = _b; + return *a - *b; +} + +static int +rua_compare (const void *a, const void *b, void *_f) +{ + function_t *f = _f; + + PR_RESET_PARAMS (f->pr); + P_POINTER (f->pr, 0) = PR_SetPointer (f->pr, a); + P_POINTER (f->pr, 1) = PR_SetPointer (f->pr, b); + f->pr->pr_argc = 2; + PR_ExecuteProgram (f->pr, f->func); + return R_INT (f->pr); +} + +static void +bi_bsearch (progs_t *pr) +{ + const void *key = P_GPOINTER (pr, 0); + const void *array = P_GPOINTER (pr, 1); + size_t nmemb = P_INT (pr, 2); + size_t size = P_INT (pr, 3) * sizeof (pr_int_t); + func_t cmp = P_FUNCTION (pr, 4); + void *p = 0; + + if (!cmp) { + p = bsearch (key, array, nmemb, size, int_compare); + } else { + function_t func = { pr, cmp }; + p = bsearch_r (key, array, nmemb, size, rua_compare, &func); + } + RETURN_POINTER (pr, p); +} + +static void +bi_fbsearch (progs_t *pr) +{ + const void *key = P_GPOINTER (pr, 0); + const void *array = P_GPOINTER (pr, 1); + size_t nmemb = P_INT (pr, 2); + size_t size = P_INT (pr, 3) * sizeof (pr_int_t); + func_t cmp = P_FUNCTION (pr, 4); + void *p = 0; + + if (!cmp) { + p = fbsearch (key, array, nmemb, size, int_compare); + } else { + function_t func = { pr, cmp }; + p = fbsearch_r (key, array, nmemb, size, rua_compare, &func); + } + RETURN_POINTER (pr, p); +} + +static void +bi_qsort (progs_t *pr) +{ + void *array = P_GPOINTER (pr, 0); + size_t nmemb = P_INT (pr, 1); + size_t size = P_INT (pr, 2) * sizeof (pr_int_t); + func_t cmp = P_FUNCTION (pr, 3); + + if (!cmp) { + qsort (array, nmemb, size, int_compare); + } else { + function_t func = { pr, cmp }; + qsort_r (array, nmemb, size, rua_compare, &func); + } +} + +static void +bi_prefixsumi (progs_t *pr) +{ + int *array = (int *) P_GPOINTER (pr, 0); + int count = P_INT (pr, 1); + + for (int i = 1; i < count; i++) { + array[i] += array[i - 1]; + } +} + +static void +bi_prefixsumf (progs_t *pr) +{ + float *array = (float *) P_GPOINTER (pr, 0); + int count = P_INT (pr, 1); + + for (int i = 1; i < count; i++) { + array[i] += array[i - 1]; + } +} + +static builtin_t builtins[] = { + {"bsearch", bi_bsearch, -1}, + {"fbsearch", bi_fbsearch, -1}, + {"qsort", bi_qsort, -1}, + {"prefixsum|^ii", bi_prefixsumi, -1}, + {"prefixsum|^fi", bi_prefixsumf, -1}, + {0} +}; + +void +RUA_Stdlib_Init (progs_t *pr, int secure) +{ + PR_RegisterBuiltins (pr, builtins); +} diff --git a/ruamoko/include/Makemodule.am b/ruamoko/include/Makemodule.am index d53289e72..8324491d3 100644 --- a/ruamoko/include/Makemodule.am +++ b/ruamoko/include/Makemodule.am @@ -16,6 +16,7 @@ ruamoko_include = \ ruamoko/include/server.h \ ruamoko/include/sound.h \ ruamoko/include/script.h \ + ruamoko/include/stdlib.h \ ruamoko/include/string.h \ ruamoko/include/sv_sound.h \ ruamoko/include/system.h \ diff --git a/ruamoko/include/stdlib.h b/ruamoko/include/stdlib.h new file mode 100644 index 000000000..d645955f4 --- /dev/null +++ b/ruamoko/include/stdlib.h @@ -0,0 +1,17 @@ +#ifndef __stdlib_h +#define __stdlib_h + +//FIXME add const to qfcc? +// If compare is nil, the value pointed to by key and the first member of the +// elements in the array are treated as ints, making for fast searches when the +// first member of the element is the key and is a simple int +void *bsearch (void *key, void *array, int nmemb, int size, + int (*compare) (void *a, void *b)); +void *fbsearch (void *key, void *array, int nmemb, int size, + int (*compare) (void *a, void *b)); +void *qsort (void *array, int nmemb, int size, + int (*compare) (void *a, void *b)); +@overload void prefixsum (int *array, int count); +@overload void prefixsum (float *array, int count); + +#endif//__stdlib_h diff --git a/ruamoko/lib/Makemodule.am b/ruamoko/lib/Makemodule.am index 0d189f6b7..5711a0b24 100644 --- a/ruamoko/lib/Makemodule.am +++ b/ruamoko/lib/Makemodule.am @@ -17,6 +17,7 @@ ruamoko_lib_libr_a_SOURCES=\ ruamoko/lib/qfs.r \ ruamoko/lib/script.r \ ruamoko/lib/sound.r \ + ruamoko/lib/stdlib.r \ ruamoko/lib/string.r \ ruamoko/lib/math.r \ ruamoko/lib/types.r \ diff --git a/ruamoko/lib/stdlib.r b/ruamoko/lib/stdlib.r new file mode 100644 index 000000000..e1145e913 --- /dev/null +++ b/ruamoko/lib/stdlib.r @@ -0,0 +1,11 @@ +#include + +void *bsearch (void *key, void *array, int nmemb, int size, + int (*compare) (void *a, void *b)) = #0; +void *fbsearch (void *key, void *array, int nmemb, int size, + int (*compare) (void *a, void *b)) = #0; +void *qsort (void *array, int nmemb, int size, + int (*compare) (void *a, void *b)) = #0; + +void prefixsum (int *array, int count) = #0; +void prefixsum (float *array, int count) = #0;