emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scratch/obarray 37fdb9d87f3 8/9: add PVEC_OBARRAY and use it for obarray


From: Mattias Engdegård
Subject: scratch/obarray 37fdb9d87f3 8/9: add PVEC_OBARRAY and use it for obarray functions
Date: Mon, 12 Feb 2024 09:10:55 -0500 (EST)

branch: scratch/obarray
commit 37fdb9d87f37945f8ac59b133925f7c443dad478
Author: Mattias Engdegård <mattiase@acm.org>
Commit: Mattias Engdegård <mattiase@acm.org>

    add PVEC_OBARRAY and use it for obarray functions
    
    New C definitions for obarray-make and obarray-size, replacing elisp
    New functions obarray-object-p and obarray-clear
    Adapt all functions to accept both obarray objects and vectors
     as obarray values
---
 etc/emacs_lldb.py          |   1 +
 lisp/obarray.el            |  28 +---
 src/alloc.c                |  19 +++
 src/data.c                 |   2 +
 src/lisp.h                 |  64 ++++++++-
 src/lread.c                | 336 ++++++++++++++++++++++++++++++++++++---------
 src/minibuf.c              |  67 ++++++---
 src/pdumper.c              |  47 +++++++
 src/print.c                |   8 ++
 test/lisp/obarray-tests.el |  11 +-
 10 files changed, 473 insertions(+), 110 deletions(-)

diff --git a/etc/emacs_lldb.py b/etc/emacs_lldb.py
index fdf4314e2d0..9865fe391a2 100644
--- a/etc/emacs_lldb.py
+++ b/etc/emacs_lldb.py
@@ -56,6 +56,7 @@ class Lisp_Object:
         "PVEC_BOOL_VECTOR": "struct Lisp_Bool_Vector",
         "PVEC_BUFFER": "struct buffer",
         "PVEC_HASH_TABLE": "struct Lisp_Hash_Table",
+        "PVEC_OBARRAY": "struct Lisp_Obarray",
         "PVEC_TERMINAL": "struct terminal",
         "PVEC_WINDOW_CONFIGURATION": "struct save_window_data",
         "PVEC_SUBR": "struct Lisp_Subr",
diff --git a/lisp/obarray.el b/lisp/obarray.el
index e1ebb2ade51..bc9086c90ad 100644
--- a/lisp/obarray.el
+++ b/lisp/obarray.el
@@ -27,24 +27,15 @@
 
 ;;; Code:
 
-(defconst obarray-default-size 59
-  "The value 59 is an arbitrary prime number that gives a good hash.")
-
-(defun obarray-make (&optional size)
-  "Return a new obarray of size SIZE or `obarray-default-size'."
-  (let ((size (or size obarray-default-size)))
-    (if (< 0 size)
-        (make-vector size 0)
-      (signal 'wrong-type-argument '(size 0)))))
-
-(defun obarray-size (ob)
-  "Return the number of slots of obarray OB."
-  (length ob))
+(defconst obarray-default-size 4)
+(make-obsolete-variable 'obarray-default-size
+                        "obarrays now grow automatically" "30.1")
 
 (defun obarrayp (object)
-  "Return t if OBJECT is an obarray."
-  (and (vectorp object)
-       (< 0 (length object))))
+  "Return t if OBJECT is an obarray object or a nonempty vector.
+See also `obarray-object-p'."
+  (or (obarray-object-p object)
+      (and (vectorp object) (< 0 (length object)))))
 
 ;; Don’t use obarray as a variable name to avoid shadowing.
 (defun obarray-get (ob name)
@@ -66,10 +57,5 @@ Return t on success, nil otherwise."
   "Call function FN on every symbol in obarray OB and return nil."
   (mapatoms fn ob))
 
-(defun obarray-clear (ob)
-  "Remove all symbols from obarray OB."
-  ;; FIXME: This doesn't change the symbols to uninterned status.
-  (fillarray ob 0))
-
 (provide 'obarray)
 ;;; obarray.el ends here
diff --git a/src/alloc.c b/src/alloc.c
index 6abe9e28650..990f75fc8fa 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3455,6 +3455,17 @@ cleanup_vector (struct Lisp_Vector *vector)
            hash_table_allocated_bytes -= bytes;
          }
       }
+      break;
+    case PVEC_OBARRAY:
+      {
+       struct Lisp_Obarray *o = PSEUDOVEC_STRUCT (vector, Lisp_Obarray);
+       eassert (o->size_bits > 0);
+       xfree (o->buckets);
+       ptrdiff_t bytes = (sizeof *o->buckets) << o->size_bits;
+       /* FIXME: should have our own counter */
+       hash_table_allocated_bytes -= bytes;
+      }
+      break;
     /* Keep the switch exhaustive.  */
     case PVEC_NORMAL_VECTOR:
     case PVEC_FREE:
@@ -7311,6 +7322,14 @@ process_mark_stack (ptrdiff_t base_sp)
                  break;
                }
 
+             case PVEC_OBARRAY:
+               {
+                 struct Lisp_Obarray *o = (struct Lisp_Obarray *)ptr;
+                 set_vector_marked (ptr);
+                 mark_stack_push_values (o->buckets, 1 << o->size_bits);
+                 break;
+               }
+
              case PVEC_CHAR_TABLE:
              case PVEC_SUB_CHAR_TABLE:
                mark_char_table (ptr, (enum pvec_type) pvectype);
diff --git a/src/data.c b/src/data.c
index 0c47750cb75..8b6005f8699 100644
--- a/src/data.c
+++ b/src/data.c
@@ -231,6 +231,7 @@ for example, (type-of 1) returns `integer'.  */)
         case PVEC_BOOL_VECTOR: return Qbool_vector;
         case PVEC_FRAME: return Qframe;
         case PVEC_HASH_TABLE: return Qhash_table;
