aboutsummaryrefslogtreecommitdiffstats
path: root/test/src/fns-tests.el
diff options
context:
space:
mode:
authorMattias EngdegÄrd2024-03-10 13:18:22 +0100
committerMattias EngdegÄrd2024-03-29 11:39:38 +0100
commit1232ab31c656b8564984a758957466f90ac10501 (patch)
tree38a7774207a5ac8dba2612bef9a6a39f3cd0d658 /test/src/fns-tests.el
parentc3684b97885c5a1f4d0713ff45c7395e9a4c6e8a (diff)
downloademacs-1232ab31c656b8564984a758957466f90ac10501.tar.gz
emacs-1232ab31c656b8564984a758957466f90ac10501.zip
Add `value<` (bug#69709)
It's a general-purpose polymorphic ordering function, like `<` but for any two values of the same type. * src/data.c (syms_of_data): Add the `type-mismatch` error. (bits_word_to_host_endian): Move... * src/lisp.h (bits_word_to_host_endian): ...here, and declare inline. * src/fns.c (Fstring_lessp): Extract the bulk of this function to... (string_cmp): ...this 3-way comparison function, for use elsewhere. (bool_vector_cmp, value_cmp, Fvaluelt): New. * lisp/emacs-lisp/byte-opt.el (side-effect-free-fns, pure-fns): Add `value<`, which is pure and side-effect-free. * test/src/fns-tests.el (fns-value<-ordered, fns-value<-unordered) (fns-value<-type-mismatch, fns-value<-symbol-with-pos) (fns-value<-circle, ert-deftest fns-value<-bool-vector): New tests. * doc/lispref/sequences.texi (Sequence Functions): * doc/lispref/numbers.texi (Comparison of Numbers): * doc/lispref/strings.texi (Text Comparison): Document the new value< function. * etc/NEWS: Announce.
Diffstat (limited to 'test/src/fns-tests.el')
-rw-r--r--test/src/fns-tests.el218
1 files changed, 218 insertions, 0 deletions
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index 7437c07f156..844000cdc76 100644
--- a/test/src/fns-tests.el
+++ b/test/src/fns-tests.el
@@ -1513,4 +1513,222 @@
1513 (should-error (copy-alist "abc") 1513 (should-error (copy-alist "abc")
1514 :type 'wrong-type-argument)) 1514 :type 'wrong-type-argument))
1515 1515
1516(ert-deftest fns-value<-ordered ()
1517 ;; values (X . Y) where X<Y
1518 (let* ((big (* 10 most-positive-fixnum))
1519 (buf1 (get-buffer-create " *one*"))
1520 (buf2 (get-buffer-create " *two*"))
1521 (buf3 (get-buffer-create " *three*"))
1522 (_ (progn (with-current-buffer buf1 (insert (make-string 20 ?a)))
1523 (with-current-buffer buf2 (insert (make-string 20 ?b)))))
1524 (mark1 (set-marker (make-marker) 12 buf1))
1525 (mark2 (set-marker (make-marker) 13 buf1))
1526 (mark3 (set-marker (make-marker) 12 buf2))
1527 (mark4 (set-marker (make-marker) 13 buf2))
1528 (proc1 (make-pipe-process :name " *proc one*"))
1529 (proc2 (make-pipe-process :name " *proc two*")))
1530 (kill-buffer buf3)
1531 (unwind-protect
1532 (dolist (c
1533 `(
1534 ;; fixnums
1535 (1 . 2) (-2 . -1) (-2 . 1) (-1 . 2)
1536 ;; bignums
1537 (,big . ,(1+ big)) (,(- big) . ,big)
1538 (,(- -1 big) . ,(- big))
1539 ;; fixnums/bignums
1540 (1 . ,big) (-1 . ,big) (,(- big) . -1) (,(- big) . 1)
1541 ;; floats
1542 (1.5 . 1.6) (-1.3 . -1.2) (-13.0 . 12.0)
1543 ;; floats/fixnums
1544 (1 . 1.1) (1.9 . 2) (-2.0 . 1) (-2 . 1.0)
1545 ;; floats/bignums
1546 (,big . ,(float (* 2 big))) (,(float big) . ,(* 2 big))
1547 ;; symbols
1548 (a . b) (nil . nix) (b . ba) (## . a) (A . a)
1549 (#:a . #:b) (a . #:b) (#:a . b)
1550 ;; strings
1551 ("" . "a") ("a" . "b") ("A" . "a") ("abc" . "abd")
1552 ("b" . "ba")
1553
1554 ;; lists
1555 ((1 2 3) . (2 3 4)) ((2) . (2 1)) (() . (0))
1556 ((1 2 3) . (1 3)) ((1 2 3) . (1 3 2))
1557 (((b a) (c d) e) . ((b a) (c d) f))
1558 (((b a) (c D) e) . ((b a) (c d) e))
1559 (((b a) (c d () x) e) . ((b a) (c d (1) x) e))
1560 ((1 . 2) . (1 . 3)) ((1 2 . 3) . (1 2 . 4))
1561
1562 ;; vectors
1563 ([1 2 3] . [2 3 4]) ([2] . [2 1]) ([] . [0])
1564 ([1 2 3] . [1 3]) ([1 2 3] . [1 3 2])
1565 ([[b a] [c d] e] . [[b a] [c d] f])
1566 ([[b a] [c D] e] . [[b a] [c d] e])
1567 ([[b a] [c d [] x] e] . [[b a] [c d [1] x] e])
1568
1569 ;; bool-vectors
1570 (,(bool-vector) . ,(bool-vector nil))
1571 (,(bool-vector nil) . ,(bool-vector t))
1572 (,(bool-vector t nil t nil) . ,(bool-vector t nil t t))
1573 (,(bool-vector t nil t) . ,(bool-vector t nil t nil))
1574
1575 ;; records
1576 (#s(a 2 3) . #s(b 3 4)) (#s(b) . #s(b a))
1577 (#s(a 2 3) . #s(a 3)) (#s(a 2 3) . #s(a 3 2))
1578 (#s(#s(b a) #s(c d) e) . #s(#s(b a) #s(c d) f))
1579 (#s(#s(b a) #s(c D) e) . #s(#s(b a) #s(c d) e))
1580 (#s(#s(b a) #s(c d #s(u) x) e)
1581 . #s(#s(b a) #s(c d #s(v) x) e))
1582
1583 ;; markers
1584 (,mark1 . ,mark2) (,mark1 . ,mark3) (,mark1 . ,mark4)
1585 (,mark2 . ,mark3) (,mark2 . ,mark4) (,mark3 . ,mark4)
1586
1587 ;; buffers
1588 (,buf1 . ,buf2) (,buf3 . ,buf1) (,buf3 . ,buf2)
1589
1590 ;; processes
1591 (,proc1 . ,proc2)
1592 ))
1593 (let ((x (car c))
1594 (y (cdr c)))
1595 (should (value< x y))
1596 (should-not (value< y x))
1597 (should-not (value< x x))
1598 (should-not (value< y y))))
1599
1600 (delete-process proc2)
1601 (delete-process proc1)
1602 (kill-buffer buf2)
1603 (kill-buffer buf1))))
1604
1605(ert-deftest fns-value<-unordered ()
1606 ;; values (X . Y) where neither X<Y nor Y<X
1607
1608 (let ((buf1 (get-buffer-create " *one*"))
1609 (buf2 (get-buffer-create " *two*")))
1610 (kill-buffer buf2)
1611 (kill-buffer buf1)
1612 (dolist (c `(
1613 ;; numbers
1614 (0 . 0.0) (0 . -0.0) (0.0 . -0.0)
1615
1616 ;; symbols
1617 (a . #:a)
1618
1619 ;; (dead) buffers
1620 (,buf1 . ,buf2)
1621
1622 ;; unordered types
1623 (,(make-hash-table) . ,(make-hash-table))
1624 (,(obarray-make) . ,(obarray-make))
1625 ;; FIXME: more?
1626 ))
1627 (let ((x (car c))
1628 (y (cdr c)))
1629 (should-not (value< x y))
1630 (should-not (value< y x))))))
1631
1632(ert-deftest fns-value<-type-mismatch ()
1633 ;; values of disjoint (incomparable) types
1634 (let ((incomparable
1635 `( 1 a "a" (a b) [a b] ,(bool-vector nil t) #s(a b)
1636 ,(make-char-table 'test)
1637 ,(make-hash-table)
1638 ,(obarray-make)
1639 ;; FIXME: more?
1640 )))
1641 (let ((tail incomparable))
1642 (while tail
1643 (let ((x (car tail)))
1644 (dolist (y (cdr tail))
1645 (should-error (value< x y) :type 'type-mismatch)
1646 (should-error (value< y x) :type 'type-mismatch)))
1647 (setq tail (cdr tail))))))
1648
1649(ert-deftest fns-value<-symbol-with-pos ()
1650 ;; values (X . Y) where X<Y
1651 (let* ((a-sp-1 (position-symbol 'a 1))
1652 (a-sp-2 (position-symbol 'a 2))
1653 (b-sp-1 (position-symbol 'b 1))
1654 (b-sp-2 (position-symbol 'b 2)))
1655
1656 (dolist (swp '(nil t))
1657 (let ((symbols-with-pos-enabled swp))
1658 ;; Enabled or not, they compare by name.
1659 (dolist (c `((,a-sp-1 . ,b-sp-1) (,a-sp-1 . ,b-sp-2)
1660 (,a-sp-2 . ,b-sp-1) (,a-sp-2 . ,b-sp-2)))
1661 (let ((x (car c))
1662 (y (cdr c)))
1663 (should (value< x y))
1664 (should-not (value< y x))
1665 (should-not (value< x x))
1666 (should-not (value< y y))))
1667 (should-not (value< a-sp-1 a-sp-2))
1668 (should-not (value< a-sp-2 a-sp-1))))
1669
1670 ;; When disabled, symbol-with-pos and symbols do not compare.
1671 (should-error (value< a-sp-1 'a) :type 'type-mismatch)
1672 (should-error (value< 'a a-sp-1) :type 'type-mismatch)
1673
1674 (let ((symbols-with-pos-enabled t))
1675 ;; When enabled, a symbol-with-pos compares as a plain symbol.
1676 (dolist (c `((,a-sp-1 . b) (a . ,b-sp-1)))
1677 (let ((x (car c))
1678 (y (cdr c)))
1679 (should (value< x y))
1680 (should-not (value< y x))
1681 (should-not (value< x x))
1682 (should-not (value< y y))))
1683 (should-not (value< a-sp-1 'a))
1684 (should-not (value< 'a a-sp-1)))))
1685
1686(ert-deftest fns-value<-circle ()
1687 ;; Check that we at least don't hang when comparing two circular lists.
1688 (let ((a (number-sequence 1 5))
1689 (b (number-sequence 1 5)))
1690 (setcdr (last a) (nthcdr 2 a))
1691 (setcdr (last b) (nthcdr 2 b))
1692 (should-error (value< a b :type 'circular))
1693 (should-error (value< b a :type 'circular))))
1694
1695(ert-deftest fns-value<-bool-vector ()
1696 ;; More thorough test of `value<' for bool-vectors.
1697 (random "my seed")
1698 (dolist (na '(0 1 5 8 9 32 63 64 65 200 1001 1024))
1699 (let ((a (make-bool-vector na nil)))
1700 (dotimes (i na)
1701 (aset a i (zerop (random 2))))
1702 (dolist (nb '(0 1 5 8 9 32 63 64 65 200 1001 1024))
1703 (when (<= nb na)
1704 (let ((b (make-bool-vector nb nil)))
1705 (dotimes (i nb)
1706 (aset b i (aref a i)))
1707 ;; `b' is now a prefix of `a'.
1708 (should-not (value< a b))
1709 (cond ((= nb na)
1710 (should (equal a b))
1711 (should-not (value< b a)))
1712 (t
1713 (should-not (equal a b))
1714 (should (value< b a))))
1715 (unless (zerop nb)
1716 ;; Flip random bits in `b' and check how it affects the order.
1717 (dotimes (_ 3)
1718 (let ((i (random nb)))
1719 (let ((val (aref b i)))
1720 (aset b i (not val))
1721 (should-not (equal a b))
1722 (cond
1723 (val
1724 ;; t -> nil: `b' is now always a proper prefix of `a'.
1725 (should-not (value< a b))
1726 (should (value< b a)))
1727 (t
1728 ;; nil -> t: `a' is now less than `b'.
1729 (should (value< a b))
1730 (should-not (value< b a))))
1731 ;; Undo the flip.
1732 (aset b i val)))))))))))
1733
1516;;; fns-tests.el ends here 1734;;; fns-tests.el ends here