]> git.eshelyaron.com Git - emacs.git/commitdiff
Represent hash table weakness as an enum internally
authorMattias Engdegård <mattiase@acm.org>
Thu, 26 Oct 2023 13:49:32 +0000 (15:49 +0200)
committerMattias Engdegård <mattiase@acm.org>
Sat, 13 Jan 2024 19:50:37 +0000 (20:50 +0100)
This takes less space (saves an entire word) and is more type-safe.
No change in behaviour.

* src/lisp.h (hash_table_weakness_t): New.
(struct Lisp_Hash_Table): Replace Lisp object `weak` with enum
`weakness`.
* src/fns.c
(keep_entry_p, hash_table_weakness_symbol): New.
(make_hash_table): Retype argument.  All callers updated.
(sweep_weak_table, Fmake_hash_table, Fhash_table_weakness):
* src/alloc.c (purecopy_hash_table, purecopy, process_mark_stack):
* src/pdumper.c (dump_hash_table):
* src/print.c (print_object): Use retyped field.

14 files changed:
src/alloc.c
src/category.c
src/emacs-module.c
src/fns.c
src/frame.c
src/image.c
src/lisp.h
src/lread.c
src/pdumper.c
src/pgtkterm.c
src/print.c
src/profiler.c
src/xfaces.c
src/xterm.c

index af9c169a3a014966cc3af3fc342899947c803f57..17ed711a318f7968299c43cd9b0b6dd641ac2834 100644 (file)
@@ -5887,7 +5887,7 @@ make_pure_vector (ptrdiff_t len)
 static struct Lisp_Hash_Table *
 purecopy_hash_table (struct Lisp_Hash_Table *table)
 {
-  eassert (NILP (table->weak));
+  eassert (table->weakness == Weak_None);
   eassert (table->purecopy);
 
   struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike);
@@ -5960,7 +5960,7 @@ purecopy (Lisp_Object obj)
       /* Do not purify hash tables which haven't been defined with
          :purecopy as non-nil or are weak - they aren't guaranteed to
          not change.  */
-      if (!NILP (table->weak) || !table->purecopy)
+      if (table->weakness != Weak_None || !table->purecopy)
         {
           /* Instead, add the hash table to the list of pinned objects,
              so that it will be marked during GC.  */
@@ -7233,7 +7233,7 @@ process_mark_stack (ptrdiff_t base_sp)
                  mark_stack_push_value (h->test.name);
                  mark_stack_push_value (h->test.user_hash_function);
                  mark_stack_push_value (h->test.user_cmp_function);
-                 if (NILP (h->weak))
+                 if (h->weakness == Weak_None)
                    mark_stack_push_value (h->key_and_value);
                  else
                    {
index b539bad31ebcb371fedc71f58567b1f2b0ca5671..67429e82571895d0793bae15756fe52e78c675ff 100644 (file)
@@ -53,7 +53,7 @@ hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
       (table, 1,
        make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
                        DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-                       Qnil, false));
+                       Weak_None, false));
   struct Lisp_Hash_Table *h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]);
   Lisp_Object hash;
   ptrdiff_t i = hash_lookup (h, category_set, &hash);
index 283703b3651bfc6ba6bafc15cf03fe6971f53891..44c3efd1440f30de7489cddd2038f2c42c5418bd 100644 (file)
@@ -1699,7 +1699,7 @@ syms_of_module (void)
   Vmodule_refs_hash
     = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
                       DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-                      Qnil, false);