+        case PVEC_OBARRAY: return Qobarray;
         case PVEC_FONT:
           if (FONT_SPEC_P (object))
            return Qfont_spec;
@@ -4238,6 +4239,7 @@ syms_of_data (void)
   DEFSYM (Qtreesit_parser, "treesit-parser");
   DEFSYM (Qtreesit_node, "treesit-node");
   DEFSYM (Qtreesit_compiled_query, "treesit-compiled-query");
+  DEFSYM (Qobarray, "obarray");
 
   DEFSYM (Qdefun, "defun");
 
diff --git a/src/lisp.h b/src/lisp.h
index 5326824bf38..54b8e42c61c 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1062,6 +1062,7 @@ enum pvec_type
   PVEC_BOOL_VECTOR,
   PVEC_BUFFER,
   PVEC_HASH_TABLE,
+  PVEC_OBARRAY,
   PVEC_TERMINAL,
   PVEC_WINDOW_CONFIGURATION,
   PVEC_SUBR,
@@ -2393,6 +2394,68 @@ INLINE int
    definition is done by lread.c's define_symbol.  */
 #define DEFSYM(sym, name) /* empty */
 
+
+struct Lisp_Obarray
+{
+  union vectorlike_header header;
+
+  /* Array of 2**bits values, each being either a (bare) symbol or
+     the fixnum 0.  The symbols for each bucket are chained via
+     their s.next field.  */
+  Lisp_Object *buckets;
+
+  unsigned size_bits;  /* log2(size of buckets vector), always positive */
+  unsigned count;      /* number of symbols in obarray */
+};
+
+INLINE bool
+OBARRAYP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_OBARRAY);
+}
+
+INLINE struct Lisp_Obarray *
+XOBARRAY (Lisp_Object a)
+{
+  eassert (OBARRAYP (a));
+  return XUNTAG (a, Lisp_Vectorlike, struct Lisp_Obarray);
+}
+
+INLINE void
+CHECK_OBARRAY (Lisp_Object x)
+{
+  CHECK_TYPE (OBARRAYP (x), Qobarrayp, x);
+}
+
+INLINE Lisp_Object
+make_lisp_obarray (struct Lisp_Obarray *o)
+{
+  eassert (PSEUDOVECTOR_TYPEP (&o->header, PVEC_OBARRAY));
+  return make_lisp_ptr (o, Lisp_Vectorlike);
+}
+
+INLINE ptrdiff_t
+obarray_size (Lisp_Object a)
+{
+  eassert (OBARRAYP (a));
+  return 1 << XOBARRAY (a)->size_bits;
+}
+
+INLINE Lisp_Object
+obarray_bucket (Lisp_Object a, ptrdiff_t index)
+{
+  eassert (OBARRAYP (a));
+  return XOBARRAY (a)->buckets[index];
+}
+
+Lisp_Object check_obarray_slow (Lisp_Object);
+
+INLINE Lisp_Object
+check_obarray (Lisp_Object obarray)
+{
+  return OBARRAYP (obarray) ? obarray : check_obarray_slow (obarray);
+}
+
 
 /***********************************************************************
                             Hash Tables
@@ -4604,7 +4667,6 @@ extern ptrdiff_t evxprintf (char **, ptrdiff_t *, char *, 
ptrdiff_t,
   ATTRIBUTE_FORMAT_PRINTF (5, 0);
 
 /* Defined in lread.c.  */
