Add new predicates for sequence lengths
* doc/lispref/sequences.texi (Sequence Functions): Document them. * lisp/emacs-lisp/byte-opt.el (side-effect-free-fns): Mark them as side-effect-free. * lisp/emacs-lisp/shortdoc.el (list): Mention them. * src/fns.c (Flength): Mention them in the doc string. (length_internal): New function. (Flength_less, Flength_greater, Flength_equal): New defuns. (syms_of_fns): Sym them.
This commit is contained in:
parent
714ca849ba
commit
0f790464d5
6 changed files with 135 additions and 2 deletions
|
@ -116,6 +116,21 @@ If you need to compute the width of a string on display, you should use
|
|||
since @code{length} only counts the number of characters, but does not
|
||||
account for the display width of each character.
|
||||
|
||||
@defun length< sequence length
|
||||
Return non-@code{nil} if @var{sequence} is shorter than @var{length}.
|
||||
This may be more efficient than computing the length of @var{sequence}
|
||||
if @var{sequence} is a long list.
|
||||
@end defun
|
||||
|
||||
@defun length> sequence length
|
||||
Return non-@code{nil} if @var{sequence} is longer than @var{length}.
|
||||
@end defun
|
||||
|
||||
@defun length= sequence length
|
||||
Return non-@code{nil} if the length of @var{sequence} is equal to
|
||||
@var{length}.
|
||||
@end defun
|
||||
|
||||
@defun elt sequence index
|
||||
@anchor{Definition of elt}
|
||||
@cindex elements of sequences
|
||||
|
|
6
etc/NEWS
6
etc/NEWS
|
@ -1460,6 +1460,12 @@ that makes it a valid button.
|
|||
|
||||
** Miscellaneous
|
||||
|
||||
+++
|
||||
*** New predicate functions 'length<', 'length>' and 'length='.
|
||||
Using these functions may be more efficient than using 'length' (if
|
||||
the length of a (long) list is being computed just to compare this
|
||||
length to a number).
|
||||
|
||||
---
|
||||
*** 'remove-hook' is now an interactive command.
|
||||
|
||||
|
|
|
@ -1169,7 +1169,9 @@
|
|||
hash-table-count
|
||||
int-to-string intern-soft isnan
|
||||
keymap-parent
|
||||
lax-plist-get ldexp length line-beginning-position line-end-position
|
||||
lax-plist-get ldexp
|
||||
length length< length> length=
|
||||
line-beginning-position line-end-position
|
||||
local-variable-if-set-p local-variable-p locale-info
|
||||
log log10 logand logb logcount logior lognot logxor lsh
|
||||
make-byte-code make-list make-string make-symbol marker-buffer max
|
||||
|
|
|
@ -618,6 +618,12 @@ There can be any number of :example/:result elements."
|
|||
"Data About Lists"
|
||||
(length
|
||||
:eval (length '(a b c)))
|
||||
(length<
|
||||
:eval (lenth< '(a b c) 1))
|
||||
(length>
|
||||
:eval (lenth> '(a b c) 1))
|
||||
(length=
|
||||
:eval (lenth> '(a b c) 3))
|
||||
(safe-length
|
||||
:eval (safe-length '(a b c))))
|
||||
|
||||
|
|
76
src/fns.c
76
src/fns.c
|
@ -105,9 +105,14 @@ list_length (Lisp_Object list)
|
|||
DEFUN ("length", Flength, Slength, 1, 1, 0,
|
||||
doc: /* Return the length of vector, list or string SEQUENCE.
|
||||
A byte-code function object is also allowed.
|
||||
|
||||
If the string contains multibyte characters, this is not necessarily
|
||||
the number of bytes in the string; it is the number of characters.
|
||||
To get the number of bytes, use `string-bytes'. */)
|
||||
To get the number of bytes, use `string-bytes'.
|
||||
|
||||
If the length of a list is being computed to compare to a (small)
|
||||
number, the `string<', `string>' and `string=' functions may be more
|
||||
efficient. */)
|
||||
(Lisp_Object sequence)
|
||||
{
|
||||
EMACS_INT val;
|
||||
|
@ -145,6 +150,72 @@ least the number of distinct elements. */)
|
|||
return make_fixnum (len);
|
||||
}
|
||||
|
||||
static inline
|
||||
EMACS_INT length_internal (Lisp_Object sequence, int len)
|
||||
{
|
||||
/* If LENGTH is short (arbitrarily chosen cut-off point), use a
|
||||
fast loop that doesn't care about whether SEQUENCE is
|
||||
circular or not. */
|
||||
if (len < 0xffff)
|
||||
while (CONSP (sequence))
|
||||
{
|
||||
if (--len == 0)
|
||||
return -1;
|
||||
sequence = XCDR (sequence);
|
||||
}
|
||||
/* Signal an error on circular lists. */
|
||||
else
|
||||
FOR_EACH_TAIL (sequence)
|
||||
if (--len == 0)
|
||||
return -1;
|
||||
return len;
|
||||
}
|
||||
|
||||
DEFUN ("length<", Flength_less, Slength_less, 2, 2, 0,
|
||||
doc: /* Return non-nil if SEQUENCE is shorter than LENGTH.
|
||||
See `length' for allowed values of SEQUENCE and how elements are
|
||||
counted. */)
|
||||
(Lisp_Object sequence, Lisp_Object length)
|
||||
{
|
||||
CHECK_FIXNUM (length);
|
||||
EMACS_INT len = XFIXNUM (length);
|
||||
|
||||
if (CONSP (sequence))
|
||||
return length_internal (sequence, len) == -1? Qnil: Qt;
|
||||
else
|
||||
return XFIXNUM (Flength (sequence)) < len? Qt: Qnil;
|
||||
}
|
||||
|
||||
DEFUN ("length>", Flength_greater, Slength_greater, 2, 2, 0,
|
||||
doc: /* Return non-nil if SEQUENCE is longer than LENGTH.
|
||||
See `length' for allowed values of SEQUENCE and how elements are
|
||||
counted. */)
|
||||
(Lisp_Object sequence, Lisp_Object length)
|
||||
{
|
||||
CHECK_FIXNUM (length);
|
||||
EMACS_INT len = XFIXNUM (length);
|
||||
|
||||
if (CONSP (sequence))
|
||||
return length_internal (sequence, len + 1) == -1? Qt: Qnil;
|
||||
else
|
||||
return XFIXNUM (Flength (sequence)) > len? Qt: Qnil;
|
||||
}
|
||||
|
||||
DEFUN ("length=", Flength_equal, Slength_equal, 2, 2, 0,
|
||||
doc: /* Return non-nil if SEQUENCE is equal to LENGTH.
|
||||
See `length' for allowed values of SEQUENCE and how elements are
|
||||
counted. */)
|
||||
(Lisp_Object sequence, Lisp_Object length)
|
||||
{
|
||||
CHECK_FIXNUM (length);
|
||||
EMACS_INT len = XFIXNUM (length);
|
||||
|
||||
if (CONSP (sequence))
|
||||
return length_internal (sequence, len + 1) == 1? Qt: Qnil;
|
||||
else
|
||||
return XFIXNUM (Flength (sequence)) == len? Qt: Qnil;
|
||||
}
|
||||
|
||||
DEFUN ("proper-list-p", Fproper_list_p, Sproper_list_p, 1, 1, 0,
|
||||
doc: /* Return OBJECT's length if it is a proper list, nil otherwise.
|
||||
A proper list is neither circular nor dotted (i.e., its last cdr is nil). */
|
||||
|
@ -5721,6 +5792,9 @@ this variable. */);
|
|||
defsubr (&Srandom);
|
||||
defsubr (&Slength);
|
||||
defsubr (&Ssafe_length);
|
||||
defsubr (&Slength_less);
|
||||
defsubr (&Slength_greater);
|
||||
defsubr (&Slength_equal);
|
||||
defsubr (&Sproper_list_p);
|
||||
defsubr (&Sstring_bytes);
|
||||
defsubr (&Sstring_distance);
|
||||
|
|
|
@ -999,3 +999,33 @@
|
|||
(object-intervals (current-buffer)))
|
||||
'((0 1 (foo 1)) (1 2 (zot 3 foo 1)) (2 4 (zot 3 bar 2))
|
||||
(4 5 (bar 2)) (5 6 nil)))))
|
||||
|
||||
(ert-deftest length-equals-tests ()
|
||||
(should-not (length< (list 1 2 3) 2))
|
||||
(should-not (length< (list 1 2 3) 3))
|
||||
(should (length< (list 1 2 3) 4))
|
||||
|
||||
(should-not (length< "abc" 2))
|
||||
(should-not (length< "abc" 3))
|
||||
(should (length< "abc" 4))
|
||||
|
||||
(should (length> (list 1 2 3) 2))
|
||||
(should-not (length> (list 1 2 3) 3))
|
||||
(should-not (length> (list 1 2 3) 4))
|
||||
|
||||
(should (length> "abc" 2))
|
||||
(should-not (length> "abc" 3))
|
||||
(should-not (length> "abc" 4))
|
||||
|
||||
(should-not (length= (list 1 2 3) 2))
|
||||
(should (length= (list 1 2 3) 3))
|
||||
(should-not (length= (list 1 2 3) 4))
|
||||
|
||||
(should-not (length= "abc" 2))
|
||||
(should (length= "abc" 3))
|
||||
(should-not (length= "abc" 4))
|
||||
|
||||
(should-error
|
||||
(let ((list (list 1)))
|
||||
(setcdr list list)
|
||||
(length< list #x1fffe))))
|
||||
|
|
Loading…
Add table
Reference in a new issue