+                      Weak_None, false);
 
   DEFSYM (Qmodule_load_failed, "module-load-failed");
   Fput (Qmodule_load_failed, Qerror_conditions,
index 89434e02ca3c9ec19fb90710aaeae6a0423342ea..5837795f83803857e6aa78f74380236850adba38 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -4541,8 +4541,7 @@ hash_index_size (struct Lisp_Hash_Table *h, ptrdiff_t size)
    be resized when the approximate ratio of table entries to table
    size exceeds REHASH_THRESHOLD.
 
-   WEAK specifies the weakness of the table.  If non-nil, it must be
-   one of the symbols `key', `value', `key-or-value', or `key-and-value'.
+   WEAK specifies the weakness of the table.
 
    If PURECOPY is non-nil, the table can be copied to pure storage via
    `purecopy' when Emacs is being dumped. Such tables can no longer be
@@ -4551,7 +4550,7 @@ hash_index_size (struct Lisp_Hash_Table *h, ptrdiff_t size)
 Lisp_Object
 make_hash_table (struct hash_table_test test, EMACS_INT size,
                 float rehash_size, float rehash_threshold,
-                Lisp_Object weak, bool purecopy)
+                hash_table_weakness_t weak, bool purecopy)
 {
   struct Lisp_Hash_Table *h;
   Lisp_Object table;
@@ -4571,7 +4570,7 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
 
   /* Initialize hash table slots.  */
   h->test = test;
-  h->weak = weak;
+  h->weakness = weak;
   h->rehash_threshold = rehash_threshold;
   h->rehash_size = rehash_size;
   h->count = 0;
@@ -4869,6 +4868,23 @@ hash_clear (struct Lisp_Hash_Table *h)
                           Weak Hash Tables
  ************************************************************************/
 
+/* Whether to keep an entry whose key and value are known to be retained
+   if STRONG_KEY and STRONG_VALUE, respectively, are true.  */
+static inline bool
+keep_entry_p (hash_table_weakness_t weakness,
+             bool strong_key, bool strong_value)
+{
+  switch (weakness)
+    {
+    case Weak_None:          return true;
+    case Weak_Key:           return strong_key;
+    case Weak_Value:         return strong_value;
+    case Weak_Key_Or_Value:  return strong_key || strong_value;
+    case Weak_Key_And_Value: return strong_key && strong_value;
+    }
+  emacs_abort();
+}
+
 /* Sweep weak hash table H.  REMOVE_ENTRIES_P means remove
    entries from the table that don't survive the current GC.
    !REMOVE_ENTRIES_P means mark entries that are in use.  Value is
@@ -4890,18 +4906,9 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
         {
          bool key_known_to_survive_p = survives_gc_p (HASH_KEY (h, i));
          bool value_known_to_survive_p = survives_gc_p (HASH_VALUE (h, i));
-         bool remove_p;
-
-         if (EQ (h->weak, Qkey))
-           remove_p = !key_known_to_survive_p;
-         else if (EQ (h->weak, Qvalue))
-           remove_p = !value_known_to_survive_p;
-         else if (EQ (h->weak, Qkey_or_value))
-           remove_p = !(key_known_to_survive_p || value_known_to_survive_p);
-         else if (EQ (h->weak, Qkey_and_value))
-           remove_p = !(key_known_to_survive_p && value_known_to_survive_p);
-         else
-           emacs_abort ();
+         bool remove_p = !keep_entry_p (h->weakness,
+                                        key_known_to_survive_p,
+                                        value_known_to_survive_p);
 
          next = HASH_NEXT (h, i);
 
@@ -5367,15 +5374,20 @@ usage: (make-hash-table &rest KEYWORD-ARGS)  */)
 
   /* Look for `:weakness WEAK'.  */
   i = get_key_arg (QCweakness, nargs, args, used);
-  Lisp_Object weak = i ? args[i] : Qnil;
-  if (EQ (weak, Qt))
-    weak = Qkey_and_value;
-  if (!NILP (weak)
-      && !EQ (weak, Qkey)
-      && !EQ (weak, Qvalue)
-      && !EQ (weak, Qkey_or_value)
-      && !EQ (weak, Qkey_and_value))
-    signal_error ("Invalid hash table weakness", weak);
+  Lisp_Object weakness = i ? args[i] : Qnil;
+  hash_table_weakness_t weak;
+  if (NILP (weakness))
+    weak = Weak_None;
+  else if (EQ (weakness, Qkey))
+    weak = Weak_Key;
+  else if (EQ (weakness, Qvalue))
+    weak = Weak_Value;
+  else if (EQ (weakness, Qkey_or_value))
+    weak = Weak_Key_Or_Value;
+  else if (EQ (weakness, Qt) || EQ (weakness, Qkey_and_value))
+    weak = Weak_Key_And_Value;
+  else
+    signal_error ("Invalid hash table weakness", weakness);
 
   /* Now, all args should have been used up, or there's a problem.  */
   for (i = 0; i < nargs; ++i)
@@ -5449,13 +5461,26 @@ DEFUN ("hash-table-test", Fhash_table_test, Shash_table_test, 1, 1, 0,
   return check_hash_table (table)->test.name;
 }
 
+Lisp_Object
+hash_table_weakness_symbol (hash_table_weakness_t weak)
+{
+  switch (weak)
+    {
+    case Weak_None:          return Qnil;
+    case Weak_Key:           return Qkey;
+    case Weak_Value:         return Qvalue;
+    case Weak_Key_And_Value: return Qkey_and_value;
+    case Weak_Key_Or_Value:  return Qkey_or_value;
+    }
+  emacs_abort ();
+}
 
 DEFUN ("hash-table-weakness", Fhash_table_weakness, Shash_table_weakness,
        1, 1, 0,
        doc: /* Return the weakness of TABLE.  */)
   (Lisp_Object table)
 {
-  return check_hash_table (table)->weak;
+  return hash_table_weakness_symbol (check_hash_table (table)->weakness);
 }
 
 
