From e84a9d609381731e3d93bc45aba4458e33d0f116 Mon Sep 17 00:00:00 2001 From: Ralph Zitz Date: Fri, 15 Nov 2019 19:47:21 +0100 Subject: [PATCH] Create 0002-patch-for-3.6.0-7-ge196172.patch This patch re-introduces alists to the 3.6.0 (and should apply with no or at least less issues) --- alists/0002-patch-for-3.6.0-7-ge196172.patch | 826 +++++++++++++++++++ 1 file changed, 826 insertions(+) create mode 100644 alists/0002-patch-for-3.6.0-7-ge196172.patch diff --git a/alists/0002-patch-for-3.6.0-7-ge196172.patch b/alists/0002-patch-for-3.6.0-7-ge196172.patch new file mode 100644 index 0000000..298f783 --- /dev/null +++ b/alists/0002-patch-for-3.6.0-7-ge196172.patch @@ -0,0 +1,826 @@ +diff -r -N -a -u ldmud/src/array.c ldmud-alists/src/array.c +--- ldmud/src/array.c 2019-11-15 18:32:58.161876071 +0000 ++++ ldmud-alists/src/array.c 2019-11-15 18:00:37.000000000 +0000 +@@ -325,6 +325,42 @@ + } + + /*-------------------------------------------------------------------------*/ ++#ifdef USE_ALISTS ++static INLINE vector_t * ++i_shrink_array (vector_t *p, mp_int n) ++ ++/* Create and return a new array containing just the first elements ++ * of

.

