aboutsummaryrefslogtreecommitdiffstats
path: root/src/fns.c
diff options
context:
space:
mode:
authorStefan Monnier2012-11-08 14:12:23 -0500
committerStefan Monnier2012-11-08 14:12:23 -0500
commitb7432bb20f48902994bee522bea15acdb0c0e209 (patch)
tree940e242625e16ade096c4144d728c56107aa7005 /src/fns.c
parent880027430c5580abf612a82273bd49b75b9fb73c (diff)
downloademacs-b7432bb20f48902994bee522bea15acdb0c0e209.tar.gz
emacs-b7432bb20f48902994bee522bea15acdb0c0e209.zip
Use ad-hoc comparison function for the profiler's hash-tables.
* src/profiler.c (Qprofiler_backtrace_equal, hashtest_profiler): New vars. (make_log): Use them. (handle_profiler_signal): Don't inhibit quit any longer since we don't call Fequal any more. (Ffunction_equal): New function. (cmpfn_profiler, hashfn_profiler): New functions. (syms_of_profiler): Initialize them. * src/lisp.h (struct hash_table_test): New struct. (struct Lisp_Hash_Table): Use it. * src/alloc.c (mark_object): Mark hash_table_test fields of hash tables. * src/fns.c (make_hash_table): Take a struct to describe the test. (cmpfn_eql, cmpfn_equal, cmpfn_user_defined, hashfn_eq, hashfn_eql) (hashfn_equal, hashfn_user_defined): Adjust to new calling convention. (hash_lookup, hash_remove_from_table): Move assertion checking of hashfn result here. Check hash-equality before calling cmpfn. (Fmake_hash_table): Adjust call to make_hash_table. (hashtest_eq, hashtest_eql, hashtest_equal): New structs. (syms_of_fns): Initialize them. * src/emacs.c (main): Move syms_of_fns earlier. * src/xterm.c (syms_of_xterm): * src/category.c (hash_get_category_set): Adjust call to make_hash_table. * src/print.c (print_object): Adjust to new hash-table struct. * src/composite.c (composition_gstring_put_cache): Adjust to new hashfn.
Diffstat (limited to 'src/fns.c')
-rw-r--r--src/fns.c138
1 files changed, 62 insertions, 76 deletions
diff --git a/src/fns.c b/src/fns.c
index 1d2e510b7e5..6faaa67152e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2014,7 +2014,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props)
2014 d1 = extract_float (o1); 2014 d1 = extract_float (o1);
2015 d2 = extract_float (o2); 2015 d2 = extract_float (o2);
2016 /* If d is a NaN, then d != d. Two NaNs should be `equal' even 2016 /* If d is a NaN, then d != d. Two NaNs should be `equal' even
2017 though they are not =. */ 2017 though they are not =. */
2018 return d1 == d2 || (d1 != d1 && d2 != d2); 2018 return d1 == d2 || (d1 != d1 && d2 != d2);
2019 } 2019 }
2020 2020
@@ -3424,14 +3424,16 @@ larger_vector (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max)
3424 Low-level Functions 3424 Low-level Functions
3425 ***********************************************************************/ 3425 ***********************************************************************/
3426 3426
3427struct hash_table_test hashtest_eq, hashtest_eql, hashtest_equal;
3428
3427/* Compare KEY1 which has hash code HASH1 and KEY2 with hash code 3429/* Compare KEY1 which has hash code HASH1 and KEY2 with hash code
3428 HASH2 in hash table H using `eql'. Value is true if KEY1 and 3430 HASH2 in hash table H using `eql'. Value is true if KEY1 and
3429 KEY2 are the same. */ 3431 KEY2 are the same. */
3430 3432
3431static bool 3433static bool
3432cmpfn_eql (struct Lisp_Hash_Table *h, 3434cmpfn_eql (struct hash_table_test *ht,
3433 Lisp_Object key1, EMACS_UINT hash1, 3435 Lisp_Object key1,
3434 Lisp_Object key2, EMACS_UINT hash2) 3436 Lisp_Object key2)
3435{ 3437{
3436 return (FLOATP (key1) 3438 return (FLOATP (key1)
3437 && FLOATP (key2) 3439 && FLOATP (key2)
@@ -3444,11 +3446,11 @@ cmpfn_eql (struct Lisp_Hash_Table *h,
3444 KEY2 are the same. */ 3446 KEY2 are the same. */
3445 3447
3446static bool 3448static bool
3447cmpfn_equal (struct Lisp_Hash_Table *h, 3449cmpfn_equal (struct hash_table_test *ht,
3448 Lisp_Object key1, EMACS_UINT hash1, 3450 Lisp_Object key1,
3449 Lisp_Object key2, EMACS_UINT hash2) 3451 Lisp_Object key2)
3450{ 3452{
3451 return hash1 == hash2 && !NILP (Fequal (key1, key2)); 3453 return !NILP (Fequal (key1, key2));
3452} 3454}
3453 3455
3454 3456
@@ -3457,21 +3459,16 @@ cmpfn_equal (struct Lisp_Hash_Table *h,
3457 if KEY1 and KEY2 are the same. */ 3459 if KEY1 and KEY2 are the same. */
3458 3460
3459static bool 3461static bool
3460cmpfn_user_defined (struct Lisp_Hash_Table *h, 3462cmpfn_user_defined (struct hash_table_test *ht,
3461 Lisp_Object key1, EMACS_UINT hash1, 3463 Lisp_Object key1,
3462 Lisp_Object key2, EMACS_UINT hash2) 3464 Lisp_Object key2)
3463{ 3465{
3464 if (hash1 == hash2) 3466 Lisp_Object args[3];
3465 {
3466 Lisp_Object args[3];
3467 3467
3468 args[0] = h->user_cmp_function; 3468 args[0] = ht->user_cmp_function;
3469 args[1] = key1; 3469 args[1] = key1;
3470 args[2] = key2; 3470 args[2] = key2;
3471 return !NILP (Ffuncall (3, args)); 3471 return !NILP (Ffuncall (3, args));
3472 }
3473 else
3474 return 0;
3475} 3472}
3476 3473
3477 3474
@@ -3480,54 +3477,48 @@ cmpfn_user_defined (struct Lisp_Hash_Table *h,
3480 in a Lisp integer. */ 3477 in a Lisp integer. */
3481 3478
3482static EMACS_UINT 3479static EMACS_UINT
3483hashfn_eq (struct Lisp_Hash_Table *h, Lisp_Object key) 3480hashfn_eq (struct hash_table_test *ht, Lisp_Object key)
3484{ 3481{
3485 EMACS_UINT hash = XUINT (key) ^ XTYPE (key); 3482 EMACS_UINT hash = XUINT (key) ^ XTYPE (key);
3486 eassert ((hash & ~INTMASK) == 0);
3487 return hash; 3483 return hash;
3488} 3484}
3489 3485
3490
3491/* Value is a hash code for KEY for use in hash table H which uses 3486/* Value is a hash code for KEY for use in hash table H which uses
3492 `eql' to compare keys. The hash code returned is guaranteed to fit 3487 `eql' to compare keys. The hash code returned is guaranteed to fit
3493 in a Lisp integer. */ 3488 in a Lisp integer. */
3494 3489
3495static EMACS_UINT 3490static EMACS_UINT
3496hashfn_eql (struct Lisp_Hash_Table *h, Lisp_Object key) 3491hashfn_eql (struct hash_table_test *ht, Lisp_Object key)
3497{ 3492{
3498 EMACS_UINT hash; 3493 EMACS_UINT hash;
3499 if (FLOATP (key)) 3494 if (FLOATP (key))
3500 hash = sxhash (key, 0); 3495 hash = sxhash (key, 0);
3501 else 3496 else
3502 hash = XUINT (key) ^ XTYPE (key); 3497 hash = XUINT (key) ^ XTYPE (key);
3503 eassert ((hash & ~INTMASK) == 0);
3504 return hash; 3498 return hash;
3505} 3499}
3506 3500
3507
3508/* Value is a hash code for KEY for use in hash table H which uses 3501/* Value is a hash code for KEY for use in hash table H which uses
3509 `equal' to compare keys. The hash code returned is guaranteed to fit 3502 `equal' to compare keys. The hash code returned is guaranteed to fit
3510 in a Lisp integer. */ 3503 in a Lisp integer. */
3511 3504
3512static EMACS_UINT 3505static EMACS_UINT
3513hashfn_equal (struct Lisp_Hash_Table *h, Lisp_Object key) 3506hashfn_equal (struct hash_table_test *ht, Lisp_Object key)
3514{ 3507{
3515 EMACS_UINT hash = sxhash (key, 0); 3508 EMACS_UINT hash = sxhash (key, 0);
3516 eassert ((hash & ~INTMASK) == 0);
3517 return hash; 3509 return hash;
3518} 3510}
3519 3511
3520
3521/* Value is a hash code for KEY for use in hash table H which uses as 3512/* Value is a hash code for KEY for use in hash table H which uses as
3522 user-defined function to compare keys. The hash code returned is 3513 user-defined function to compare keys. The hash code returned is
3523 guaranteed to fit in a Lisp integer. */ 3514 guaranteed to fit in a Lisp integer. */
3524 3515
3525static EMACS_UINT 3516static EMACS_UINT
3526hashfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key) 3517hashfn_user_defined (struct hash_table_test *ht, Lisp_Object key)
3527{ 3518{
3528 Lisp_Object args[2], hash; 3519 Lisp_Object args[2], hash;
3529 3520
3530 args[0] = h->user_hash_function; 3521 args[0] = ht->user_hash_function;
3531 args[1] = key; 3522 args[1] = key;
3532 hash = Ffuncall (2, args); 3523 hash = Ffuncall (2, args);
3533 if (!INTEGERP (hash)) 3524 if (!INTEGERP (hash))
@@ -3563,9 +3554,9 @@ hashfn_user_defined (struct Lisp_Hash_Table *h, Lisp_Object key)
3563 one of the symbols `key', `value', `key-or-value', or `key-and-value'. */ 3554 one of the symbols `key', `value', `key-or-value', or `key-and-value'. */
3564 3555
3565Lisp_Object 3556Lisp_Object
3566make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size, 3557make_hash_table (struct hash_table_test test,
3567 Lisp_Object rehash_threshold, Lisp_Object weak, 3558 Lisp_Object size, Lisp_Object rehash_size,
3568 Lisp_Object user_test, Lisp_Object user_hash) 3559 Lisp_Object rehash_threshold, Lisp_Object weak)
3569{ 3560{
3570 struct Lisp_Hash_Table *h; 3561 struct Lisp_Hash_Table *h;
3571 Lisp_Object table; 3562 Lisp_Object table;
@@ -3574,7 +3565,7 @@ make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size,
3574 double index_float; 3565 double index_float;
3575 3566
3576 /* Preconditions. */ 3567 /* Preconditions. */
3577 eassert (SYMBOLP (test)); 3568 eassert (SYMBOLP (test.name));
3578 eassert (INTEGERP (size) && XINT (size) >= 0); 3569 eassert (INTEGERP (size) && XINT (size) >= 0);
3579 eassert ((INTEGERP (rehash_size) && XINT (rehash_size) > 0) 3570 eassert ((INTEGERP (rehash_size) && XINT (rehash_size) > 0)
3580 || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size))); 3571 || (FLOATP (rehash_size) && 1 < XFLOAT_DATA (rehash_size)));
@@ -3598,29 +3589,6 @@ make_hash_table (Lisp_Object test, Lisp_Object size, Lisp_Object rehash_size,
3598 3589
3599 /* Initialize hash table slots. */ 3590 /* Initialize hash table slots. */
3600 h->test = test; 3591 h->test = test;
3601 if (EQ (test, Qeql))
3602 {
3603 h->cmpfn = cmpfn_eql;
3604 h->hashfn = hashfn_eql;
3605 }
3606 else if (EQ (test, Qeq))
3607 {
3608 h->cmpfn = NULL;
3609 h->hashfn = hashfn_eq;
3610 }
3611 else if (EQ (test, Qequal))
3612 {
3613 h->cmpfn = cmpfn_equal;
3614 h->hashfn = hashfn_equal;
3615 }
3616 else
3617 {
3618 h->user_cmp_function = user_test;
3619 h->user_hash_function = user_hash;
3620 h->cmpfn = cmpfn_user_defined;
3621 h->hashfn = hashfn_user_defined;
3622 }
3623
3624 h->weak = weak; 3592 h->weak = weak;
3625 h->rehash_threshold = rehash_threshold; 3593 h->rehash_threshold = rehash_threshold;
3626 h->rehash_size = rehash_size; 3594 h->rehash_size = rehash_size;
@@ -3776,7 +3744,8 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash)
3776 ptrdiff_t start_of_bucket; 3744 ptrdiff_t start_of_bucket;
3777 Lisp_Object idx; 3745 Lisp_Object idx;
3778 3746
3779 hash_code = h->hashfn (h, key); 3747 hash_code = h->test.hashfn (&h->test, key);
3748 eassert ((hash_code & ~INTMASK) == 0);
3780 if (hash) 3749 if (hash)
3781 *hash = hash_code; 3750 *hash = hash_code;
3782 3751
@@ -3788,9 +3757,9 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash)
3788 { 3757 {
3789 ptrdiff_t i = XFASTINT (idx); 3758 ptrdiff_t i = XFASTINT (idx);
3790 if (EQ (key, HASH_KEY (h, i)) 3759 if (EQ (key, HASH_KEY (h, i))
3791 || (h->cmpfn 3760 || (h->test.cmpfn
3792 && h->cmpfn (h, key, hash_code, 3761 && hash_code == XUINT (HASH_HASH (h, i))
3793 HASH_KEY (h, i), XUINT (HASH_HASH (h, i))))) 3762 && h->test.cmpfn (&h->test, key, HASH_KEY (h, i))))
3794 break; 3763 break;
3795 idx = HASH_NEXT (h, i); 3764 idx = HASH_NEXT (h, i);
3796 } 3765 }
@@ -3841,7 +3810,8 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
3841 ptrdiff_t start_of_bucket; 3810 ptrdiff_t start_of_bucket;
3842 Lisp_Object idx, prev; 3811 Lisp_Object idx, prev;
3843 3812
3844 hash_code = h->hashfn (h, key); 3813 hash_code = h->test.hashfn (&h->test, key);
3814 eassert ((hash_code & ~INTMASK) == 0);
3845 start_of_bucket = hash_code % ASIZE (h->index); 3815 start_of_bucket = hash_code % ASIZE (h->index);
3846 idx = HASH_INDEX (h, start_of_bucket); 3816 idx = HASH_INDEX (h, start_of_bucket);
3847 prev = Qnil; 3817 prev = Qnil;
@@ -3852,9 +3822,9 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
3852 ptrdiff_t i = XFASTINT (idx); 3822 ptrdiff_t i = XFASTINT (idx);
3853 3823
3854 if (EQ (key, HASH_KEY (h, i)) 3824 if (EQ (key, HASH_KEY (h, i))
3855 || (h->cmpfn 3825 || (h->test.cmpfn
3856 && h->cmpfn (h, key, hash_code, 3826 && hash_code == XUINT (HASH_HASH (h, i))
3857 HASH_KEY (h, i), XUINT (HASH_HASH (h, i))))) 3827 && h->test.cmpfn (&h->test, key, HASH_KEY (h, i))))
3858 { 3828 {
3859 /* Take entry out of collision chain. */ 3829 /* Take entry out of collision chain. */
3860 if (NILP (prev)) 3830 if (NILP (prev))
@@ -4303,7 +4273,7 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4303 (ptrdiff_t nargs, Lisp_Object *args) 4273 (ptrdiff_t nargs, Lisp_Object *args)
4304{ 4274{
4305 Lisp_Object test, size, rehash_size, rehash_threshold, weak; 4275 Lisp_Object test, size, rehash_size, rehash_threshold, weak;
4306 Lisp_Object user_test, user_hash; 4276 struct hash_table_test testdesc;
4307 char *used; 4277 char *used;
4308 ptrdiff_t i; 4278 ptrdiff_t i;
4309 4279
@@ -4315,7 +4285,13 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4315 /* See if there's a `:test TEST' among the arguments. */ 4285 /* See if there's a `:test TEST' among the arguments. */
4316 i = get_key_arg (QCtest, nargs, args, used); 4286 i = get_key_arg (QCtest, nargs, args, used);
4317 test = i ? args[i] : Qeql; 4287 test = i ? args[i] : Qeql;
4318 if (!EQ (test, Qeq) && !EQ (test, Qeql) && !EQ (test, Qequal)) 4288 if (EQ (test, Qeq))
4289 testdesc = hashtest_eq;
4290 else if (EQ (test, Qeql))
4291 testdesc = hashtest_eql;
4292 else if (EQ (test, Qequal))
4293 testdesc = hashtest_equal;
4294 else
4319 { 4295 {
4320 /* See if it is a user-defined test. */ 4296 /* See if it is a user-defined test. */
4321 Lisp_Object prop; 4297 Lisp_Object prop;
@@ -4323,11 +4299,12 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4323 prop = Fget (test, Qhash_table_test); 4299 prop = Fget (test, Qhash_table_test);
4324 if (!CONSP (prop) || !CONSP (XCDR (prop))) 4300 if (!CONSP (prop) || !CONSP (XCDR (prop)))
4325 signal_error ("Invalid hash table test", test); 4301 signal_error ("Invalid hash table test", test);
4326 user_test = XCAR (prop); 4302 testdesc.name = test;
4327 user_hash = XCAR (XCDR (prop)); 4303 testdesc.user_cmp_function = XCAR (prop);
4304 testdesc.user_hash_function = XCAR (XCDR (prop));
4305 testdesc.hashfn = hashfn_user_defined;
4306 testdesc.cmpfn = cmpfn_user_defined;
4328 } 4307 }
4329 else
4330 user_test = user_hash = Qnil;
4331 4308
4332 /* See if there's a `:size SIZE' argument. */ 4309 /* See if there's a `:size SIZE' argument. */
4333 i = get_key_arg (QCsize, nargs, args, used); 4310 i = get_key_arg (QCsize, nargs, args, used);
@@ -4369,8 +4346,7 @@ usage: (make-hash-table &rest KEYWORD-ARGS) */)
4369 if (!used[i]) 4346 if (!used[i])
4370 signal_error ("Invalid argument list", args[i]); 4347 signal_error ("Invalid argument list", args[i]);
4371 4348
4372 return make_hash_table (test, size, rehash_size, rehash_threshold, weak, 4349 return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
4373 user_test, user_hash);
4374} 4350}
4375 4351
4376 4352
@@ -4424,7 +4400,7 @@ DEFUN ("hash-table-test", Fhash_table_test, Shash_table_test, 1, 1, 0,
4424 doc: /* Return the test TABLE uses. */) 4400 doc: /* Return the test TABLE uses. */)
4425 (Lisp_Object table) 4401 (Lisp_Object table)
4426{ 4402{
4427 return check_hash_table (table)->test; 4403 return check_hash_table (table)->test.name;
4428} 4404}
4429 4405
4430 4406
@@ -4988,4 +4964,14 @@ this variable. */);
4988 defsubr (&Smd5); 4964 defsubr (&Smd5);
4989 defsubr (&Ssecure_hash); 4965 defsubr (&Ssecure_hash);
4990 defsubr (&Slocale_info); 4966 defsubr (&Slocale_info);
4967
4968 {
4969 struct hash_table_test
4970 eq = { Qeq, Qnil, Qnil, NULL, hashfn_eq },
4971 eql = { Qeql, Qnil, Qnil, cmpfn_eql, hashfn_eql },
4972 equal = { Qequal, Qnil, Qnil, cmpfn_equal, hashfn_equal };
4973 hashtest_eq = eq;
4974 hashtest_eql = eql;
4975 hashtest_equal = equal;
4976 }
4991} 4977}