aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias EngdegÄrd2025-07-19 16:15:47 +0200
committerMattias EngdegÄrd2025-07-19 16:48:11 +0200
commitf4a9673f615aa8d1fad499784fdcd11ac0ec4042 (patch)
treef0009c8133bbf89fc73d6fa10ed8f59f4ed9589d /src
parente9deec70dac822f2f312497c6d7a7bd6b4e648bb (diff)
downloademacs-f4a9673f615aa8d1fad499784fdcd11ac0ec4042.tar.gz
emacs-f4a9673f615aa8d1fad499784fdcd11ac0ec4042.zip
Speed up unintern, and fix symbol shorthand edge case (bug#79035)
Don't do a full lookup if the argument is a symbol, and only compute the hash index once. Fix a bug that occurred when there is another symbol whose shorthand is equal to the true name of the symbol being removed. * src/lread.c (Funintern): Rewrite for speed and correctness. (oblookup_last_bucket_number, oblookup): Remove now unused variable. * test/src/lread-tests.el (lread-unintern): New test.
Diffstat (limited to 'src')
-rw-r--r--src/lread.c114
1 files changed, 49 insertions, 65 deletions
diff --git a/src/lread.c b/src/lread.c
index 00b9a33e45a..287528ab32d 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -4916,10 +4916,6 @@ string_to_number (char const *string, int base, ptrdiff_t *plen)
4916 4916
4917static Lisp_Object initial_obarray; 4917static Lisp_Object initial_obarray;
4918 4918
4919/* `oblookup' stores the bucket number here, for the sake of Funintern. */
4920
4921static size_t oblookup_last_bucket_number;
4922
4923static Lisp_Object make_obarray (unsigned bits); 4919static Lisp_Object make_obarray (unsigned bits);
4924 4920
4925/* Slow path obarray check: return the obarray to use or signal an error. */ 4921/* Slow path obarray check: return the obarray to use or signal an error. */
@@ -5130,6 +5126,14 @@ it defaults to the value of `obarray'. */)
5130 } 5126 }
5131} 5127}
5132 5128
5129/* Bucket index of the string STR of length SIZE_BYTE bytes in obarray OA. */
5130static ptrdiff_t
5131obarray_index (struct Lisp_Obarray *oa, const char *str, ptrdiff_t size_byte)
5132{
5133 EMACS_UINT hash = hash_char_array (str, size_byte);
5134 return knuth_hash (reduce_emacs_uint_to_hash_hash (hash), oa->size_bits);
5135}
5136
5133DEFUN ("unintern", Funintern, Sunintern, 2, 2, 0, 5137DEFUN ("unintern", Funintern, Sunintern, 2, 2, 0,
5134 doc: /* Delete the symbol named NAME, if any, from OBARRAY. 5138 doc: /* Delete the symbol named NAME, if any, from OBARRAY.
5135The value is t if a symbol was found and deleted, nil otherwise. 5139The value is t if a symbol was found and deleted, nil otherwise.
@@ -5138,89 +5142,70 @@ is deleted, if it belongs to OBARRAY--no other symbol is deleted.
5138OBARRAY, if nil, defaults to the value of the variable `obarray'. */) 5142OBARRAY, if nil, defaults to the value of the variable `obarray'. */)
5139 (Lisp_Object name, Lisp_Object obarray) 5143 (Lisp_Object name, Lisp_Object obarray)
5140{ 5144{
5141 register Lisp_Object tem;
5142 Lisp_Object string;
5143
5144 if (NILP (obarray)) obarray = Vobarray; 5145 if (NILP (obarray)) obarray = Vobarray;
5145 obarray = check_obarray (obarray); 5146 obarray = check_obarray (obarray);
5146 5147
5148 Lisp_Object sym;
5147 if (SYMBOLP (name)) 5149 if (SYMBOLP (name))
5148 { 5150 sym = BARE_SYMBOL_P (name) ? name : XSYMBOL_WITH_POS (name)->sym;
5149 if (!BARE_SYMBOL_P (name))
5150 name = XSYMBOL_WITH_POS (name)->sym;
5151 string = SYMBOL_NAME (name);
5152 }
5153 else 5151 else
5154 { 5152 {
5155 CHECK_STRING (name); 5153 CHECK_STRING (name);
5156 string = name; 5154 char *longhand = NULL;
5155 ptrdiff_t longhand_chars = 0;
5156 ptrdiff_t longhand_bytes = 0;
5157 sym = oblookup_considering_shorthand (obarray, SSDATA (name),
5158 SCHARS (name), SBYTES (name),
5159 &longhand, &longhand_chars,
5160 &longhand_bytes);
5161 xfree(longhand);
5162 if (FIXNUMP (sym))
5163 return Qnil;
5157 } 5164 }
5158 5165
5159 char *longhand = NULL; 5166 /* There are plenty of symbols which will screw up the Emacs
5160 ptrdiff_t longhand_chars = 0;
5161 ptrdiff_t longhand_bytes = 0;
5162 tem = oblookup_considering_shorthand (obarray, SSDATA (string),
5163 SCHARS (string), SBYTES (string),
5164 &longhand, &longhand_chars,
5165 &longhand_bytes);
5166 if (longhand)
5167 xfree(longhand);
5168
5169 if (FIXNUMP (tem))
5170 return Qnil;
5171 /* If arg was a symbol, don't delete anything but that symbol itself. */
5172 if (BARE_SYMBOL_P (name) && !BASE_EQ (name, tem))
5173 return Qnil;
5174
5175 /* There are plenty of other symbols which will screw up the Emacs
5176 session if we unintern them, as well as even more ways to use 5167 session if we unintern them, as well as even more ways to use
5177 `setq' or `fset' or whatnot to make the Emacs session 5168 `setq' or `fset' or whatnot to make the Emacs session
5178 unusable. Let's not go down this silly road. --Stef */ 5169 unusable. We don't try to prevent such mistakes here. */
5179 /* if (NILP (tem) || EQ (tem, Qt))
5180 error ("Attempt to unintern t or nil"); */
5181
5182 struct Lisp_Symbol *sym = XBARE_SYMBOL (tem);
5183 sym->u.s.interned = SYMBOL_UNINTERNED;
5184 5170
5185 ptrdiff_t idx = oblookup_last_bucket_number; 5171 struct Lisp_Obarray *o = XOBARRAY (obarray);
5186 Lisp_Object *loc = &XOBARRAY (obarray)->buckets[idx]; 5172 Lisp_Object symname = SYMBOL_NAME (sym);
5173 ptrdiff_t idx = obarray_index (o, SSDATA (symname), SBYTES (symname));
5174 Lisp_Object *loc = &o->buckets[idx];
5175 if (BASE_EQ (*loc, make_fixnum (0)))
5176 return Qnil;
5187 5177
5188 eassert (BARE_SYMBOL_P (*loc)); 5178 struct Lisp_Symbol *s = XBARE_SYMBOL (sym);
5189 struct Lisp_Symbol *prev = XBARE_SYMBOL (*loc); 5179 struct Lisp_Symbol *prev = XBARE_SYMBOL (*loc);
5190 if (sym == prev) 5180 if (prev == s)
5191 *loc = sym->u.s.next ? make_lisp_symbol (sym->u.s.next) : make_fixnum (0); 5181 *loc = s->u.s.next ? make_lisp_symbol (s->u.s.next) : make_fixnum (0);
5192 else 5182 else
5193 while (1) 5183 {
5194 { 5184 do
5195 struct Lisp_Symbol *next = prev->u.s.next; 5185 {
5196 if (next == sym) 5186 struct Lisp_Symbol *next = prev->u.s.next;
5197 { 5187 if (next == s)
5198 prev->u.s.next = next->u.s.next; 5188 {
5199 break; 5189 prev->u.s.next = next->u.s.next;
5200 } 5190 goto removed;
5201 prev = next; 5191 }
5202 } 5192 prev = next;
5203 5193 }
5204 XOBARRAY (obarray)->count--; 5194 while (prev);
5195 return Qnil;
5196 }
5205 5197
5198 removed:
5199 s->u.s.interned = SYMBOL_UNINTERNED;
5200 o->count--;
5206 return Qt; 5201 return Qt;
5207} 5202}
5208 5203
5209 5204
5210/* Bucket index of the string STR of length SIZE_BYTE bytes in obarray OA. */
5211static ptrdiff_t
5212obarray_index (struct Lisp_Obarray *oa, const char *str, ptrdiff_t size_byte)
5213{
5214 EMACS_UINT hash = hash_char_array (str, size_byte);
5215 return knuth_hash (reduce_emacs_uint_to_hash_hash (hash), oa->size_bits);
5216}
5217
5218/* Return the symbol in OBARRAY whose name matches the string 5205/* Return the symbol in OBARRAY whose name matches the string
5219 of SIZE characters (SIZE_BYTE bytes) at PTR. 5206 of SIZE characters (SIZE_BYTE bytes) at PTR.
5220 If there is no such symbol, return the integer bucket number of 5207 If there is no such symbol, return the integer bucket number of
5221 where the symbol would be if it were present. 5208 where the symbol would be if it were present. */
5222
5223 Also store the bucket number in oblookup_last_bucket_number. */
5224 5209
5225Lisp_Object 5210Lisp_Object
5226oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, ptrdiff_t size_byte) 5211oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, ptrdiff_t size_byte)
@@ -5229,7 +5214,6 @@ oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, ptrdiff
5229 ptrdiff_t idx = obarray_index (o, ptr, size_byte); 5214 ptrdiff_t idx = obarray_index (o, ptr, size_byte);
5230 Lisp_Object bucket = o->buckets[idx]; 5215 Lisp_Object bucket = o->buckets[idx];
5231 5216
5232 oblookup_last_bucket_number = idx;
5233 if (!BASE_EQ (bucket, make_fixnum (0))) 5217 if (!BASE_EQ (bucket, make_fixnum (0)))
5234 { 5218 {
5235 Lisp_Object sym = bucket; 5219 Lisp_Object sym = bucket;