itself is freed (and thus possibly deallocated). ++ * This function is only needed if alists are used. ++ */ ++ ++{ ++ vector_t *res; ++ ++ if (p->ref == 1 && VEC_SIZE(p) == n) ++ return p; ++ /* This case seems to happen often enough to justify ++ * the shortcut ++ */ ++ ++ if (n) ++ { ++ res = slice_array(p, 0, n-1); ++ } ++ else ++ { ++ res = ref_array(&null_vector); ++ } ++ free_array(p); ++ return res; ++} ++ ++vector_t * shrink_array (vector_t *p, mp_int n) { return i_shrink_array(p, n); } ++ ++#define shrink_array(p,n) i_shrink_array(p,n) ++#endif ++ ++/*-------------------------------------------------------------------------*/ + void + set_vector_user (vector_t *p, object_t *owner) + +diff -r -N -a -u ldmud/src/array.h ldmud-alists/src/array.h +--- ldmud/src/array.h 2019-11-15 18:32:58.162876071 +0000 ++++ ldmud-alists/src/array.h 2019-11-15 18:00:37.000000000 +0000 +@@ -100,6 +100,10 @@ + extern void set_vector_user(vector_t *p, object_t *owner); + extern long total_array_size(void); + ++#ifdef USE_ALISTS ++extern vector_t * shrink_array (vector_t *p, mp_int n); ++#endif ++ + #if defined(GC_SUPPORT) + extern void clear_array_size (void); + extern void count_array_size (vector_t *vec); +diff -r -N -a -u ldmud/src/autoconf/configure.ac ldmud-alists/src/autoconf/configure.ac +--- ldmud/src/autoconf/configure.ac 2019-11-15 18:32:58.165876071 +0000 ++++ ldmud-alists/src/autoconf/configure.ac 2019-11-15 18:00:37.000000000 +0000 +@@ -216,6 +216,7 @@ + AC_MY_ARG_ENABLE(filename-spaces,no,,[Allow space characters in filenames]) + AC_MY_ARG_ENABLE(share-variables,no,,[Enable clone initialization from blueprint variable values]) + AC_MY_ARG_ENABLE(use-ipv6,no,,[Enables support for IPv6]) ++AC_MY_ARG_ENABLE(use-alists,no,,[Enables alist support]) + AC_MY_ARG_ENABLE(use-mccp,no,,[Enables MCCP support]) + AC_MY_ARG_ENABLE(use-mysql,no,,[Enables mySQL support]) + AC_MY_ARG_ENABLE(use-pgsql,no,,[Enables PostgreSQL support]) +@@ -508,6 +509,7 @@ + AC_CDEF_FROM_ENABLE(strict_euids) + AC_CDEF_FROM_ENABLE(filename_spaces) + AC_CDEF_FROM_ENABLE(share_variables) ++AC_CDEF_FROM_ENABLE(use_alists) + AC_CDEF_FROM_ENABLE(use_mccp) + AC_CDEF_FROM_ENABLE(use_ipv6) + AC_CDEF_FROM_ENABLE(use_deprecated) +@@ -2577,6 +2579,7 @@ + AC_SUBST(cdef_use_json) + AC_SUBST(cdef_use_python) + AC_SUBST(cdef_use_xml) ++AC_SUBST(cdef_use_alists) + AC_SUBST(cdef_use_mccp) + AC_SUBST(cdef_use_pcre) + AC_SUBST(cdef_use_deprecated) +diff -r -N -a -u ldmud/src/config.h.in ldmud-alists/src/config.h.in +--- ldmud/src/config.h.in 2019-11-15 18:32:58.173876071 +0000 ++++ ldmud-alists/src/config.h.in 2019-11-15 18:00:37.000000000 +0000 +@@ -375,6 +375,10 @@ + */ + @cdef_python_script@ PYTHON_STARTUP_SCRIPT @val_python_script@ + ++/* Define this if you want alist support. ++ */ ++@cdef_use_alists@ USE_ALISTS ++ + /* Define this if you want PCRE instead of traditional regexps. + */ + @cdef_use_pcre@ USE_PCRE +diff -r -N -a -u ldmud/src/func_spec ldmud-alists/src/func_spec +--- ldmud/src/func_spec 2019-11-15 18:32:58.179876071 +0000 ++++ ldmud-alists/src/func_spec 2019-11-15 18:00:37.000000000 +0000 +@@ -648,6 +648,16 @@ + + #ifdef USE_SQLITE + ++#ifdef USE_ALISTS ++ ++mixed assoc(mixed, mixed *, mixed|void, mixed|void); ++mixed insert_alist(mixed, mixed, ...); ++mixed *intersect_alist(mixed *,mixed *); ++mixed *order_alist(mixed *, void|mixed *, ...); ++ ++#endif /* USE_ALISTS */ ++ ++ + int sl_open(string); + mixed sl_exec(string, ...); + int sl_insert_id(); +diff -r -N -a -u ldmud/src/lex.c ldmud-alists/src/lex.c +--- ldmud/src/lex.c 2019-11-15 18:32:58.192876072 +0000 ++++ ldmud-alists/src/lex.c 2019-11-15 18:05:26.000000000 +0000 +@@ -847,6 +847,9 @@ + #ifdef USE_JSON + add_permanent_define_str("__JSON__", -1, "1"); + #endif ++#ifdef USE_ALISTS ++ add_permanent_define_str("__ALISTS__", -1, "1"); ++#endif + #ifdef HAS_PCRE + add_permanent_define_str("__PCRE__", -1, "1"); + #endif +diff -r -N -a -u ldmud/src/main.c ldmud-alists/src/main.c +--- ldmud/src/main.c 2019-11-15 18:32:58.193876072 +0000 ++++ ldmud-alists/src/main.c 2019-11-15 18:00:37.000000000 +0000 +@@ -2002,6 +2002,9 @@ + #ifdef USE_SQLITE + , "SQLite3 supported\n" + #endif ++#ifdef USE_ALISTS ++ , "Alists supported\n" ++#endif + #ifdef USE_TLS + , "TLS supported (" + # if defined(HAS_OPENSSL) +diff -r -N -a -u ldmud/src/Makefile.in ldmud-alists/src/Makefile.in +--- ldmud/src/Makefile.in 2019-11-15 18:32:58.159876070 +0000 ++++ ldmud-alists/src/Makefile.in 2019-11-15 18:00:37.000000000 +0000 +@@ -100,7 +100,7 @@ + interpret.c \ + lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \ + otable.c\ +- parser.c parse.c pkg-iksemel.c pkg-xml2.c pkg-idna.c \ ++ parser.c parse.c pkg-alists.c pkg-iksemel.c pkg-xml2.c pkg-idna.c \ + pkg-mccp.c pkg-mysql.c pkg-gcrypt.c pkg-json.c pkg-python.c \ + pkg-pgsql.c pkg-sqlite.c pkg-tls.c pkg-openssl.c pkg-gnutls.c \ + port.c ptrtable.c \ +@@ -112,7 +112,7 @@ + interpret.o \ + lex.o main.o mapping.o md5.o mempools.o mregex.o mstrings.o object.o \ + otable.o \ +- parser.o parse.o pkg-iksemel.o pkg-xml2.o pkg-idna.o \ ++ parser.o parse.o pkg-alists.o pkg-iksemel.o pkg-xml2.o pkg-idna.o \ + pkg-mccp.o pkg-mysql.o pkg-gcrypt.o pkg-json.o pkg-python.o \ + pkg-pgsql.o pkg-sqlite.o pkg-tls.o pkg-openssl.o pkg-gnutls.o \ + port.o ptrtable.o \ +@@ -429,6 +429,11 @@ + array.h prolang.h my-alloca.h typedefs.h driver.h strfuns.h hash.h \ + ptrtable.h sent.h bytecode.h port.h config.h bytecode_gen.h machine.h + ++pkg-alists.o : i-svalue_cmp.h xalloc.h svalue.h simulate.h mstrings.h \ ++ main.h interpret.h array.h my-alloca.h pkg-alists.h typedefs.h driver.h \ ++ closure.h strfuns.h sent.h bytecode.h hash.h backend.h exec.h port.h \ ++ config.h bytecode_gen.h types.h machine.h ++ + pkg-gcrypt.o : ../mudlib/sys/tls.h pkg-gcrypt.h xalloc.h typedefs.h \ + simulate.h main.h driver.h svalue.h strfuns.h sent.h bytecode.h port.h \ + config.h bytecode_gen.h machine.h +diff -r -N -a -u ldmud/src/pkg-alists.c ldmud-alists/src/pkg-alists.c +--- ldmud/src/pkg-alists.c 1970-01-01 00:00:00.000000000 +0000 ++++ ldmud-alists/src/pkg-alists.c 2019-11-15 18:10:08.000000000 +0000 +@@ -0,0 +1,621 @@ ++/*--------------------------------------------------------------------------- ++ * Alist handling functions. ++ * ++ *--------------------------------------------------------------------------- ++ * One special application of arrays are alists: associative lists. ++ * Alists allow the association of data (single values or tuples) with ++ * a key value, which is then used to locate the data in the alist structure. ++ * ++ * Nowadays the same functionality is offered by mappings in a much more ++ * efficient manner, so this usage of alists is deprecated. However, for ++ * reasons explained below, alists can be used as an efficient way to ++ * construct lookup arrays. ++ * ++ * It might be historically interesting to know that the very first ++ * implementations of mappings were mere syntactic sugar for alists. ++ * Furthermore, the LPMud variant of alists offers only a part of the ++ * functionality of 'real' alists. ++ * ++ * Alists are implemented by a vector of vectors. A typical alist ++ * for (key:data1,...,dataN) tuples looks like this: ++ * ++ * alist = ({ ({ key values }) ++ * , ({ data1 values }) ++ * , ... ++ * , ({ dataN values }) ++ * }) ++ * ++ * All subarrays are of the same length, and all the values for one tuple ++ * is found at the same index. For example, if the key for a tuple ++ * is found in alist[0][3], the data values are found in alist[1..N][3]. ++ * ++ * The key value array is sorted to allow fast lookups, the sorting order ++ * uses the internal representation of the key values (which usually has ++ * nothing in common with the meaning of the key values). Three things ++ * however can be guaranteed: ++ * ++ * - integer key values appear in rising order in the key array, though ++ * not necessarily consecutive. ++ * - removing one or more keys does not break the order of the ++ * other keys. ++ * - all strings used as key values are made shared strings. ++ *--------------------------------------------------------------------------- ++ */ ++ ++#include "driver.h" ++#include "typedefs.h" ++ ++#ifdef USE_ALISTS ++ ++#include "pkg-alists.h" ++ ++#include "my-alloca.h" ++#include ++ ++#include "array.h" ++#include "interpret.h" /* destructed_object_ref(), error functions */ ++#include "main.h" ++#include "mstrings.h" ++#include "simulate.h" /* errorf() */ ++#include "svalue.h" ++#include "xalloc.h" ++ ++#include "i-svalue_cmp.h" ++ ++/*-------------------------------------------------------------------------*/ ++static vector_t * ++intersect_ordered_arr (vector_t *a1, vector_t *a2) ++ ++/* Compute the intersection of the two ordered arrays and . ++ * ++ * The result is a new sorted(!) vector with all elements, which are present ++ * in both input vectors. ++ * This function is called by f_intersect_alists(). ++ */ ++ ++{ ++ vector_t *a3; ++ mp_int d, l, i1, i2, a1s, a2s; ++ ++ a1s = (mp_int)VEC_SIZE(a1); ++ a2s = (mp_int)VEC_SIZE(a2); ++ a3 = allocate_array( a1s < a2s ? a1s : a2s); ++ for (i1=i2=l=0; i1 < a1s && i2 < a2s; ) { ++ d = svalue_cmp(&a1->item[i1], &a2->item[i2]); ++ if (d<0) ++ i1++; ++ else if (d>0) ++ i2++; ++ else { ++ assign_svalue_no_free(&a3->item[l++], &a2->item[(i1++,i2++)] ); ++ } ++ } ++ return shrink_array(a3, l); ++} /* intersect_ordered_arr() */ ++ ++/*-------------------------------------------------------------------------*/ ++vector_t * ++order_alist (svalue_t *inlists, int listnum, Bool reuse) ++ ++/* Order the alist and return a new vector with it. The sorting ++ * order is the internal order defined by alist_cmp(). ++ * ++ * is a vector of vectors: ++ * = ({ ({ keys }), ({ data1 }), ..., ({ data }) }) ++ * ++ * If is true, the vectors of are reused for the ++ * vectors of the result when possible, and their entries in are ++ * set to T_INVALID. ++ * ++ * As a side effect, strings in the key vector are made shared, and ++ * destructed objects in key and data vectors are replaced by svalue 0s. ++ * ++ * This function is also called by the compiler for constant expressions. ++ */ ++ ++{ ++ vector_t *outlist; /* The result vector of vectors */ ++ vector_t *v; /* Aux vector pointer */ ++ svalue_t *outlists; /* Next element in outlist to fill in */ ++ ptrdiff_t * sorted; /* The vector elements in sorted order */ ++ svalue_t *inpnt; /* Pointer to the value to copy into the result */ ++ mp_int keynum; /* Number of keys */ ++ int i, j; ++ ++ keynum = (mp_int)VEC_SIZE(inlists[0].u.vec); ++ ++ /* Get the sorting order */ ++ ++ sorted = get_array_order(inlists[0].u.vec); ++ ++ /* Generate the result vectors from the sorting order. ++ */ ++ ++ outlist = allocate_array(listnum); ++ outlists = outlist->item; ++ ++ /* Copy the elements from all inlist vectors into the outlist ++ * vectors. ++ * ++ * At the beginning of every loop v points to the vector to ++ * use as the next 'out' vector. It may be a re-used 'in' vector ++ * from the previous run. ++ */ ++ v = allocate_array(keynum); ++ for (i = listnum; --i >= 0; ) { ++ ++ svalue_t *outpnt; /* Next result value element to fill in */ ++ ++ /* Set the new array v as the next 'out' vector, and init outpnt ++ * and offs. ++ */ ++ put_array(outlists + i, v); ++ outpnt = v->item; ++ ++ v = inlists[i].u.vec; /* Next vector to fill if reusable */ ++ ++ /* Copy the elements. ++ * For a reusable 'in' vector, a simple memory copy is sufficient. ++ * For a new vector, a full assignment is due to keep the refcounters ++ * happy. ++ */ ++ if (reuse && inlists[i].u.vec->ref == 1) { ++ ++ if (i) /* not the last iteration */ ++ inlists[i].type = T_INVALID; ++ ++ for (j = keynum; --j >= 0; ) { ++ inpnt = inlists[i].u.vec->item + sorted[j]; ++ if (destructed_object_ref(inpnt)) ++ { ++ free_svalue(inpnt); ++ put_number(outpnt, 0); ++ outpnt++; ++ } else { ++ *outpnt++ = *inpnt; ++ } ++ inpnt->type = T_INVALID; ++ } ++ ++ } else { ++ ++ if (i) /* Not the last iteration: get new out-vector */ ++ v = allocate_array(keynum); ++ ++ for (j = keynum; --j >= 0; ) { ++ inpnt = inlists[i].u.vec->item + sorted[j]; ++ if (destructed_object_ref(inpnt)) ++ { ++ put_number(outpnt, 0); ++ outpnt++; ++ } else { ++ assign_svalue_no_free(outpnt++, inpnt); ++ } ++ } ++ } /* if (reuse) */ ++ } /* for (listnum) */ ++ ++ xfree(sorted); ++ ++ return outlist; ++} /* order_alist() */ ++ ++/*-------------------------------------------------------------------------*/ ++static svalue_t * ++insert_alist (svalue_t *key, svalue_t * /* TODO: bool */ key_data, vector_t *list) ++ ++/* Implementation of efun insert_alist() ++ * ++ * The function can be used in two ways: ++ * ++ * 1. Insert/replace a (new) : tuple into the alist . ++ * and have to point to an array of svalues. The first ++ * element is the key value, the following values the associated ++ * data values. The function will read as many elements from the ++ * array as necessary to fill the alist . ++ * Result is a fresh copy of the modified alist. ++ * ++ * 2. Lookup a in the alist and return its index. If the key ++ * is not found, return the position at which it would be inserted. ++ * must be NULL, points to the svalue to be looked ++ * up, and points to an alist with at least the key vector. ++ * ++ * If is no alist, the result can be wrong (case 2.) or not ++ * an alist either (case 1.). ++ * ++ * If the is a string, it is made shared. ++ * ++ * TODO: Make the hidden flag 'key_data' a real flag. ++ */ ++ ++{ ++ static svalue_t stmp; /* Result value */ ++ mp_int i,j,ix; ++ mp_int keynum, list_size; /* Number of keys, number of alist vectors */ ++ int new_member; /* Flag if a new tuple is given */ ++ ++ /* If key is a string, make it shared */ ++ if (key->type == T_STRING && !mstr_tabled(key->u.str)) ++ { ++ key->u.str = make_tabled(key->u.str); ++ } ++ ++ keynum = (mp_int)VEC_SIZE(list->item[0].u.vec); ++ ++ /* Locate the key */ ++ ix = lookup_key(key, list->item[0].u.vec); ++ ++ /* If its just a lookup: return the result. ++ */ ++ if (key_data == NULL) { ++ put_number(&stmp, ix < 0 ? -ix-1 : ix); ++ return &stmp; ++ } ++ ++ /* Prepare the result alist vector */ ++ put_array(&stmp, allocate_array(list_size = (mp_int)VEC_SIZE(list))); ++ ++ new_member = ix < 0; ++ if (new_member) ++ ix = -ix-1; ++ ++ /* Loop over all key/data vectors in , insert/replace the ++ * new value and put the new vector into . ++ */ ++ for (i = 0; i < list_size; i++) { ++ vector_t *vtmp; ++ ++ if (new_member) { ++ ++ svalue_t *pstmp = list->item[i].u.vec->item; ++ ++ vtmp = allocate_array(keynum+1); ++ for (j=0; j < ix; j++) { ++ assign_svalue_no_free(&vtmp->item[j], pstmp++); ++ } ++ assign_svalue_no_free(&vtmp->item[ix], i ? &key_data[i] : key ); ++ for (j = ix+1; j <= keynum; j++) { ++ assign_svalue_no_free(&vtmp->item[j], pstmp++); ++ } ++ ++ } else { ++ ++ vtmp = slice_array(list->item[i].u.vec, 0, keynum-1); ++ if (i) ++ assign_svalue(&vtmp->item[ix], &key_data[i]); ++ /* No need to assign the key value: it's already there. */ ++ ++ } ++ ++ stmp.u.vec->item[i].type=T_POINTER; ++ stmp.u.vec->item[i].u.vec=vtmp; ++ } ++ ++ /* Done */ ++ return &stmp; ++} /* insert_alist() */ ++ ++/*=========================================================================*/ ++ ++/* EFUNS */ ++ ++/*-------------------------------------------------------------------------*/ ++svalue_t * ++v_insert_alist (svalue_t *sp, int num_arg) ++ ++/* EFUN insert_alist() ++ * ++ * mixed* insert_alist (mixed key, mixed data..., mixed * alist) ++ * int insert_alist (mixed key, mixed * keys) ++ * ++ * 1. Form: Alist Insertion ++ * ++ * The and all following values are inserted ++ * into the . If an entry for already exists ++ * in the list, just the data values are replaced. The number ++ * of values must match the number of data arrays ++ * in the alist, naturally. ++ * ++ * Result is the updated . ++ * ++ * 2. Form: Key Insertion ++ * ++ * Insert the into the (ordered) array of , so that ++ * subsequent assoc()s can perform quick lookups. Result is the ++ * index at which was inserted (or already found). ++ * ++ * CAVEAT: when working with string keys, the index might no longer ++ * be valid after the next call to insert_alist(). ++ */ ++/* When the key list of an alist contains destructed objects ++ it is better not to free them till the next reordering by ++ order_alist to retain the alist property. ++ */ ++ ++{ ++ int i; ++ vector_t *list; ++ long listsize; ++ size_t keynum; ++ svalue_t *key,*key_data,*ret; ++ static struct { ++ vector_t v; ++ } insert_alist_vec = { { VEC_HEAD(1) } }; ++ /* Mock-alist for the insert_alist() key-insertion form. ++ */ ++ ++ if (sp->type != T_POINTER) ++ vefun_arg_error(num_arg, T_POINTER, sp->type, sp); ++ ++ /* Make up an alist if only a key-insertion is required */ ++ if ( !(listsize = (long)VEC_SIZE(sp->u.vec)) ++ || sp->u.vec->item[0].type != T_POINTER ) ++ { ++ list = &insert_alist_vec.v; ++ *list->item = *sp; ++ listsize = 1; ++ } ++ else ++ list = sp->u.vec; ++ ++ /* Check the validity of the alist */ ++ keynum = VEC_SIZE(list->item[0].u.vec); ++ for (i = 1; i < listsize; i++) ++ { ++ if (list->item[i].type != T_POINTER ++ || (size_t)VEC_SIZE(list->item[i].u.vec) != keynum) ++ { ++ errorf("Type or size mismatch of the data arrays.\n"); ++ /* NOTREACHED */ ++ return sp; ++ } ++ } ++ ++ /* Get and test the data to insert */ ++ if (num_arg == 2) ++ { ++ if (sp[-1].type != T_POINTER) ++ { ++ key_data = NULL; ++ key = sp-1; ++ } ++ else ++ { ++ if (VEC_SIZE(sp[-1].u.vec) != listsize) ++ { ++ errorf("Size mismatch of the data arrays: " ++ "vec size %ld, list size %ld.\n" ++ , (long)VEC_SIZE(sp[-1].u.vec), (long)listsize ++ ); ++ /* NOTREACHED */ ++ return sp; ++ } ++ key_data = key = sp[-1].u.vec->item; ++ } ++ } ++ else ++ { ++ if (num_arg - 1 != listsize) ++ { ++ errorf("Not enough data given: %ld arguments, %ld listsize.\n" ++ , (long)num_arg - 1, (long)listsize); ++ /* NOTREACHED */ ++ return sp; ++ } ++ key_data = key = sp-num_arg+1; ++ } ++ ++ /* Do the insertion */ ++ ret = insert_alist(key,key_data,list); ++ sp = pop_n_elems(num_arg, sp); ++ sp++; ++ *sp = *ret; ++ ++ return sp; ++} /* v_insert_alist() */ ++ ++/*-------------------------------------------------------------------------*/ ++svalue_t * ++v_assoc (svalue_t *sp, int num_arg) ++ ++/* EFUN assoc() ++ * ++ * int assoc (mixed key, mixed *keys) ++ * mixed assoc (mixed key, mixed *alist [, mixed fail] ) ++ * mixed assoc (mixed key, mixed *keys, mixed *data [, mixed fail]) ++ * ++ * Search for in the resp. in the . ++ * ++ * When the key list of an alist contains destructed objects ++ * it is better not to free them till the next reordering by ++ * order_alist to retain the alist property. ++ */ ++ ++{ ++ svalue_t *args; ++ vector_t *keys,*data; ++ svalue_t *fail_val; ++ int ix; ++ ++ args = sp -num_arg +1; ++ ++ /* Analyse the arguments */ ++ if ( !VEC_SIZE(args[1].u.vec) ++ || args[1].u.vec->item[0].type != T_POINTER ) ++ { ++ keys = args[1].u.vec; ++ if (num_arg == 2) ++ { ++ data = NULL; ++ } ++ else ++ { ++ if (args[2].type != T_POINTER ++ || VEC_SIZE(args[2].u.vec) != VEC_SIZE(keys)) ++ { ++ errorf("Number of values in key and data arrays differ.\n"); ++ /* NOTREACHED */ ++ return sp; ++ } ++ data = args[2].u.vec; ++ } ++ if (num_arg == 4) ++ { ++ fail_val = &args[3]; ++ } ++ else ++ { ++ fail_val = &const0; ++ } ++ } ++ else ++ { ++ keys = args[1].u.vec->item[0].u.vec; ++ if (VEC_SIZE(args[1].u.vec) > 1) ++ { ++ if (args[1].u.vec->item[1].type != T_POINTER ++ || VEC_SIZE(args[1].u.vec->item[1].u.vec) != VEC_SIZE(keys)) ++ { ++ errorf("Number of values in key and data arrays differ.\n"); ++ /* NOTREACHED */ ++ return sp; ++ } ++ data = args[1].u.vec->item[1].u.vec; ++ } ++ else ++ { ++ data = NULL; ++ } ++ ++ if (num_arg == 3) fail_val = &args[2]; ++ else if (num_arg == 2) fail_val = &const0; ++ else ++ { ++ errorf("too many args to efun assoc\n"); ++ /* NOTREACHED */ ++ return sp; ++ } ++ } ++ ++ /* Call lookup_key() and push the result */ ++ ix = lookup_key(&args[0],keys); ++ if (data == NULL) ++ { ++ sp = pop_n_elems(num_arg, sp); ++ push_number(sp, ix < 0 ? -1 : ix); ++ } ++ else ++ { ++ assign_svalue(args ++ , ix < 0 ++ ? fail_val ++ : (destructed_object_ref(&data->item[ix]) ++ ? &const0 ++ : &data->item[ix]) ++ ); ++ sp = pop_n_elems(num_arg-1, sp); ++ } ++ ++ return sp; ++} /* v_assoc() */ ++ ++/*-------------------------------------------------------------------------*/ ++svalue_t * ++f_intersect_alist (svalue_t *sp) ++ ++/* EFUN intersect_alist() ++ * ++ * mixed * intersect_alist (mixed * list1, mixed * list2) ++ * ++ * Does a fast set intersection on alist key vectors (NOT on full ++ * alists!). ++ * ++ * The result is a new sorted(!) vector with all elements, which are present ++ * in both input vectors. ++ * ++ * The operator '&' does set intersection on arrays in ++ * general. ++ * ++ * TODO: Maybe rename the efun. ++ */ ++ ++{ ++ vector_t *rc; ++ ++ rc = intersect_ordered_arr(sp[-1].u.vec, sp->u.vec); ++ ++ free_svalue(sp--); ++ free_array(sp->u.vec); ++ sp->u.vec = rc; ++ ++ return sp; ++} /* f_intersect_alist() */ ++ ++/*-------------------------------------------------------------------------*/ ++svalue_t * ++v_order_alist (svalue_t *sp, int num_arg) ++ ++/* EFUN order_alist() ++ * ++ * mixed *order_alist(mixed *keys, mixed *|void data, ...) ++ * ++ * Creates an alist. ++ * ++ * Either takes an array containing keys, and others containing ++ * the associated data, where all arrays are to be of the same ++ * length, or takes a single array that contains as first member ++ * the array of keys and has an arbitrary number of other members ++ * containing data, each of wich has to be of the same length as ++ * the key array. Returns an array holding the sorted key array ++ * and the data arrays; the same permutation that is applied to ++ * the key array is applied to all data arrays. ++ */ ++ ++{ ++ int i; ++ svalue_t *args; ++ vector_t *list; ++ long listsize; ++ Bool reuse; ++ size_t keynum; ++ ++ args = sp-num_arg+1; ++ ++ /* Get the key array to order */ ++ if (num_arg == 1 ++ && ((list = args->u.vec), (listsize = (long)VEC_SIZE(list))) ++ && list->item[0].type == T_POINTER) ++ { ++ args = list->item; ++ reuse = (list->ref == 1); ++ } ++ else ++ { ++ listsize = num_arg; ++ reuse = MY_TRUE; ++ } ++ keynum = VEC_SIZE(args[0].u.vec); ++ ++ /* Get the data arrays to order */ ++ for (i = 0; i < listsize; i++) ++ { ++ if (args[i].type != T_POINTER ++ || (size_t)VEC_SIZE(args[i].u.vec) != keynum) ++ { ++ errorf("bad data array %d in call to order_alist\n",i); ++ } ++ } ++ ++ /* Create the alist */ ++ list = order_alist(args, listsize, reuse); ++ sp = pop_n_elems(num_arg, sp); ++ sp++; ++ put_array(sp, list); ++ ++ return sp; ++} /* v_order_alist() */ ++ ++#endif /* USE_ALISTS */ ++ ++/***************************************************************************/ ++ +diff -r -N -a -u ldmud/src/pkg-alists.h ldmud-alists/src/pkg-alists.h +--- ldmud/src/pkg-alists.h 1970-01-01 00:00:00.000000000 +0000 ++++ ldmud-alists/src/pkg-alists.h 2019-11-15 18:00:37.000000000 +0000 +@@ -0,0 +1,17 @@ ++#ifndef PKG_ALISTS_H__ ++#define PKG_ALISTS_H__ 1 ++ ++#include "driver.h" ++#include "typedefs.h" ++ ++#ifdef USE_ALISTS ++ ++extern vector_t *order_alist (svalue_t *inlists, int listnum, Bool reuse); ++extern svalue_t *v_assoc(svalue_t *sp, int num_arg); ++extern svalue_t *f_intersect_alist(svalue_t *sp); ++extern svalue_t *v_insert_alist(svalue_t *sp, int num_arg); ++extern svalue_t *v_order_alist(svalue_t *sp, int num_arg); ++ ++#endif /* USE_ALISTS */ ++ ++#endif /* PKG_ALISTS_H__ */