index f5b07e212f218185f923147c6ab7717289df13ac..41b0f2f5764b1ecbd3ab9486933438cbc57ba3f5 100644 (file)
@@ -1041,7 +1041,7 @@ make_frame (bool mini_p)
 
   fset_face_hash_table
     (f, make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-                         DEFAULT_REHASH_THRESHOLD, Qnil, false));
+                         DEFAULT_REHASH_THRESHOLD, Weak_None, false));
 
   if (mini_p)
     {
index 252b83da992e27a59f9d98dd44cdf8a1dbab23c0..92e1e0b0be721db1a37153fc980491ff3691a790 100644 (file)
@@ -6071,7 +6071,7 @@ xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
   *get_func = xpm_get_color_table_h;
   return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
                          DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-                         Qnil, false);
+                         Weak_None, false);
 }
 
 static void
index e80a6388657ad59e323c2565c053af44f26aebea..480d963e63d87571ad6178b3743caf31e899d68a 100644 (file)
@@ -2403,6 +2403,18 @@ struct hash_table_test
   Lisp_Object (*hashfn) (Lisp_Object, struct Lisp_Hash_Table *);
 };
 
+typedef enum {
+  Weak_None,            /* No weak references.  */
+  Weak_Key,             /* Reference to key is weak.  */
+  Weak_Value,           /* Reference to value is weak.  */
+  Weak_Key_Or_Value,    /* References to key or value are weak:
+                           element kept as long as strong reference to
+                           either key or value remains.  */
+  Weak_Key_And_Value,   /* References to key and value are weak:
+                           element kept as long as strong references to
+                           both key and value remain.  */
+} hash_table_weakness_t;
+
 struct Lisp_Hash_Table
 {
   union vectorlike_header header;
@@ -2432,10 +2444,6 @@ struct Lisp_Hash_Table
      The table is physically split into three vectors (hash, next,
      key_and_value) which may or may not be beneficial.  */
 
-  /* Nil if table is non-weak.  Otherwise a symbol describing the
-     weakness of the table.  */
-  Lisp_Object weak;
-
   /* Vector of hash codes, or nil if the table needs rehashing.
      If the I-th entry is unused, then hash[I] should be nil.  */
   Lisp_Object hash;
@@ -2462,6 +2470,9 @@ struct Lisp_Hash_Table
   /* Index of first free entry in free list, or -1 if none.  */
   ptrdiff_t next_free;
 
+  /* Weakness of the table.  */
+  hash_table_weakness_t weakness : 8;
+
   /* True if the table can be purecopied.  The table cannot be
      changed afterwards.  */
   bool purecopy;
@@ -2498,7 +2509,7 @@ struct Lisp_Hash_Table
 } GCALIGNED_STRUCT;
 
 /* Sanity-check pseudovector layout.  */
-verify (offsetof (struct Lisp_Hash_Table, weak) == header_size);
+verify (offsetof (struct Lisp_Hash_Table, hash) == header_size);
 
 /* Key value that marks an unused hash table entry.  */
 #define HASH_UNUSED_ENTRY_KEY Qunbound
@@ -4050,7 +4061,8 @@ EMACS_UINT hash_string (char const *, ptrdiff_t);
 EMACS_UINT sxhash (Lisp_Object);
 Lisp_Object hashfn_user_defined (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,
-                             Lisp_Object, bool);
+                             hash_table_weakness_t, bool);
+Lisp_Object hash_table_weakness_symbol (hash_table_weakness_t weak);
 ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object *);
 ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
                    Lisp_Object);
index 1889480137698ab2cd402da437e0aaf4c78d6a93..6d3c06265e0f966b464420b827900c89a7425846 100644 (file)
@@ -2546,13 +2546,13 @@ readevalloop (Lisp_Object readcharfun,
        read_objects_map
          = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
                             DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-                            Qnil, false);
+                            Weak_None, false);
       if (! HASH_TABLE_P (read_objects_completed)
          || XHASH_TABLE (read_objects_completed)->count)
        read_objects_completed
          = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
                             DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-                            Qnil, false);
+                            Weak_None, false);
       if (!NILP (Vpurify_flag) && c == '(')
        val = read0 (readcharfun, false);
       else
