]> git.eshelyaron.com Git - emacs.git/commitdiff
Minimize ‘equal’ calls in (delete x vector)
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Aug 2020 17:48:37 +0000 (10:48 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 15 Aug 2020 18:19:51 +0000 (11:19 -0700)
* src/fns.c (Fdelete): When deleting from a vector, call Fequal
only once per vector element.  This is faster when Fequal is slow,
and avoids the need to preinitialize the vector result.  Finish
when the result is exhausted, not when the input is exhausted;
the two are equivalent but the former may be faster.
* test/src/fns-tests.el (test-vector-delete): New test.

src/fns.c
test/src/fns-tests.el

index c89bd8144e7105db540ec43f858b7d5207c1f402..069edbe90e28eb243431d837ff8177835939316b 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1747,22 +1747,42 @@ changing the value of a sequence `foo'.  */)
 {
   if (VECTORP (seq))
     {
-      ptrdiff_t i, n;
+      ptrdiff_t n = 0;
+      ptrdiff_t size = ASIZE (seq);
+      ptrdiff_t neqbits_words = ((size + BITS_PER_BITS_WORD - 1)
+                                / BITS_PER_BITS_WORD);
+      USE_SAFE_ALLOCA;
+      bits_word *neqbits = SAFE_ALLOCA (neqbits_words * sizeof *neqbits);
+      bits_word neqword = 0;
 
-      for (i = n = 0; i < ASIZE (seq); ++i)
-       if (NILP (Fequal (AREF (seq, i), elt)))
-         ++n;
+      for (ptrdiff_t i = 0; i < size; i++)
+       {
+         bool neq = NILP (Fequal (AREF (seq, i), elt));
+         n += neq;
+         neqbits[i / BITS_PER_BITS_WORD] = neqword = (neqword << 1) + neq;
+       }
 
-      if (n != ASIZE (seq))
+      if (n != size)
        {
-         struct Lisp_Vector *p = allocate_nil_vector (n);
+         struct Lisp_Vector *p = allocate_vector (n);
 
-         for (i = n = 0; i < ASIZE (seq); ++i)
-           if (NILP (Fequal (AREF (seq, i), elt)))
-             p->contents[n++] = AREF (seq, i);
+         if (n != 0)
+           {
+             ptrdiff_t j = 0;
+             for (ptrdiff_t i = 0; ; i++)
+               if (neqbits[i / BITS_PER_BITS_WORD]
+                   & ((bits_word) 1 << (i % BITS_PER_BITS_WORD)))
+                 {
+                   p->contents[j++] = AREF (seq, i);
+                   if (j == n)
+                     break;
+                 }
+           }
 
          XSETVECTOR (seq, p);
        }
+
+      SAFE_FREE ();
     }
   else if (STRINGP (seq))
     {
index f1faf58659a3554d7d44b416dbccd11ddc741674..141de1d226c37b6dabc3afaaeca04880d8096147 100644 (file)
   ;; This does not test randomness; it's merely a format check.
   (should (string-match "\\`[0-9a-f]\\{128\\}\\'"
                         (secure-hash 'sha512 'iv-auto 100))))
+
+(ert-deftest test-vector-delete ()
+  (let ((v1 (make-vector 1000 1)))
+    (should (equal (delete 1 v1) (vector)))
+    (should (equal (delete 2 v1) v1))))