-extern Lisp_Object check_obarray (Lisp_Object);
 extern Lisp_Object intern_1 (const char *, ptrdiff_t);
 extern Lisp_Object intern_c_string_1 (const char *, ptrdiff_t);
 extern Lisp_Object intern_driver (Lisp_Object, Lisp_Object, Lisp_Object);
diff --git a/src/lread.c b/src/lread.c
index 71564f8a0f1..d8c9dd10ef0 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -4888,7 +4888,7 @@ static size_t oblookup_last_bucket_number;
    If it is one, return it.  */
 
 Lisp_Object
-check_obarray (Lisp_Object obarray)
+check_obarray_slow (Lisp_Object obarray)
 {
   /* We don't want to signal a wrong-type-argument error when we are
      shutting down due to a fatal error, and we don't want to hit
@@ -4898,13 +4898,16 @@ check_obarray (Lisp_Object obarray)
     {
       /* If Vobarray is now invalid, force it to be valid.  */
       if (EQ (Vobarray, obarray)) Vobarray = initial_obarray;
-      wrong_type_argument (Qvectorp, obarray);
+      wrong_type_argument (Qobarrayp, obarray);
     }
   return obarray;
 }
 
+static void grow_obarray (struct Lisp_Obarray *o);
+
 /* Intern symbol SYM in OBARRAY using bucket INDEX.  */
 
+/* FIXME: retype index as a C integer, maybe sym as a symbol struct */
 static Lisp_Object
 intern_sym (Lisp_Object sym, Lisp_Object obarray, Lisp_Object index)
 {
@@ -4923,9 +4926,22 @@ intern_sym (Lisp_Object sym, Lisp_Object obarray, 
Lisp_Object index)
       SET_SYMBOL_VAL (s, sym);
     }
 
-  Lisp_Object *ptr = aref_addr (obarray, XFIXNUM (index));
-  s->u.s.next = BARE_SYMBOL_P (*ptr) ? XBARE_SYMBOL (*ptr) : NULL;
-  *ptr = sym;
+  if (OBARRAYP (obarray))
+    {
+      struct Lisp_Obarray *o = XOBARRAY (obarray);
+      Lisp_Object *ptr = o->buckets + XFIXNUM (index);
+      s->u.s.next = BARE_SYMBOL_P (*ptr) ? XBARE_SYMBOL (*ptr) : NULL;
+      *ptr = sym;
+      o->count++;
+      if (o->count > (1 << o->size_bits))
+       grow_obarray (o);
+    }
+  else
+    {
+      Lisp_Object *ptr = aref_addr (obarray, XFIXNUM (index));
+      s->u.s.next = BARE_SYMBOL_P (*ptr) ? XBARE_SYMBOL (*ptr) : NULL;
+      *ptr = sym;
+    }
   return sym;
 }
 
@@ -5079,7 +5095,6 @@ usage: (unintern NAME OBARRAY)  */)
 {
   register Lisp_Object tem;
   Lisp_Object string;
-  size_t hash;
 
   if (NILP (obarray)) obarray = Vobarray;
   obarray = check_obarray (obarray);
@@ -5119,41 +5134,63 @@ usage: (unintern NAME OBARRAY)  */)
   /* if (NILP (tem) || EQ (tem, Qt))
        error ("Attempt to unintern t or nil"); */
 
-  XBARE_SYMBOL (tem)->u.s.interned = SYMBOL_UNINTERNED;
+  struct Lisp_Symbol *sym = XBARE_SYMBOL (tem);
+  sym->u.s.interned = SYMBOL_UNINTERNED;
 
-  hash = oblookup_last_bucket_number;
+  ptrdiff_t idx = oblookup_last_bucket_number;
+  Lisp_Object *loc = (OBARRAYP (obarray)
+                     ? &XOBARRAY (obarray)->buckets[idx]
+                     : aref_addr (obarray, idx));
 
-  if (BASE_EQ (AREF (obarray, hash), tem))
-    {
-      if (XBARE_SYMBOL (tem)->u.s.next)
-       {
-         Lisp_Object sym;
-         XSETSYMBOL (sym, XBARE_SYMBOL (tem)->u.s.next);
-         ASET (obarray, hash, sym);
-       }
-      else
-       ASET (obarray, hash, make_fixnum (0));
-    }
+  eassert (BARE_SYMBOL_P (*loc));
+  struct Lisp_Symbol *prev = XBARE_SYMBOL (*loc);
+  if (sym == prev)
+    *loc = sym->u.s.next ? make_lisp_symbol (sym->u.s.next) : make_fixnum (0);
   else