@@ -2797,12 +2797,12 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end,
       || XHASH_TABLE (read_objects_map)->count)
     read_objects_map
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-                        DEFAULT_REHASH_THRESHOLD, Qnil, false);
+                        DEFAULT_REHASH_THRESHOLD, Weak_None, false);
   if (! HASH_TABLE_P (read_objects_completed)
       || XHASH_TABLE (read_objects_completed)->count)
     read_objects_completed
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-                        DEFAULT_REHASH_THRESHOLD, Qnil, false);
+                        DEFAULT_REHASH_THRESHOLD, Weak_None, false);
 
   if (STRINGP (stream)
       || ((CONSP (stream) && STRINGP (XCAR (stream)))))
index c72db7f3ea3e855660951b7fe1fff2a67e2ec67f..982b991dc63347136696ef93b771a1c1aa93afd9 100644 (file)
@@ -2726,6 +2726,7 @@ dump_hash_table (struct dump_context *ctx, Lisp_Object object)
      them as close to the hash table as possible.  */
   DUMP_FIELD_COPY (out, hash, count);
   DUMP_FIELD_COPY (out, hash, next_free);
+  DUMP_FIELD_COPY (out, hash, weakness);
   DUMP_FIELD_COPY (out, hash, purecopy);
   DUMP_FIELD_COPY (out, hash, mutable);
   DUMP_FIELD_COPY (out, hash, rehash_threshold);
index 2f7a390d22d82326f498cb9c9582723c9234edce..b45cf56135de75303b84163ad10933329d2285e2 100644 (file)
@@ -7179,7 +7179,8 @@ If set to a non-float value, there will be no wait at all.  */);
   DEFVAR_LISP ("pgtk-keysym-table", Vpgtk_keysym_table,
     doc: /* Hash table of character codes indexed by X keysym codes.  */);
   Vpgtk_keysym_table = make_hash_table (hashtest_eql, 900, DEFAULT_REHASH_SIZE,
-                                       DEFAULT_REHASH_THRESHOLD, Qnil, false);
+                                       DEFAULT_REHASH_THRESHOLD,
+                                       Weak_None, false);
 
   window_being_scrolled = Qnil;
   staticpro (&window_being_scrolled);
index c1c91b2383a8bf5c872330aab82c41474f8c7a48..9c36144445853b3f25e50c304ee56dd4a0fa37f7 100644 (file)
@@ -2583,10 +2583,11 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
                print_object (h->test.name, printcharfun, escapeflag);
              }
 
-           if (!NILP (h->weak))
+           if (h->weakness != Weak_None)
              {
                print_c_string (" weakness ", printcharfun);
-               print_object (h->weak, printcharfun, escapeflag);
+               print_object (hash_table_weakness_symbol (h->weakness),
+                             printcharfun, escapeflag);
              }
 
            print_c_string (" rehash-size ", printcharfun);
index 48a042cc8aa0600a2a899318b1aa691bba88b480..a75998c7c40ad1cebf2d6f3072cb178a1bd99778 100644 (file)
@@ -566,7 +566,7 @@ export_log (struct profiler_log *plog)
   Lisp_Object h = make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
                                   DEFAULT_REHASH_SIZE,
                                   DEFAULT_REHASH_THRESHOLD,
-                                  Qnil, false);
+                                  Weak_None, false);
   for (int i = 0; i < log->size; i++)
     {
       int count = get_log_count (log, i);
index c9ade2769bd39d9f66f73360e71f25b59bea0cfc..7c3dd7ebc15e90e2056da8f29403c80ec84e8c44 100644 (file)
@@ -7334,7 +7334,7 @@ only for this purpose.  */);
   Vface_new_frame_defaults =
     /* 33 entries is enough to fit all basic faces */
     make_hash_table (hashtest_eq, 33, DEFAULT_REHASH_SIZE,
-                     DEFAULT_REHASH_THRESHOLD, Qnil, false);
+                     DEFAULT_REHASH_THRESHOLD, Weak_None, false);
 
   DEFVAR_LISP ("face-default-stipple", Vface_default_stipple,
     doc: /* Default stipple pattern used on monochrome displays.
index 0cbf32ae1ea84b7a6a1ecf748f4ef6890841824a..98f8c8afb3bb3ffadd2871444cf707d0dd5b4c41 100644 (file)
@@ -32557,7 +32557,7 @@ If set to a non-float value, there will be no wait at all.  */);
   Vx_keysym_table = make_hash_table (hashtest_eql, 900,
                                     DEFAULT_REHASH_SIZE,
                                     DEFAULT_REHASH_THRESHOLD,
-                                    Qnil, false);
+                                    Weak_None, false);
 
   DEFVAR_BOOL ("x-frame-normalize-before-maximize",
               x_frame_normalize_before_maximize,