diff options
| author | Mattias EngdegÄrd | 2023-11-22 14:54:34 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2024-01-13 20:50:39 +0100 |
| commit | 1998039f7a8f2ecc884a6fed85c0cc1ce06f83e2 (patch) | |
| tree | 92fb11cd22e2560e637c95cc61c42eff7edfa7d0 /src | |
| parent | 11e467eb6004286765c1d8c408f8d773d9113aca (diff) | |
| download | emacs-1998039f7a8f2ecc884a6fed85c0cc1ce06f83e2.tar.gz emacs-1998039f7a8f2ecc884a6fed85c0cc1ce06f83e2.zip | |
Change hash_hash_t to uint32_t
This saves a lot of memory and is quite sufficient. Hash functions
are adapted to produce a hash_hash_t eventually, which eliminates some
useless and information-destroying intermediate hash reduction steps.
We still use EMACS_UINT for most of the actual hashing steps before
producing the final value; this may be slightly wasteful on 32-bit
platforms with 64-bit EMACS_UINT.
* src/lisp.h (hash_hash_t): Change to uint32_t.
* src/fns.c (reduce_emacs_uint_to_hash_hash): New.
(hashfn_eq, hashfn_equal, hashfn_user_defined): Reduce return values
to hash_hash_t.
(sxhash_string): Remove. Caller changed to hash_string.
(sxhash_float, sxhash_list, sxhash_vector, sxhash_bool_vector)
(sxhash_bignum): Remove wasteful calls to SXHASH_REDUCE.
(hash_hash_to_fixnum): New.
(Fsxhash_eq, Fsxhash_eql, Fsxhash_equal)
(Fsxhash_equal_including_properties): Convert return values to fixnum.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 77 | ||||
| -rw-r--r-- | src/lisp.h | 2 |
2 files changed, 43 insertions, 36 deletions
| @@ -4452,6 +4452,16 @@ cmpfn_user_defined (Lisp_Object key1, Lisp_Object key2, | |||
| 4452 | return hash_table_user_defined_call (ARRAYELTS (args), args, h); | 4452 | return hash_table_user_defined_call (ARRAYELTS (args), args, h); |
| 4453 | } | 4453 | } |
| 4454 | 4454 | ||
| 4455 | /* Reduce an EMACS_UINT hash value to hash_hash_t. */ | ||
| 4456 | static inline hash_hash_t | ||
| 4457 | reduce_emacs_uint_to_hash_hash (EMACS_UINT x) | ||
| 4458 | { | ||
| 4459 | verify (sizeof x <= 2 * sizeof (hash_hash_t)); | ||
| 4460 | return (sizeof x == sizeof (hash_hash_t) | ||
| 4461 | ? x | ||
| 4462 | : x ^ (x >> (8 * (sizeof x - sizeof (hash_hash_t))))); | ||
| 4463 | } | ||
| 4464 | |||
| 4455 | /* Ignore H and return a hash code for KEY which uses 'eq' to compare keys. */ | 4465 | /* Ignore H and return a hash code for KEY which uses 'eq' to compare keys. */ |
| 4456 | 4466 | ||
| 4457 | static hash_hash_t | 4467 | static hash_hash_t |
| @@ -4459,21 +4469,18 @@ hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h) | |||
| 4459 | { | 4469 | { |
| 4460 | if (symbols_with_pos_enabled && SYMBOL_WITH_POS_P (key)) | 4470 | if (symbols_with_pos_enabled && SYMBOL_WITH_POS_P (key)) |
| 4461 | key = SYMBOL_WITH_POS_SYM (key); | 4471 | key = SYMBOL_WITH_POS_SYM (key); |
| 4462 | return XHASH (key) ^ XTYPE (key); | 4472 | return reduce_emacs_uint_to_hash_hash (XHASH (key) ^ XTYPE (key)); |
| 4463 | } | 4473 | } |
| 4464 | 4474 | ||
| 4465 | /* Ignore H and return a hash code for KEY which uses 'equal' to compare keys. | 4475 | /* Ignore H and return a hash code for KEY which uses 'equal' to |
| 4466 | The hash code is at most INTMASK. */ | 4476 | compare keys. */ |
| 4467 | |||
| 4468 | static hash_hash_t | 4477 | static hash_hash_t |
| 4469 | hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h) | 4478 | hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h) |
| 4470 | { | 4479 | { |
| 4471 | return sxhash (key); | 4480 | return reduce_emacs_uint_to_hash_hash (sxhash (key)); |
| 4472 | } | 4481 | } |
| 4473 | 4482 | ||
| 4474 | /* Ignore H and return a hash code for KEY which uses 'eql' to compare keys. | 4483 | /* Ignore H and return a hash code for KEY which uses 'eql' to compare keys. */ |
| 4475 | The hash code is at most INTMASK. */ | ||
| 4476 | |||
| 4477 | static hash_hash_t | 4484 | static hash_hash_t |
| 4478 | hashfn_eql (Lisp_Object key, struct Lisp_Hash_Table *h) | 4485 | hashfn_eql (Lisp_Object key, struct Lisp_Hash_Table *h) |
| 4479 | { | 4486 | { |
| @@ -4489,7 +4496,8 @@ hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) | |||
| 4489 | { | 4496 | { |
| 4490 | Lisp_Object args[] = { h->test->user_hash_function, key }; | 4497 | Lisp_Object args[] = { h->test->user_hash_function, key }; |
| 4491 | Lisp_Object hash = hash_table_user_defined_call (ARRAYELTS (args), args, h); | 4498 | Lisp_Object hash = hash_table_user_defined_call (ARRAYELTS (args), args, h); |
| 4492 | return FIXNUMP (hash) ? XUFIXNUM(hash) : sxhash (hash); | 4499 | return reduce_emacs_uint_to_hash_hash (FIXNUMP (hash) |
| 4500 | ? XUFIXNUM(hash) : sxhash (hash)); | ||
| 4493 | } | 4501 | } |
| 4494 | 4502 | ||
| 4495 | struct hash_table_test const | 4503 | struct hash_table_test const |
| @@ -5061,16 +5069,6 @@ hash_string (char const *ptr, ptrdiff_t len) | |||
| 5061 | return hash; | 5069 | return hash; |
| 5062 | } | 5070 | } |
| 5063 | 5071 | ||
| 5064 | /* Return a hash for string PTR which has length LEN. The hash | ||
| 5065 | code returned is at most INTMASK. */ | ||
| 5066 | |||
| 5067 | static EMACS_UINT | ||
| 5068 | sxhash_string (char const *ptr, ptrdiff_t len) | ||
| 5069 | { | ||
| 5070 | EMACS_UINT hash = hash_string (ptr, len); | ||
| 5071 | return SXHASH_REDUCE (hash); | ||
| 5072 | } | ||
| 5073 | |||
| 5074 | /* Return a hash for the floating point value VAL. */ | 5072 | /* Return a hash for the floating point value VAL. */ |
| 5075 | 5073 | ||
| 5076 | static EMACS_UINT | 5074 | static EMACS_UINT |
| @@ -5080,7 +5078,7 @@ sxhash_float (double val) | |||
| 5080 | union double_and_words u = { .val = val }; | 5078 | union double_and_words u = { .val = val }; |
| 5081 | for (int i = 0; i < WORDS_PER_DOUBLE; i++) | 5079 | for (int i = 0; i < WORDS_PER_DOUBLE; i++) |
| 5082 | hash = sxhash_combine (hash, u.word[i]); | 5080 | hash = sxhash_combine (hash, u.word[i]); |
| 5083 | return SXHASH_REDUCE (hash); | 5081 | return hash; |
| 5084 | } | 5082 | } |
| 5085 | 5083 | ||
| 5086 | /* Return a hash for list LIST. DEPTH is the current depth in the | 5084 | /* Return a hash for list LIST. DEPTH is the current depth in the |
| @@ -5107,7 +5105,7 @@ sxhash_list (Lisp_Object list, int depth) | |||
| 5107 | hash = sxhash_combine (hash, hash2); | 5105 | hash = sxhash_combine (hash, hash2); |
| 5108 | } | 5106 | } |
| 5109 | 5107 | ||
| 5110 | return SXHASH_REDUCE (hash); | 5108 | return hash; |
| 5111 | } | 5109 | } |
| 5112 | 5110 | ||
| 5113 | 5111 | ||
| @@ -5127,7 +5125,7 @@ sxhash_vector (Lisp_Object vec, int depth) | |||
| 5127 | hash = sxhash_combine (hash, hash2); | 5125 | hash = sxhash_combine (hash, hash2); |
| 5128 | } | 5126 | } |
| 5129 | 5127 | ||
| 5130 | return SXHASH_REDUCE (hash); | 5128 | return hash; |
| 5131 | } | 5129 | } |
| 5132 | 5130 | ||
| 5133 | /* Return a hash for bool-vector VECTOR. */ | 5131 | /* Return a hash for bool-vector VECTOR. */ |
| @@ -5143,7 +5141,7 @@ sxhash_bool_vector (Lisp_Object vec) | |||
| 5143 | for (i = 0; i < n; ++i) | 5141 | for (i = 0; i < n; ++i) |
| 5144 | hash = sxhash_combine (hash, bool_vector_data (vec)[i]); | 5142 | hash = sxhash_combine (hash, bool_vector_data (vec)[i]); |
| 5145 | 5143 | ||
| 5146 | return SXHASH_REDUCE (hash); | 5144 | return hash; |
| 5147 | } | 5145 | } |
| 5148 | 5146 | ||
| 5149 | /* Return a hash for a bignum. */ | 5147 | /* Return a hash for a bignum. */ |
| @@ -5158,19 +5156,18 @@ sxhash_bignum (Lisp_Object bignum) | |||
| 5158 | for (i = 0; i < nlimbs; ++i) | 5156 | for (i = 0; i < nlimbs; ++i) |
| 5159 | hash = sxhash_combine (hash, mpz_getlimbn (*n, i)); | 5157 | hash = sxhash_combine (hash, mpz_getlimbn (*n, i)); |
| 5160 | 5158 | ||
| 5161 | return SXHASH_REDUCE (hash); | 5159 | return hash; |
| 5162 | } | 5160 | } |
| 5163 | 5161 | ||
| 5164 | |||
| 5165 | /* Return a hash code for OBJ. DEPTH is the current depth in the Lisp | ||
| 5166 | structure. Value is an unsigned integer clipped to INTMASK. */ | ||
| 5167 | |||
| 5168 | EMACS_UINT | 5162 | EMACS_UINT |
| 5169 | sxhash (Lisp_Object obj) | 5163 | sxhash (Lisp_Object obj) |
| 5170 | { | 5164 | { |
| 5171 | return sxhash_obj (obj, 0); | 5165 | return sxhash_obj (obj, 0); |
| 5172 | } | 5166 | } |
| 5173 | 5167 | ||
| 5168 | /* Return a hash code for OBJ. DEPTH is the current depth in the Lisp | ||
| 5169 | structure. */ | ||
| 5170 | |||
| 5174 | static EMACS_UINT | 5171 | static EMACS_UINT |
| 5175 | sxhash_obj (Lisp_Object obj, int depth) | 5172 | sxhash_obj (Lisp_Object obj, int depth) |
| 5176 | { | 5173 | { |
| @@ -5186,7 +5183,7 @@ sxhash_obj (Lisp_Object obj, int depth) | |||
| 5186 | return XHASH (obj); | 5183 | return XHASH (obj); |
| 5187 | 5184 | ||
| 5188 | case Lisp_String: | 5185 | case Lisp_String: |
| 5189 | return sxhash_string (SSDATA (obj), SBYTES (obj)); | 5186 | return hash_string (SSDATA (obj), SBYTES (obj)); |
| 5190 | 5187 | ||
| 5191 | case Lisp_Vectorlike: | 5188 | case Lisp_Vectorlike: |
| 5192 | { | 5189 | { |
| @@ -5213,7 +5210,7 @@ sxhash_obj (Lisp_Object obj, int depth) | |||
| 5213 | = XMARKER (obj)->buffer ? XMARKER (obj)->bytepos : 0; | 5210 | = XMARKER (obj)->buffer ? XMARKER (obj)->bytepos : 0; |
| 5214 | EMACS_UINT hash | 5211 | EMACS_UINT hash |
| 5215 | = sxhash_combine ((intptr_t) XMARKER (obj)->buffer, bytepos); | 5212 | = sxhash_combine ((intptr_t) XMARKER (obj)->buffer, bytepos); |
| 5216 | return SXHASH_REDUCE (hash); | 5213 | return hash; |
| 5217 | } | 5214 | } |
| 5218 | else if (pvec_type == PVEC_BOOL_VECTOR) | 5215 | else if (pvec_type == PVEC_BOOL_VECTOR) |
| 5219 | return sxhash_bool_vector (obj); | 5216 | return sxhash_bool_vector (obj); |
| @@ -5222,7 +5219,7 @@ sxhash_obj (Lisp_Object obj, int depth) | |||
| 5222 | EMACS_UINT hash = OVERLAY_START (obj); | 5219 | EMACS_UINT hash = OVERLAY_START (obj); |
| 5223 | hash = sxhash_combine (hash, OVERLAY_END (obj)); | 5220 | hash = sxhash_combine (hash, OVERLAY_END (obj)); |
| 5224 | hash = sxhash_combine (hash, sxhash_obj (XOVERLAY (obj)->plist, depth)); | 5221 | hash = sxhash_combine (hash, sxhash_obj (XOVERLAY (obj)->plist, depth)); |
| 5225 | return SXHASH_REDUCE (hash); | 5222 | return hash; |
| 5226 | } | 5223 | } |
| 5227 | else if (symbols_with_pos_enabled && pvec_type == PVEC_SYMBOL_WITH_POS) | 5224 | else if (symbols_with_pos_enabled && pvec_type == PVEC_SYMBOL_WITH_POS) |
| 5228 | return sxhash_obj (XSYMBOL_WITH_POS (obj)->sym, depth + 1); | 5225 | return sxhash_obj (XSYMBOL_WITH_POS (obj)->sym, depth + 1); |
| @@ -5258,6 +5255,15 @@ collect_interval (INTERVAL interval, Lisp_Object collector) | |||
| 5258 | Lisp Interface | 5255 | Lisp Interface |
| 5259 | ***********************************************************************/ | 5256 | ***********************************************************************/ |
| 5260 | 5257 | ||
| 5258 | /* Reduce X to a Lisp fixnum. */ | ||
| 5259 | static inline Lisp_Object | ||
| 5260 | hash_hash_to_fixnum (hash_hash_t x) | ||
| 5261 | { | ||
| 5262 | return make_ufixnum (FIXNUM_BITS < 8 * sizeof x | ||
| 5263 | ? (x ^ x >> (8 * sizeof x - FIXNUM_BITS)) & INTMASK | ||
| 5264 | : x); | ||
| 5265 | } | ||
| 5266 | |||
| 5261 | DEFUN ("sxhash-eq", Fsxhash_eq, Ssxhash_eq, 1, 1, 0, | 5267 | DEFUN ("sxhash-eq", Fsxhash_eq, Ssxhash_eq, 1, 1, 0, |
| 5262 | doc: /* Return an integer hash code for OBJ suitable for `eq'. | 5268 | doc: /* Return an integer hash code for OBJ suitable for `eq'. |
| 5263 | If (eq A B), then (= (sxhash-eq A) (sxhash-eq B)). | 5269 | If (eq A B), then (= (sxhash-eq A) (sxhash-eq B)). |
| @@ -5265,7 +5271,7 @@ If (eq A B), then (= (sxhash-eq A) (sxhash-eq B)). | |||
| 5265 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) | 5271 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) |
| 5266 | (Lisp_Object obj) | 5272 | (Lisp_Object obj) |
| 5267 | { | 5273 | { |
| 5268 | return make_ufixnum (hashfn_eq (obj, NULL)); | 5274 | return hash_hash_to_fixnum (hashfn_eq (obj, NULL)); |
| 5269 | } | 5275 | } |
| 5270 | 5276 | ||
| 5271 | DEFUN ("sxhash-eql", Fsxhash_eql, Ssxhash_eql, 1, 1, 0, | 5277 | DEFUN ("sxhash-eql", Fsxhash_eql, Ssxhash_eql, 1, 1, 0, |
| @@ -5276,7 +5282,7 @@ isn't necessarily true. | |||
| 5276 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) | 5282 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) |
| 5277 | (Lisp_Object obj) | 5283 | (Lisp_Object obj) |
| 5278 | { | 5284 | { |
| 5279 | return make_ufixnum (hashfn_eql (obj, NULL)); | 5285 | return hash_hash_to_fixnum (hashfn_eql (obj, NULL)); |
| 5280 | } | 5286 | } |
| 5281 | 5287 | ||
| 5282 | DEFUN ("sxhash-equal", Fsxhash_equal, Ssxhash_equal, 1, 1, 0, | 5288 | DEFUN ("sxhash-equal", Fsxhash_equal, Ssxhash_equal, 1, 1, 0, |
| @@ -5287,7 +5293,7 @@ opposite isn't necessarily true. | |||
| 5287 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) | 5293 | Hash codes are not guaranteed to be preserved across Emacs sessions. */) |
| 5288 | (Lisp_Object obj) | 5294 | (Lisp_Object obj) |
| 5289 | { | 5295 | { |
| 5290 | return make_ufixnum (hashfn_equal (obj, NULL)); | 5296 | return hash_hash_to_fixnum (hashfn_equal (obj, NULL)); |
| 5291 | } | 5297 | } |
| 5292 | 5298 | ||
| 5293 | DEFUN ("sxhash-equal-including-properties", Fsxhash_equal_including_properties, | 5299 | DEFUN ("sxhash-equal-including-properties", Fsxhash_equal_including_properties, |
| @@ -5302,6 +5308,7 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */) | |||
| 5302 | { | 5308 | { |
| 5303 | if (STRINGP (obj)) | 5309 | if (STRINGP (obj)) |
| 5304 | { | 5310 | { |
| 5311 | /* FIXME: This is very wasteful. We needn't cons at all. */ | ||
| 5305 | Lisp_Object collector = Fcons (Qnil, Qnil); | 5312 | Lisp_Object collector = Fcons (Qnil, Qnil); |
| 5306 | traverse_intervals (string_intervals (obj), 0, collect_interval, | 5313 | traverse_intervals (string_intervals (obj), 0, collect_interval, |
| 5307 | collector); | 5314 | collector); |
| @@ -5311,7 +5318,7 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */) | |||
| 5311 | sxhash (CDR (collector))))); | 5318 | sxhash (CDR (collector))))); |
| 5312 | } | 5319 | } |
| 5313 | 5320 | ||
| 5314 | return make_ufixnum (hashfn_equal (obj, NULL)); | 5321 | return hash_hash_to_fixnum (hashfn_equal (obj, NULL)); |
| 5315 | } | 5322 | } |
| 5316 | 5323 | ||
| 5317 | 5324 | ||
diff --git a/src/lisp.h b/src/lisp.h index 0701028c14c..64492361e64 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2387,7 +2387,7 @@ struct Lisp_Hash_Table; | |||
| 2387 | 2387 | ||
| 2388 | /* The type of a hash value stored in the table. | 2388 | /* The type of a hash value stored in the table. |
| 2389 | It's unsigned and a subtype of EMACS_UINT. */ | 2389 | It's unsigned and a subtype of EMACS_UINT. */ |
| 2390 | typedef EMACS_UINT hash_hash_t; | 2390 | typedef uint32_t hash_hash_t; |
| 2391 | 2391 | ||
| 2392 | typedef enum { | 2392 | typedef enum { |
| 2393 | Test_eql, | 2393 | Test_eql, |