-    {
-      Lisp_Object tail, following;
+    while (1)
+      {
+       struct Lisp_Symbol *next = prev->u.s.next;
+       if (next == sym)
+         {
+           prev->u.s.next = next->u.s.next;
+           break;
+         }
+       prev = next;
+      }
 
-      for (tail = AREF (obarray, hash);
-          XBARE_SYMBOL (tail)->u.s.next;
-          tail = following)
-       {
-         XSETSYMBOL (following, XBARE_SYMBOL (tail)->u.s.next);
-         if (BASE_EQ (following, tem))
-           {
-             set_symbol_next (tail, XBARE_SYMBOL (following)->u.s.next);
-             break;
-           }
-       }
-    }
+  if (OBARRAYP (obarray))
+    XOBARRAY (obarray)->count--;
 
   return Qt;
 }
 
+
+/* FIXME: copied from fns.c, should move to lisp.h */
+static inline hash_hash_t
+reduce_emacs_uint_to_hash_hash (EMACS_UINT x)
+{
+  verify (sizeof x <= 2 * sizeof (hash_hash_t));
+  return (sizeof x == sizeof (hash_hash_t)
+         ? x
+         : x ^ (x >> (8 * (sizeof x - sizeof (hash_hash_t)))));
+}
+
+/* Bucket index of the string STR of length SIZE_BYTE bytes in obarray OA.  */
+static ptrdiff_t
+obarray_index (struct Lisp_Obarray *oa, const char *str, ptrdiff_t size_byte)
+{
+  unsigned bits = oa->size_bits;
+  EMACS_UINT hash = hash_string (str, size_byte);
+#if 1
+  uint32_t hash32 = reduce_emacs_uint_to_hash_hash (hash);
+  uint32_t alpha = 2654435769; /* 2**32/phi */
+  return (uint64_t)((uint32_t)hash32 * alpha) >> (32 - bits);
+#else
+  uint64_t alpha = 11400714819323198485uLL;    /* 2**64/phi */
+  return ((uint64_t)hash * alpha) >> (64 - bits);
+#endif
+}
+
 /* Return the symbol in OBARRAY whose names matches the string
    of SIZE characters (SIZE_BYTE bytes) at PTR.
    If there is no such symbol, return the integer bucket number of
@@ -5164,17 +5201,24 @@ usage: (unintern NAME OBARRAY)  */)
 Lisp_Object
 oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, 
