X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/fca81a8d405cd4c825e144099c54dd163636aa3b..8d3655be5a5c41b1f0a9985bcdb614693fce67e5:/src/fns.c diff --git a/src/fns.c b/src/fns.c index 20770af67d..82ce933b25 100644 --- a/src/fns.c +++ b/src/fns.c @@ -1,6 +1,6 @@ /* Random utility Lisp functions. - Copyright (C) 1985-1987, 1993-1995, 1997-2012 - Free Software Foundation, Inc. + +Copyright (C) 1985-1987, 1993-1995, 1997-2013 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -21,7 +21,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include @@ -62,11 +61,15 @@ DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, DEFUN ("random", Frandom, Srandom, 0, 1, 0, doc: /* Return a pseudo-random number. -All integers representable in Lisp are equally likely. - On most systems, this is 29 bits' worth. +All integers representable in Lisp, i.e. between `most-negative-fixnum' +and `most-positive-fixnum', inclusive, are equally likely. + With positive integer LIMIT, return random number in interval [0,LIMIT). With argument t, set the random number seed from the current time and pid. -Other values of LIMIT are ignored. */) +With a string argument, set the seed based on the string's contents. +Other values of LIMIT are ignored. + +See Info node `(elisp)Random Numbers' for more details. */) (Lisp_Object limit) { EMACS_INT val; @@ -86,7 +89,7 @@ Other values of LIMIT are ignored. */) before it's time to do a QUIT. This must be a power of 2. */ enum { QUIT_COUNT_HEURISTIC = 1 << 16 }; -/* Random data-structure functions */ +/* Random data-structure functions. */ DEFUN ("length", Flength, Slength, 1, 1, 0, doc: /* Return the length of vector, list or string SEQUENCE. @@ -211,12 +214,18 @@ Symbols are also allowed; their print names are used instead. */) DEFUN ("compare-strings", Fcompare_strings, Scompare_strings, 6, 7, 0, doc: /* Compare the contents of two strings, converting to multibyte if needed. -In string STR1, skip the first START1 characters and stop at END1. -In string STR2, skip the first START2 characters and stop at END2. -END1 and END2 default to the full lengths of the respective strings. - -Case is significant in this comparison if IGNORE-CASE is nil. -Unibyte strings are converted to multibyte for comparison. +The arguments START1, END1, START2, and END2, if non-nil, are +positions specifying which parts of STR1 or STR2 to compare. In +string STR1, compare the part between START1 (inclusive) and END1 +\(exclusive). If START1 is nil, it defaults to 0, the beginning of +the string; if END1 is nil, it defaults to the length of the string. +Likewise, in string STR2, compare the part between START2 and END2. + +The strings are compared by the numeric values of their characters. +For instance, STR1 is "less than" STR2 if its first differing +character has a smaller numeric value. If IGNORE-CASE is non-nil, +characters are converted to lower-case before comparing them. Unibyte +strings are converted to multibyte for comparison. The value is t if the strings (or specified portions) match. If string STR1 is less, the value is a negative number N; @@ -1527,11 +1536,14 @@ The value is actually the first element of LIST whose cdr equals KEY. */) } DEFUN ("delq", Fdelq, Sdelq, 2, 2, 0, - doc: /* Delete by side effect any occurrences of ELT as a member of LIST. -The modified LIST is returned. Comparison is done with `eq'. -If the first member of LIST is ELT, there is no way to remove it by side effect; -therefore, write `(setq foo (delq element foo))' -to be sure of changing the value of `foo'. */) + doc: /* Delete members of LIST which are `eq' to ELT, and return the result. +More precisely, this function skips any members `eq' to ELT at the +front of LIST, then removes members `eq' to ELT from the remaining +sublist by modifying its list structure, then returns the resulting +list. + +Write `(setq foo (delq element foo))' to be sure of correctly changing +the value of a list `foo'. */) (register Lisp_Object elt, Lisp_Object list) { register Lisp_Object tail, prev; @@ -1559,13 +1571,19 @@ to be sure of changing the value of `foo'. */) } DEFUN ("delete", Fdelete, Sdelete, 2, 2, 0, - doc: /* Delete by side effect any occurrences of ELT as a member of SEQ. -SEQ must be a list, a vector, or a string. -The modified SEQ is returned. Comparison is done with `equal'. -If SEQ is not a list, or the first member of SEQ is ELT, deleting it -is not a side effect; it is simply using a different sequence. -Therefore, write `(setq foo (delete element foo))' -to be sure of changing the value of `foo'. */) + doc: /* Delete members of SEQ which are `equal' to ELT, and return the result. +SEQ must be a sequence (i.e. a list, a vector, or a string). +The return value is a sequence of the same type. + +If SEQ is a list, this behaves like `delq', except that it compares +with `equal' instead of `eq'. In particular, it may remove elements +by altering the list structure. + +If SEQ is not a list, deletion is never performed destructively; +instead this function creates and returns a new vector or string. + +Write `(setq foo (delete element foo))' to be sure of correctly +changing the value of a sequence `foo'. */) (Lisp_Object elt, Lisp_Object seq) { if (VECTORP (seq)) @@ -1680,7 +1698,7 @@ to be sure of changing the value of `foo'. */) DEFUN ("nreverse", Fnreverse, Snreverse, 1, 1, 0, doc: /* Reverse LIST by modifying cdr pointers. -Return the reversed list. */) +Return the reversed list. Expects a properly nil-terminated list. */) (Lisp_Object list) { register Lisp_Object prev, tail, next; @@ -1691,7 +1709,7 @@ Return the reversed list. */) while (!NILP (tail)) { QUIT; - CHECK_LIST_CONS (tail, list); + CHECK_LIST_CONS (tail, tail); next = XCDR (tail); Fsetcdr (tail, prev); prev = tail; @@ -1830,13 +1848,6 @@ properties on the list. This function never signals an error. */) halftail = XCDR (halftail); if (EQ (tail, halftail)) break; - -#if 0 /* Unsafe version. */ - /* This function can be called asynchronously - (setup_coding_system). Don't QUIT in that case. */ - if (!interrupt_input_blocked) - QUIT; -#endif } return Qnil; @@ -2012,7 +2023,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props) d1 = extract_float (o1); d2 = extract_float (o2); /* If d is a NaN, then d != d. Two NaNs should be `equal' even - though they are not =. */ + though they are not =. */ return d1 == d2 || (d1 != d1 && d2 != d2); } @@ -2074,9 +2085,8 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props) are sensible to compare, so eliminate the others now. */ if (size & PSEUDOVECTOR_FLAG) { - if (!(size & ((PVEC_COMPILED | PVEC_CHAR_TABLE - | PVEC_SUB_CHAR_TABLE | PVEC_FONT) - << PSEUDOVECTOR_SIZE_BITS))) + if (((size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) + < PVEC_COMPILED) return 0; size &= PSEUDOVECTOR_SIZE_MASK; } @@ -2475,7 +2485,7 @@ is nil, and `use-dialog-box' is non-nil. */) Fding (Qnil); Fdiscard_input (); - message ("Please answer yes or no."); + message1 ("Please answer yes or no."); Fsleep_for (make_number (2), Qnil); } } @@ -2735,7 +2745,7 @@ ARGS are passed as extra arguments to the function. usage: (widget-apply WIDGET PROPERTY &rest ARGS) */) (ptrdiff_t nargs, Lisp_Object *args) { - /* This function can GC. */ + /* This function can GC. */ Lisp_Object newargs[3]; struct gcpro gcpro1, gcpro2; Lisp_Object result; @@ -2797,9 +2807,8 @@ The data read from the system are decoded using `locale-coding-system'. */) val = build_unibyte_string (str); /* Fixme: Is this coding system necessarily right, even if it is consistent with CODESET? If not, what to do? */ - Faset (v, make_number (i), - code_convert_string_norecord (val, Vlocale_coding_system, - 0)); + ASET (v, i, code_convert_string_norecord (val, Vlocale_coding_system, + 0)); } UNGCPRO; return v; @@ -2819,8 +2828,8 @@ The data read from the system are decoded using `locale-coding-system'. */) { str = nl_langinfo (months[i]); val = build_unibyte_string (str); - Faset (v, make_number (i), - code_convert_string_norecord (val, Vlocale_coding_system, 0)); + ASET (v, i, code_convert_string_norecord (val, Vlocale_coding_system, + 0)); } UNGCPRO; return v; @@ -2830,10 +2839,7 @@ The data read from the system are decoded using `locale-coding-system'. */) but is in the locale files. This could be used by ps-print. */ #ifdef PAPER_WIDTH else if (EQ (item, Qpaper)) - { - return list2 (make_number (nl_langinfo (PAPER_WIDTH)), - make_number (nl_langinfo (PAPER_HEIGHT))); - } + return list2i (nl_langinfo (PAPER_WIDTH), nl_langinfo (PAPER_HEIGHT)); #endif /* PAPER_WIDTH */ #endif /* HAVE_LANGINFO_CODESET*/ return Qnil; @@ -3330,19 +3336,11 @@ static struct Lisp_Hash_Table *weak_hash_tables; /* Various symbols. */ -static Lisp_Object Qhash_table_p, Qkey, Qvalue; -Lisp_Object Qeq, Qeql, Qequal; +static Lisp_Object Qhash_table_p, Qkey, Qvalue, Qeql; +Lisp_Object Qeq, Qequal; Lisp_Object QCtest, QCsize, QCrehash_size, QCrehash_threshold, QCweakness; static Lisp_Object Qhash_table_test, Qkey_or_value, Qkey_and_value; -/* Function prototypes. */ - -static struct Lisp_Hash_Table *check_hash_table (Lisp_Object); -static ptrdiff_t get_key_arg (Lisp_Object, ptrdiff_t, Lisp_Object *, char *); -static void maybe_resize_hash_table (struct Lisp_Hash_Table *); -static bool sweep_weak_table (struct Lisp_Hash_Table *, bool); - - /*********************************************************************** Utilities @@ -3411,7 +3409,7 @@ larger_vector (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max) ptrdiff_t n_max = (0 <= nitems_max && nitems_max < C_language_max ? nitems_max : C_language_max); eassert (VECTORP (vec)); - eassert (0 < incr_min && -1 <= nitems_max); + eassert (incr_min > 0 && nitems_max >= -1); old_size = ASIZE (vec); incr_max = n_max - old_size; incr = max (incr_min, min (old_size >> 1, incr_max)); @@ -3431,14 +3429,17 @@ larger_vector (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max) Low-level Functions ***********************************************************************/ +static struct hash_table_test hashtest_eq; +struct hash_table_test hashtest_eql, hashtest_equal; + /* Compare KEY1 which has hash code HASH1 and KEY2 with hash code HASH2 in hash table H using `eql'. Value is true if KEY1 and KEY2 are the same. */ static bool -cmpfn_eql (struct Lisp_Hash_Table *h, - Lisp_Object key1, EMACS_UINT hash1, - Lisp_Object key2, EMACS_UINT hash2) +cmpfn_eql (struct hash_table_test *ht, + Lisp_Object key1, + Lisp_Object key2) { return (FLOATP (key1) && FLOATP (key2) @@ -3451,11 +3452,11 @@ cmpfn_eql (struct Lisp_Hash_Table *h, KEY2 are the same. */ static bool -cmpfn_equal (struct Lisp_Hash_Table *h, - Lisp_Object key1, EMACS_UINT hash1, - Lisp_Object key2, EMACS_UINT hash2) +cmpfn_equal (struct hash_table_test *ht, + Lisp_Object key1, + Lisp_Object key2) { - return hash1 == hash2 && !NILP (Fequal (key1, key2)); + return !NILP (Fequal (key1, key2)); } @@ -3464,21 +3465,16 @@ cmpfn_equal (struct Lisp_Hash_Table *h, if KEY1 and KEY2 are the same. */ static bool -cmpfn_user_defined (struct Lisp_Hash_Table *h, - Lisp_Object key1, EMACS_UINT hash1, - Lisp_Object key2, EMACS_UINT hash2) +cmpfn_user_defined (struct hash_table_test *ht, + Lisp_Object key1, + Lisp_Object key2) { - if (hash1 == hash2) - { - Lisp_Object args[3]; + Lisp_Object args[3]; - args[0] = h->user_cmp_function; - args[1] = key1; - args[2] = key2; - return !NILP (Ffuncall (3, args)); - } - else - return 0; + args[0] = ht->user_cmp_function; + args[1] = key1; + args[2] = key2; + return !NILP (Ffuncall (3, args)); } @@ -3487,54 +3483,48 @@ cmpfn_user_defined (struct Lisp_Hash_Table *h, in a Lisp integer. */ static EMACS_UINT -hashfn_eq (struct Lisp_Hash_Table *h, Lisp_Object key) +hashfn_eq (struct hash_table_test *ht, Lisp_Object key) { - EMACS_UINT hash = XUINT (key) ^ XTYPE (key); - eassert ((hash & ~INTMASK) == 0); + EMACS_UINT hash = XHASH (key) ^ XTYPE (key); return hash; } - /* Value is a hash code for KEY for use in hash table H which uses `eql' to compare keys. The hash code returned is guaranteed to fit in a Lisp integer. */ static EMACS_UINT -hashfn_eql (struct Lisp_Hash_Table *h, Lisp_Object key) +hashfn_eql (struct hash_table_test *ht, Lisp_Object key) { EMACS_UINT hash; if (FLOATP (key)) hash = sxhash (key, 0); else - hash = XUINT (key) ^ XTYPE (key); - eassert ((hash & ~INTMASK) == 0); + hash = XHASH (key) ^ XTYPE (key); return hash; } - /* Value is a hash code for KEY for use in hash table H which uses `equal' to compare keys. The hash code returned is guaranteed to fit in a Lisp integer. */ static EMACS_UINT -hashfn_equal (struct Lisp_Hash_Table *h, Lisp_Object key) +hashfn_equal (struct hash_table_test *ht, Lisp_Object key) { EMACS_UINT hash = sxhash (key, 0); - eassert ((hash & ~INTMASK) == 0); return hash; } - /* Value is a hash code for KEY for use in hash table H which uses as user-defined function to compare keys. The hash code returned is guaranteed to fit in a Lisp integer. */ static EMACS_UINT -hashfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key) +hashfn_user_defined (struct hash_table_test *ht, Lisp_Object key) { Lisp_Object args[2], hash; - args[0] = h->user_hash_function; + args[0] = ht->user_hash_function; args[1] = key; hash = Ffuncall (2, args); if (!INTEGERP (hash)) @@ -3570,9 +3560,9 @@ hashfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key) one of the symbols `key', `value', `key-or-value', or `key-and-value'. */ Lisp_Object -make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size, - Lisp_Object rehash_threshold, Lisp_Object weak, - Lisp_Object user_test, Lisp_Object user_hash) +make_hash_table (struct hash_table_test test, + Lisp_Object size, Lisp_Object rehash_size, + Lisp_Object rehash_threshold, Lisp_Object weak) { struct Lisp_Hash_Table *h; Lisp_Object table; @@ -3581,12 +3571,12 @@ make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size, double index_float; /* Preconditions. */ - eassert (SYMBOLP (test)); + eassert (SYMBOLP (test.name)); eassert (INTEGERP (size) && XINT (size) >= 0); eassert ((INTEGERP (rehash_size) && XINT (rehash_size) > 0) - || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size))); + || (FLOATP (rehash_size) && XFLOAT_DATA (rehash_size) > 1)); eassert (FLOATP (rehash_threshold) - && 0 < XFLOAT_DATA (rehash_threshold) + && XFLOAT_DATA (rehash_threshold) > 0 && XFLOAT_DATA (rehash_threshold) <= 1.0); if (XFASTINT (size) == 0) @@ -3605,29 +3595,6 @@ make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size, /* Initialize hash table slots. */ h->test = test; - if (EQ (test, Qeql)) - { - h->cmpfn = cmpfn_eql; - h->hashfn = hashfn_eql; - } - else if (EQ (test, Qeq)) - { - h->cmpfn = NULL; - h->hashfn = hashfn_eq; - } - else if (EQ (test, Qequal)) - { - h->cmpfn = cmpfn_equal; - h->hashfn = hashfn_equal; - } - else - { - h->user_cmp_function = user_test; - h->user_hash_function = user_hash; - h->cmpfn = cmpfn_user_defined; - h->hashfn = hashfn_user_defined; - } - h->weak = weak; h->rehash_threshold = rehash_threshold; h->rehash_size = rehash_size; @@ -3667,12 +3634,9 @@ copy_hash_table (struct Lisp_Hash_Table *h1) { Lisp_Object table; struct Lisp_Hash_Table *h2; - struct Lisp_Vector *next; h2 = allocate_hash_table (); - next = h2->header.next.vector; - memcpy (h2, h1, sizeof *h2); - h2->header.next.vector = next; + *h2 = *h1; h2->key_and_value = Fcopy_sequence (h1->key_and_value); h2->hash = Fcopy_sequence (h1->hash); h2->next = Fcopy_sequence (h1->next); @@ -3693,7 +3657,7 @@ copy_hash_table (struct Lisp_Hash_Table *h1) /* Resize hash table H if it's too full. If H cannot be resized because it's already too large, throw an error. */ -static inline void +static void maybe_resize_hash_table (struct Lisp_Hash_Table *h) { if (NILP (h->next_free)) @@ -3786,7 +3750,8 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash) ptrdiff_t start_of_bucket; Lisp_Object idx; - hash_code = h->hashfn (h, key); + hash_code = h->test.hashfn (&h->test, key); + eassert ((hash_code & ~INTMASK) == 0); if (hash) *hash = hash_code; @@ -3798,9 +3763,9 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash) { ptrdiff_t i = XFASTINT (idx); if (EQ (key, HASH_KEY (h, i)) - || (h->cmpfn - && h->cmpfn (h, key, hash_code, - HASH_KEY (h, i), XUINT (HASH_HASH (h, i))))) + || (h->test.cmpfn + && hash_code == XUINT (HASH_HASH (h, i)) + && h->test.cmpfn (&h->test, key, HASH_KEY (h, i)))) break; idx = HASH_NEXT (h, i); } @@ -3851,7 +3816,8 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key) ptrdiff_t start_of_bucket; Lisp_Object idx, prev; - hash_code = h->hashfn (h, key); + hash_code = h->test.hashfn (&h->test, key); + eassert ((hash_code & ~INTMASK) == 0); start_of_bucket = hash_code % ASIZE (h->index); idx = HASH_INDEX (h, start_of_bucket); prev = Qnil; @@ -3862,9 +3828,9 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key) ptrdiff_t i = XFASTINT (idx); if (EQ (key, HASH_KEY (h, i)) - || (h->cmpfn - && h->cmpfn (h, key, hash_code, - HASH_KEY (h, i), XUINT (HASH_HASH (h, i))))) + || (h->test.cmpfn + && hash_code == XUINT (HASH_HASH (h, i)) + && h->test.cmpfn (&h->test, key, HASH_KEY (h, i)))) { /* Take entry out of collision chain. */ if (NILP (prev)) @@ -4076,17 +4042,6 @@ sweep_weak_hash_tables (void) #define SXHASH_MAX_LEN 7 -/* Combine two integers X and Y for hashing. The result might not fit - into a Lisp integer. */ - -#define SXHASH_COMBINE(X, Y) \ - ((((EMACS_UINT) (X) << 4) + ((EMACS_UINT) (X) >> (BITS_PER_EMACS_INT - 4))) \ - + (EMACS_UINT) (Y)) - -/* Hash X, returning a value that fits into a Lisp integer. */ -#define SXHASH_REDUCE(X) \ - ((((X) ^ (X) >> (BITS_PER_EMACS_INT - FIXNUM_BITS))) & INTMASK) - /* Return a hash for string PTR which has length LEN. The hash value can be any EMACS_UINT value. */ @@ -4101,7 +4056,7 @@ hash_string (char const *ptr, ptrdiff_t len) while (p != end) { c = *p++; - hash = SXHASH_COMBINE (hash, c); + hash = sxhash_combine (hash, c); } return hash; @@ -4119,7 +4074,7 @@ sxhash_string (char const *ptr, ptrdiff_t len) /* Return a hash for the floating point value VAL. */ -static EMACS_INT +static EMACS_UINT sxhash_float (double val) { EMACS_UINT hash = 0; @@ -4135,7 +4090,7 @@ sxhash_float (double val) u.val = val; memset (&u.val + 1, 0, sizeof u - sizeof u.val); for (i = 0; i < WORDS_PER_DOUBLE; i++) - hash = SXHASH_COMBINE (hash, u.word[i]); + hash = sxhash_combine (hash, u.word[i]); return SXHASH_REDUCE (hash); } @@ -4154,13 +4109,13 @@ sxhash_list (Lisp_Object list, int depth) list = XCDR (list), ++i) { EMACS_UINT hash2 = sxhash (XCAR (list), depth + 1); - hash = SXHASH_COMBINE (hash, hash2); + hash = sxhash_combine (hash, hash2); } if (!NILP (list)) { EMACS_UINT hash2 = sxhash (list, depth + 1); - hash = SXHASH_COMBINE (hash, hash2); + hash = sxhash_combine (hash, hash2); } return SXHASH_REDUCE (hash); @@ -4180,7 +4135,7 @@ sxhash_vector (Lisp_Object vec, int depth) for (i = 0; i < n; ++i) { EMACS_UINT hash2 = sxhash (AREF (vec, i), depth + 1); - hash = SXHASH_COMBINE (hash, hash2); + hash = sxhash_combine (hash, hash2); } return SXHASH_REDUCE (hash); @@ -4196,7 +4151,7 @@ sxhash_bool_vector (Lisp_Object vec) n = min (SXHASH_MAX_LEN, XBOOL_VECTOR (vec)->header.size); for (i = 0; i < n; ++i) - hash = SXHASH_COMBINE (hash, XBOOL_VECTOR (vec)->data[i]); + hash = sxhash_combine (hash, XBOOL_VECTOR (vec)->data[i]); return SXHASH_REDUCE (hash); } @@ -4220,7 +4175,7 @@ sxhash (Lisp_Object obj, int depth) break; case Lisp_Misc: - hash = XUINT (obj); + hash = XHASH (obj); break; case Lisp_Symbol: @@ -4244,7 +4199,7 @@ sxhash (Lisp_Object obj, int depth) else /* Others are `equal' if they are `eq', so let's take their address as hash. */ - hash = XUINT (obj); + hash = XHASH (obj); break; case Lisp_Cons: @@ -4313,7 +4268,7 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */) (ptrdiff_t nargs, Lisp_Object *args) { Lisp_Object test, size, rehash_size, rehash_threshold, weak; - Lisp_Object user_test, user_hash; + struct hash_table_test testdesc; char *used; ptrdiff_t i; @@ -4325,7 +4280,13 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */) /* See if there's a `:test TEST' among the arguments. */ i = get_key_arg (QCtest, nargs, args, used); test = i ? args[i] : Qeql; - if (!EQ (test, Qeq) && !EQ (test, Qeql) && !EQ (test, Qequal)) + if (EQ (test, Qeq)) + testdesc = hashtest_eq; + else if (EQ (test, Qeql)) + testdesc = hashtest_eql; + else if (EQ (test, Qequal)) + testdesc = hashtest_equal; + else { /* See if it is a user-defined test. */ Lisp_Object prop; @@ -4333,11 +4294,12 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */) prop = Fget (test, Qhash_table_test); if (!CONSP (prop) || !CONSP (XCDR (prop))) signal_error ("Invalid hash table test", test); - user_test = XCAR (prop); - user_hash = XCAR (XCDR (prop)); + testdesc.name = test; + testdesc.user_cmp_function = XCAR (prop); + testdesc.user_hash_function = XCAR (XCDR (prop)); + testdesc.hashfn = hashfn_user_defined; + testdesc.cmpfn = cmpfn_user_defined; } - else - user_test = user_hash = Qnil; /* See if there's a `:size SIZE' argument. */ i = get_key_arg (QCsize, nargs, args, used); @@ -4350,15 +4312,15 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */) /* Look for `:rehash-size SIZE'. */ i = get_key_arg (QCrehash_size, nargs, args, used); rehash_size = i ? args[i] : make_float (DEFAULT_REHASH_SIZE); - if (! ((INTEGERP (rehash_size) && 0 < XINT (rehash_size)) - || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size)))) + if (! ((INTEGERP (rehash_size) && XINT (rehash_size) > 0) + || (FLOATP (rehash_size) && XFLOAT_DATA (rehash_size) > 1))) signal_error ("Invalid hash table rehash size", rehash_size); /* Look for `:rehash-threshold THRESHOLD'. */ i = get_key_arg (QCrehash_threshold, nargs, args, used); rehash_threshold = i ? args[i] : make_float (DEFAULT_REHASH_THRESHOLD); if (! (FLOATP (rehash_threshold) - && 0 < XFLOAT_DATA (rehash_threshold) + && XFLOAT_DATA (rehash_threshold) > 0 && XFLOAT_DATA (rehash_threshold) <= 1)) signal_error ("Invalid hash table rehash threshold", rehash_threshold); @@ -4379,8 +4341,7 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */) if (!used[i]) signal_error ("Invalid argument list", args[i]); - return make_hash_table (test, size, rehash_size, rehash_threshold, weak, - user_test, user_hash); + return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak); } @@ -4434,7 +4395,7 @@ DEFUN ("hash-table-test", Fhash_table_test, Shash_table_test, 1, 1, 0, doc: /* Return the test TABLE uses. */) (Lisp_Object table) { - return check_hash_table (table)->test; + return check_hash_table (table)->test.name; } @@ -4998,4 +4959,14 @@ this variable. */); defsubr (&Smd5); defsubr (&Ssecure_hash); defsubr (&Slocale_info); + + { + struct hash_table_test + eq = { Qeq, Qnil, Qnil, NULL, hashfn_eq }, + eql = { Qeql, Qnil, Qnil, cmpfn_eql, hashfn_eql }, + equal = { Qequal, Qnil, Qnil, cmpfn_equal, hashfn_equal }; + hashtest_eq = eq; + hashtest_eql = eql; + hashtest_equal = equal; + } }