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.
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);
/* 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. */
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
{
(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);
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,
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
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;
/* 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;
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
{
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);
/* 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)
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);
}
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)
{
*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
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;
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;
/* 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;
} 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
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);
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
|| 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)))))
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);
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);
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);
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);
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.
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,