ptrdiff_t size_byte)
 {
-  size_t hash;
-  size_t obsize;
-  register Lisp_Object tail;
-  Lisp_Object bucket, tem;
+  Lisp_Object bucket;
+  ptrdiff_t idx;
+  if (OBARRAYP (obarray))
+    {
+      struct Lisp_Obarray *o = XOBARRAY (obarray);
+      idx = obarray_index (o, ptr, size_byte);
+      bucket = o->buckets[idx];
+    }
+  else
+    {
+      obarray = check_obarray (obarray);
+      /* This is sometimes needed in the middle of GC.  */
+      size_t obsize = gc_asize (obarray);
+      idx = hash_string (ptr, size_byte) % obsize;
+      bucket = AREF (obarray, idx);
+    }
 
-  obarray = check_obarray (obarray);
-  /* This is sometimes needed in the middle of GC.  */
-  obsize = gc_asize (obarray);
-  hash = hash_string (ptr, size_byte) % obsize;
-  bucket = AREF (obarray, hash);
-  oblookup_last_bucket_number = hash;
+  oblookup_last_bucket_number = idx;
   if (BASE_EQ (bucket, make_fixnum (0)))
     ;
   else if (!BARE_SYMBOL_P (bucket))
@@ -5182,18 +5226,21 @@ oblookup (Lisp_Object obarray, register const char 
*ptr, ptrdiff_t size, ptrdiff
     xsignal2 (Qwrong_type_argument, Qobarrayp,
              build_string ("Bad data in guts of obarray"));
   else
-    for (tail = bucket; ; XSETSYMBOL (tail, XBARE_SYMBOL (tail)->u.s.next))
-      {
-       Lisp_Object name = XBARE_SYMBOL (tail)->u.s.name;
-       if (SBYTES (name) == size_byte
-           && SCHARS (name) == size
-           && !memcmp (SDATA (name), ptr, size_byte))
-         return tail;
-       else if (XBARE_SYMBOL (tail)->u.s.next == 0)
-         break;
-      }
-  XSETINT (tem, hash);
-  return tem;
+    {
+      Lisp_Object sym = bucket;
+      while (1)
+       {
+         struct Lisp_Symbol *s = XBARE_SYMBOL (sym);
+         Lisp_Object name = s->u.s.name;
+         if (SBYTES (name) == size_byte && SCHARS (name) == size
+             && memcmp (SDATA (name), ptr, size_byte) == 0)
+           return sym;
+         if (s->u.s.next == NULL)
+           break;
+         sym = make_lisp_symbol(s->u.s.next);
+       }
+    }
+  return make_fixnum (idx);
 }
 
 /* Like 'oblookup', but considers 'Vread_symbol_shorthands',
@@ -5260,22 +5307,164 @@ oblookup_considering_shorthand (Lisp_Object obarray, 
const char *in,
 }
 
 
+static struct Lisp_Obarray *
+allocate_obarray (void)
+{
+  return ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Obarray, PVEC_OBARRAY);
+}
+
+static Lisp_Object
+make_obarray (int bits)
+{
+  eassert (bits > 0);
+  struct Lisp_Obarray *o = allocate_obarray ();
+  o->count = 0;
+  o->size_bits = bits;
+  ptrdiff_t size = 1 << bits;
+  o->buckets = hash_table_alloc_bytes (size * sizeof *o->buckets);
+  for (ptrdiff_t i = 0; i < size; i++)
+    o->buckets[i] = make_fixnum (0);
+  return make_lisp_obarray (o);
+}
+
+static void
+grow_obarray (struct Lisp_Obarray *o)
+{
+  ptrdiff_t old_size = 1 << o->size_bits;
+  eassert (o->count > old_size);
+  Lisp_Object *old_buckets = o->buckets;
+
+  int new_bits = o->size_bits + 1;
+  ptrdiff_t new_size = 1 << new_bits;
+  o->buckets = hash_table_alloc_bytes (new_size * sizeof *o->buckets);
+  for (ptrdiff_t i = 0; i < new_size; i++)
+    o->buckets[i] = make_fixnum (0);
+  o->size_bits = new_bits;
+
+  /* Rehash symbols.
+     FIXME: this is expensive since we need to recompute hashes for every
+     symbol name.  Would it be reasonable to store it in the symbol?  */
+  for (ptrdiff_t i = 0; i < old_size; i++)
+    {
+      Lisp_Object obj = old_buckets[i];
+      if (BARE_SYMBOL_P (obj))
+       {
+         struct Lisp_Symbol *s = XBARE_SYMBOL (obj);
+         while (1)
+           {
+             Lisp_Object name = s->u.s.name;
+             ptrdiff_t idx = obarray_index (o, SSDATA (name), SBYTES (name));
+             Lisp_Object *loc = o->buckets + idx;
+             struct Lisp_Symbol *next = s->u.s.next;
+             s->u.s.next = BARE_SYMBOL_P (*loc) ? XBARE_SYMBOL (*loc) : NULL;
+             *loc = make_lisp_symbol (s);
+             if (next == NULL)
+               break;
+             s = next;
+           }
+       }
+    }
+
+  hash_table_free_bytes (old_buckets, old_size * sizeof *old_buckets);
+}
+
+enum { obarray_default_bits = 3 };
+
+DEFUN ("obarray-make", Fobarray_make, Sobarray_make, 0, 1, 0,
+       doc: /* Return a new obarray of size SIZE.
+The obarray will grow to accommodate any number of symbols; the size, if
+given, is only a hint for the expected number.  */)
+  (Lisp_Object size)
+{
+  EMACS_INT n;
+  if (NILP (size))
+    n = obarray_default_bits - 1;
+  else
+    {
+      CHECK_FIXNUM (size);
+      n = XFIXNUM (size);
+      if (n < 1)
+       n = 1;
+    }
+  int bits = elogb (n) + 1;
+  eassert (bits > 0);
+  return make_obarray (bits);
+}
+
+DEFUN ("obarray-object-p", Fobarray_object_p, Sobarray_object_p, 1, 1, 0,
+       doc: /* Return t iff OBJECT is an obarray object.
+See also `obarrayp' which also accepts old vector-based obarrays.  */)
+  (Lisp_Object object)
+{
+  return OBARRAYP (object) ? Qt : Qnil;
+}
+
+DEFUN ("obarray-size", Fobarray_size, Sobarray_size, 1, 1, 0,
+       doc: /* Allocated size of OBARRAY.
+This is not the number of symbols in OBARRAY, but an internal size
+that is rarely of interest.  */)
+  (Lisp_Object obarray)
+{
+  if (VECTORP (obarray))
+    return Flength (obarray);
+  CHECK_OBARRAY (obarray);
+  return make_fixnum (1 << XOBARRAY (obarray)->size_bits);
+}
+
+DEFUN ("obarray-clear", Fobarray_clear, Sobarray_clear, 1, 1, 0,
+       doc: /* Remove all symbols from OBARRAY.  */)
+  (Lisp_Object obarray)
+{
+  /* FIXME: This code doesn't set the symbol status to uninterned.  */
+  /* FIXME: Should it work on vectors as well? (probably not)  */
+  CHECK_OBARRAY (obarray);
+  struct Lisp_Obarray *o = XOBARRAY (obarray);
+
+  int new_bits = obarray_default_bits;
+  int new_size = 1 << new_bits;
+  Lisp_Object *new_buckets
+    = hash_table_alloc_bytes (new_size * sizeof *new_buckets);
+  for (ptrdiff_t i = 0; i < new_size; i++)
+    new_buckets[i] = make_fixnum (0);
+
+  int old_size = 1 << o->size_bits;
+  hash_table_free_bytes (o->buckets, old_size * sizeof *o->buckets);
+  o->buckets = new_buckets;
+  o->size_bits = new_bits;
+  o->count = 0;
+
+  return Qnil;
+}
+
 void
-map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), 
Lisp_Object arg)
+map_obarray (Lisp_Object obarray,
+            void (*fn) (Lisp_Object, Lisp_Object), Lisp_Object arg)
 {
-  ptrdiff_t i;
-  register Lisp_Object tail;
-  CHECK_VECTOR (obarray);
-  for (i = ASIZE (obarray) - 1; i >= 0; i--)
+  Lisp_Object *buckets;
+  ptrdiff_t size;
+  if (OBARRAYP (obarray))
     {
-      tail = AREF (obarray, i);
+      struct Lisp_Obarray *o = XOBARRAY (obarray);
+      buckets = o->buckets;
+      size = 1 << o->size_bits;
+    }
+  else
+    {
+      CHECK_VECTOR (obarray);
+      buckets = XVECTOR (obarray)->contents;
+      size = ASIZE (obarray);
+    }
+
+  for (ptrdiff_t i = 0; i < size; i++)
+    {
+      Lisp_Object tail = buckets[i];
       if (BARE_SYMBOL_P (tail))
        while (1)
          {
            (*fn) (tail, arg);
            if (XBARE_SYMBOL (tail)->u.s.next == 0)
              break;
-           XSETSYMBOL (tail, XBARE_SYMBOL (tail)->u.s.next);
+           tail = make_lisp_symbol (XBARE_SYMBOL (tail)->u.s.next);
          }
     }
 }
@@ -5304,12 +5493,24 @@ DEFUN ("internal--obarray-buckets",
     (Lisp_Object obarray)
 {
   obarray = check_obarray (obarray);
-  ptrdiff_t size = ASIZE (obarray);
+  ptrdiff_t size;
+  Lisp_Object *buckets;
+  if (OBARRAYP (obarray))
+    {
+      struct Lisp_Obarray *o = XOBARRAY (obarray);
+      size = 1 << o->size_bits;
+      buckets = o->buckets;
+    }
+  else
+    {
+      size = ASIZE (obarray);
+      buckets = XVECTOR (obarray)->contents;
+    }
   Lisp_Object ret = Qnil;
   for (ptrdiff_t i = 0; i < size; i++)
     {
       Lisp_Object bucket = Qnil;
-      Lisp_Object sym = AREF (obarray, i);
+      Lisp_Object sym = buckets[i];
       if (BARE_SYMBOL_P (sym))
        while (1)
          {
@@ -5324,11 +5525,12 @@ DEFUN ("internal--obarray-buckets",
   return Fnreverse (ret);
 }
 
-#define OBARRAY_SIZE 15121
+#define OBARRAY_SIZE 16384
 
 void
 init_obarray_once (void)
 {
+  /* FIXME: use PVEC_OBARRAY */
   Vobarray = make_vector (OBARRAY_SIZE, make_fixnum (0));
   initial_obarray = Vobarray;
   staticpro (&initial_obarray);
@@ -5712,6 +5914,10 @@ syms_of_lread (void)
   defsubr (&Smapatoms);
   defsubr (&Slocate_file_internal);
   defsubr (&Sinternal__obarray_buckets);
+  defsubr (&Sobarray_make);
+  defsubr (&Sobarray_object_p);
+  defsubr (&Sobarray_size);
+  defsubr (&Sobarray_clear);
 
   DEFVAR_LISP ("obarray", Vobarray,
               doc: /* Symbol table for use by `intern' and `read'.
diff --git a/src/minibuf.c b/src/minibuf.c
index 7c0c9799a60..bdfc28fb719 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1617,7 +1617,7 @@ or from one of the possible completions.  */)
   ptrdiff_t compare, matchsize;
   enum { function_table, list_table, obarray_table, hash_table}
     type = (HASH_TABLE_P (collection) ? hash_table
-           : VECTORP (collection) ? obarray_table
+           : (OBARRAYP (collection) || VECTORP (collection)) ? obarray_table
            : ((NILP (collection)
                || (CONSP (collection) && !FUNCTIONP (collection)))
               ? list_table : function_table));
@@ -1637,8 +1637,16 @@ or from one of the possible completions.  */)
   if (type == obarray_table)
     {
       collection = check_obarray (collection);
-      obsize = ASIZE (collection);
-      bucket = AREF (collection, idx);
+      if (OBARRAYP (collection))
+       {
+         obsize = obarray_size (collection);
+         bucket = obarray_bucket (collection, idx);
+       }
+      else
+       {
+         obsize = ASIZE (collection);
+         bucket = AREF (collection, idx);
+       }
     }
 
   while (1)
@@ -1673,7 +1681,10 @@ or from one of the possible completions.  */)
            break;
          else
            {
-             bucket = AREF (collection, idx);
+             if (OBARRAYP (collection))
+               bucket = obarray_bucket (collection, idx);
+             else
+               bucket = AREF (collection, idx);
              continue;
            }
        }
@@ -1859,7 +1870,7 @@ with a space are ignored unless STRING itself starts with 
a space.  */)
   Lisp_Object tail, elt, eltstring;
   Lisp_Object allmatches;
   int type = HASH_TABLE_P (collection) ? 3
-    : VECTORP (collection) ? 2
+    : (OBARRAYP (collection) || VECTORP (collection)) ? 2
     : NILP (collection) || (CONSP (collection) && !FUNCTIONP (collection));
   ptrdiff_t idx = 0, obsize = 0;
   Lisp_Object bucket, tem, zero;
@@ -1875,8 +1886,16 @@ with a space are ignored unless STRING itself starts 
with a space.  */)
   if (type == 2)
     {
       collection = check_obarray (collection);
-      obsize = ASIZE (collection);
-      bucket = AREF (collection, idx);
+      if (OBARRAYP (collection))
+       {
+         obsize = obarray_size (collection);
+         bucket = obarray_bucket (collection, idx);
+       }
+      else
+       {
+         obsize = ASIZE (collection);
+         bucket = AREF (collection, idx);
+       }
     }
 
   while (1)
@@ -1911,7 +1930,10 @@ with a space are ignored unless STRING itself starts 
with a space.  */)
            break;
          else
            {
-             bucket = AREF (collection, idx);
+             if (OBARRAYP (collection))
+               bucket = obarray_bucket (collection, idx);
+             else
+               bucket = AREF (collection, idx);
              continue;
            }
        }
@@ -2069,19 +2091,32 @@ the values STRING, PREDICATE and `lambda'.  */)
       if (NILP (tem))
        return Qnil;
     }
-  else if (VECTORP (collection))
+  else if (OBARRAYP (collection) || VECTORP (collection))
     {
       /* Bypass intern-soft as that loses for nil.  */
       tem = oblookup (collection,
                      SSDATA (string),
                      SCHARS (string),
                      SBYTES (string));
-      if (completion_ignore_case && !SYMBOLP (tem))
+      if (completion_ignore_case && !BARE_SYMBOL_P (tem))
        {
-         for (ptrdiff_t i = ASIZE (collection) - 1; i >= 0; i--)
+         Lisp_Object *buckets;
+         ptrdiff_t size;
+         if (OBARRAYP (collection))
+           {
+             buckets = XOBARRAY (collection)->buckets;
+             size = obarray_size (collection);
+           }
+         else
+           {
+             buckets = XVECTOR (collection)->contents;
+             size = ASIZE (collection);
+           }
+
+         for (ptrdiff_t i = size - 1; i >= 0; i--)
            {
-             tail = AREF (collection, i);
-             if (SYMBOLP (tail))
+             tail = buckets[i];
+             if (BARE_SYMBOL_P (tail))
                while (1)
                  {
                    if (BASE_EQ (Fcompare_strings (string, make_fixnum (0),
@@ -2093,14 +2128,14 @@ the values STRING, PREDICATE and `lambda'.  */)
                        tem = tail;
                        break;
                      }
-                   if (XSYMBOL (tail)->u.s.next == 0)
+                   if (XBARE_SYMBOL (tail)->u.s.next == 0)
                      break;
-                   XSETSYMBOL (tail, XSYMBOL (tail)->u.s.next);
+                   XSETSYMBOL (tail, XBARE_SYMBOL (tail)->u.s.next);
                  }
            }
        }
 
-      if (!SYMBOLP (tem))
+      if (!BARE_SYMBOL_P (tem))
        return Qnil;
     }
   else if (HASH_TABLE_P (collection))
diff --git a/src/pdumper.c b/src/pdumper.c
index b8006b035ea..af839dbb98b 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2748,6 +2748,51 @@ dump_hash_table (struct dump_context *ctx, Lisp_Object 
object)
   return offset;
 }
 
+static dump_off
+dump_obarray_buckets (struct dump_context *ctx, const struct Lisp_Obarray *o)
+{
+  dump_align_output (ctx, DUMP_ALIGNMENT);
+  dump_off start_offset = ctx->offset;
+  ptrdiff_t n = 1 << o->size_bits;
+
+  struct dump_flags old_flags = ctx->flags;
+  ctx->flags.pack_objects = true;
+
+  for (ptrdiff_t i = 0; i < n; i++)
+    {
+      Lisp_Object out;
+      const Lisp_Object *slot = &o->buckets[i];
+      dump_object_start (ctx, &out, sizeof out);
+      dump_field_lv (ctx, &out, slot, slot, WEIGHT_STRONG);
+      dump_object_finish (ctx, &out, sizeof out);
+    }
+
+  ctx->flags = old_flags;
+  return start_offset;
+}
+
+static dump_off
+dump_obarray (struct dump_context *ctx, Lisp_Object object)
+{
+#if CHECK_STRUCTS && !defined HASH_Lisp_Obarray_XXXXXXXXXX
+# error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h."
+#endif
+  const struct Lisp_Obarray *in_oa = XOBARRAY (object);
+  struct Lisp_Obarray munged_oa = *in_oa;
+  struct Lisp_Obarray *oa = &munged_oa;
+  START_DUMP_PVEC (ctx, &oa->header, struct Lisp_Obarray, out);
+  dump_pseudovector_lisp_fields (ctx, &out->header, &oa->header);
+  DUMP_FIELD_COPY (out, oa, count);
+  DUMP_FIELD_COPY (out, oa, size_bits);
+  dump_field_fixup_later (ctx, out, oa, &oa->buckets);
+  dump_off offset = finish_dump_pvec (ctx, &out->header);
+  dump_remember_fixup_ptr_raw
+    (ctx,
+     offset + dump_offsetof (struct Lisp_Obarray, buckets),
+     dump_obarray_buckets (ctx, oa));
+  return offset;
+}
+
 static dump_off
 dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer)
 {
@@ -3031,6 +3076,8 @@ dump_vectorlike (struct dump_context *ctx,
       return dump_bool_vector(ctx, v);
     case PVEC_HASH_TABLE:
       return dump_hash_table (ctx, lv);
+    case PVEC_OBARRAY:
+      return dump_obarray (ctx, lv);
     case PVEC_BUFFER:
       return dump_buffer (ctx, XBUFFER (lv));
     case PVEC_SUBR:
diff --git a/src/print.c b/src/print.c
index e2252562915..c16573a93be 100644
--- a/src/print.c
+++ b/src/print.c
@@ -2078,6 +2078,14 @@ print_vectorlike_unreadable (Lisp_Object obj, 
Lisp_Object printcharfun,
       }
       return;
 
+    case PVEC_OBARRAY:
+      {
+       struct Lisp_Obarray *o = XOBARRAY (obj);
+       int i = sprintf (buf, "#<obarray %d/%d>", o->count, 1 << o->size_bits);
+       strout (buf, i, i, printcharfun);
+       return;
+      }
+
     /* Types handled earlier.  */
     case PVEC_NORMAL_VECTOR:
     case PVEC_RECORD:
diff --git a/test/lisp/obarray-tests.el b/test/lisp/obarray-tests.el
index dd8f1c8abd4..36c59ea4235 100644
--- a/test/lisp/obarray-tests.el
+++ b/test/lisp/obarray-tests.el
@@ -43,17 +43,14 @@
 
 (ert-deftest obarray-make-default-test ()
   (let ((table (obarray-make)))
-    (should (obarrayp table))
-    (should (eq (obarray-size table) obarray-default-size))))
+    (should (obarrayp table))))
 
 (ert-deftest obarray-make-with-size-test ()
-  ;; FIXME: Actually, `wrong-type-argument' is not the right error to signal,
-  ;; so we shouldn't enforce this misbehavior in tests!
-  (should-error (obarray-make -1) :type 'wrong-type-argument)
-  (should-error (obarray-make 0) :type 'wrong-type-argument)
+  (should-error (obarray-make 'a) :type 'wrong-type-argument)
   (let ((table (obarray-make 1)))
     (should (obarrayp table))
-    (should (eq (obarray-size table) 1))))
+    (should (obarray-object-p table))
+    (should (>= (obarray-size table) 1))))
 
 (ert-deftest obarray-get-test ()
   (let ((table (obarray-make 3)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]