[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/dict-tree 5cf96da 123/154: Implement iterator generator
From: |
Stefan Monnier |
Subject: |
[elpa] externals/dict-tree 5cf96da 123/154: Implement iterator generators on collection data structures. |
Date: |
Mon, 14 Dec 2020 12:21:58 -0500 (EST) |
branch: externals/dict-tree
commit 5cf96da28c4adc7cfdeb7bf15ff68826564734ed
Author: Toby S. Cubitt <toby-predictive@dr-qubit.org>
Commit: Toby S. Cubitt <toby-predictive@dr-qubit.org>
Implement iterator generators on collection data structures.
---
dict-tree.el | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 218 insertions(+), 16 deletions(-)
diff --git a/dict-tree.el b/dict-tree.el
index 03e881d..7b91fea 100644
--- a/dict-tree.el
+++ b/dict-tree.el
@@ -267,6 +267,43 @@ If START or END is negative, it counts from the end."
(setq b (cons (caar b) (dictree--cell-data (cdr b)))))
(,rankfun a b))))
+;; return wrapped sortfun to ignore regexp grouping data
+(trie--if-lexical-binding
+ (defun dictree--wrap-regexp-sortfun (cmpfun &optional reverse)
+ (let ((sortfun (trie-construct-sortfun cmpfun reverse)))
+ (lambda (a b)
+ ;; if car of argument contains a key+group list rather than a
+ ;; straight key, remove group list
+ ;; FIXME: the test for straight key, below, will fail if the key
+ ;; is a list, and the first element of the key is itself a
+ ;; list (there might be no easy way to fully fix this...)
+ (if (or (atom (car a))
+ (and (listp (car a)) (not (sequencep (caar a)))))
+ (setq a (car a))
+ (setq a (caar a)))
+ (if (or (atom (car b))
+ (and (listp (car b)) (not (sequencep (caar b)))))
+ (setq b (car b))
+ (setq b (caar b)))
+ (funcall sortfun a b))))
+ (defun dictree--wrap-regexp-sortfun (cmpfun &optional reverse)
+ (let ((sortfun (trie-construct-sortfun cmpfun reverse)))
+ `(lambda (a b)
+ ;; if car of argument contains a key+group list rather than a
+ ;; straight key, remove group list
+ ;; FIXME: the test for straight key, below, will fail if the key
+ ;; is a list, and the first element of the key is itself a
+ ;; list (there might be no easy way to fully fix this...)
+ (if (or (atom (car a))
+ (and (listp (car a)) (not (sequencep (caar a)))))
+ (setq a (car a))
+ (setq a (caar a)))
+ (if (or (atom (car b))
+ (and (listp (car b)) (not (sequencep (caar b)))))
+ (setq b (car b))
+ (setq b (caar b)))
+ (,sortfun a b)))))
+
;; return wrapped rankfun to ignore fuzzy query distance data
(trie--if-lexical-binding
@@ -280,6 +317,15 @@ If START or END is negative, it counts from the end."
(,rankfun (cons (nth 0 (car a)) (dictree--cell-data (cdr a)))
(cons (nth 0 (car b)) (dictree--cell-data (cdr b)))))))
+;; return wrapped sortfun to ignore fuzzy query distance data
+(trie--if-lexical-binding
+ (defun dictree--wrap-fuzzy-sortfun (cmpfun &optional reverse)
+ (let ((sortfun (trie-construct-sortfun cmpfun reverse)))
+ (lambda (a b) (funcall sortfun (car a) (car b)))))
+ (defun dictree--wrap-fuzzy-sortfun (cmpfun &optional reverse)
+ (let ((sortfun (trie-construct-sortfun cmpfun reverse)))
+ `(lambda (a b) (,sortfun (car a) (car b))))))
+
;; return wrapped combfun to deal with data wrapping
(trie--if-lexical-binding
@@ -430,8 +476,9 @@ If START or END is negative, it counts from the end."
(dictionary-list
&optional
filename
- (name (file-name-sans-extension
- (file-name-nondirectory filename)))
+ (name (when filename
+ (file-name-sans-extension
+ (file-name-nondirectory filename))))
autosave
_unlisted
(combine-function #'+)
@@ -470,15 +517,13 @@ If START or END is negative, it counts from the end."
;; Return a list of all the tries on which DICT is based. If DICT is a
;; meta-dict, this recursively descends the hierarchy, gathering all
;; the tries from the base dictionaries.
- (let (accumulate)
- (dictree--do-trielist dict)
- accumulate))
+ (dictree--do-trielist dict))
(defun dictree--do-trielist (dict)
- (declare (special accumulate))
(if (dictree-meta-dict-p dict)
- (mapc #'dictree--do-trielist (dictree--meta-dict-dictlist dict))
- (setq accumulate (cons (dictree--trie dict) accumulate))))
+ (apply #'nconc (mapcar #'dictree--do-trielist
+ (dictree--meta-dict-dictlist dict)))
+ (list (dictree--trie dict))))
(defun dictree--merge (list1 list2 cmpfun &optional combfun maxnum)
@@ -1950,8 +1995,8 @@ Interactively, DICT is read from the mini-buffer."
&aux
(combfun (dictree--wrap-combfun
(dictree--meta-dict-combine-function dict)))
- (sortfun (trie-construct-sortfun
- (dictree-comparison-function dict)))
+ (sortfun (dictree--wrap-regexp-sortfun
+ (dictree-comparison-function dict) 'reverse))
(heap (heap-create
(dictree--construct-meta-stack-heapfun
sortfun reverse)
@@ -1969,7 +2014,7 @@ Interactively, DICT is read from the mini-buffer."
&aux
(combfun (dictree--wrap-combfun
(dictree--meta-dict-combine-function dict)))
- (sortfun (trie-construct-sortfun
+ (sortfun (dictree--wrap-fuzzy-sortfun
(dictree-comparison-function dict)))
(heap (heap-create
(dictree--construct-meta-stack-heapfun
@@ -1988,7 +2033,7 @@ Interactively, DICT is read from the mini-buffer."
&aux
(combfun (dictree--wrap-combfun
(dictree--meta-dict-combine-function dict)))
- (sortfun (trie-construct-sortfun
+ (sortfun (dictree--wrap-fuzzy-sortfun
(dictree-comparison-function dict)))
(heap (heap-create
(dictree--construct-meta-stack-heapfun
@@ -2056,10 +2101,10 @@ element (a key and its associated data) from the stack.
PREFIX must be a sequence (vector, list or string) that forms the
initial part of a DICT key. (If PREFIX is a string, it must be
possible to apply `string' to individual elements of DICT keys.)
-The completions returned in the alist will be sequences of the
-same type as KEY. If PREFIX is a list of sequences, completions
-of all sequences in the list are included in the stack. All
-sequences in the list must be of the same type.
+The returned keys will be sequences of the same type as
+PREFIX. If PREFIX is a list of sequences, completions of all
+sequences in the list are included in the stack. All sequences in
+the list must be of the same type.
Note that any modification to DICT *immediately* invalidates all
dictree-stacks created before the modification (in particular,
@@ -2304,6 +2349,163 @@ Returns nil if the stack is empty."
;; ----------------------------------------------------------------
+;; dictree iterator generators
+
+;; dictree-stacks *are* iterators (with additional push and
+;; inspect-first-element operations). If we're running on a modern Emacs that
+;; includes the `generator' library, we can trivially define dictree iterator
+;; generators in terms of dictree-stacks.
+
+(heap--when-generators
+ (iter-defun dictree-iter (dict &optional type reverse)
+ "Return a dictree iterator object.
+
+Calling `iter-next' on this object will retrieve the next
+element (a cons cell containing a key and its associated data)
+from DICT in \"lexicographic\" order, i.e. the order defined by
+the DICT's comparison function, or in reverse order if REVERSE is
+non-nil.
+
+Optional argument TYPE (one of the symbols `vector', `list' or
+`string') sets the type of sequence used for the keys.
+
+Note that any modification to DICT *immediately* invalidates all
+iterators created from DICT before the modification (in
+particular, calling `iter-next' will give unpredictable
+results). If DICT is a meta-dict, this includes any modifications
+to its constituent dicts."
+ (let ((stack (dictree-stack dict type reverse)))
+ (while (not (dictree-stack-empty-p stack))
+ (iter-yield (dictree-stack-pop stack))))))
+
+
+(heap--when-generators
+ (iter-defun dictree-complete-iter (dict prefix &optional reverse)
+ "Return an iterator object for completions of PREFIX in DICT.
+
+Calling `iter-next' on this object will retrieve the next
+completion of PREFIX (a cons cell containing a key and its
+associated data) from DICT in \"lexicographic\" order, i.e. the
+order defined by DICT's comparison function, or in reverse order
+if REVERSE is non-nil.
+
+PREFIX must be a sequence (vector, list or string) that forms the
+initial part of a DICT key. (If PREFIX is a string, it must be
+possible to apply `string' to individual elements of DICT keys.)
+The returned keys will be sequences of the same type as
+PREFIX. If PREFIX is a list of sequences, completions of all
+sequences in the list are included in the stack. All sequences in
+the list must be of the same type.
+
+Note that any modification to DICT *immediately* invalidates all
+iterators created from DICT before the modification (in
+particular, calling `iter-next' will give unpredictable
+results). If DICT is a meta-dict, this includes any modifications
+to its constituent dicts."
+ (let ((stack (dictree-complete-stack dict prefix reverse)))
+ (while (not (dictree-stack-empty-p stack))
+ (iter-yield (dictree-stack-pop stack))))))
+
+
+(heap--when-generators
+ (iter-defun dictree-regexp-iter (dict regexp &optional reverse)
+ "Return an iterator object for REGEXP matches in DICT.
+
+Calling `iter-next' on this object will retrieve the next match
+\(a cons cell containing a key and its associated data\) in
+\"lexicographic\" order, i.e. the order defined by DICT's
+comparison function, or in reverse order if REVERSE is non-nil.
+
+REGEXP is a regular expression, but it need not necessarily be a
+string. It must be a sequence (vector, list of string) whose
+elements are either elements of the same type as elements of the
+keys in DICT (which behave as literals in the regexp), or any of
+the usual regexp special characters and backslash constructs. If
+REGEXP is a string, it must be possible to apply `string' to
+individual elements of the keys stored in DICT. The matches
+returned in the alist will be sequences of the same type as KEY.
+
+Back-references and non-greedy postfix operators are *not*
+supported, and the matches are always anchored, so `$' and `^'
+lose their special meanings.
+
+If the regexp contains any non-shy grouping constructs, subgroup
+match data is included in the results. In this case, the car of
+each match is no longer just a key. Instead, it is a list whose
+first element is the matching key, and whose remaining elements
+are cons cells whose cars and cdrs give the start and end indices
+of the elements that matched the corresponding groups, in order.
+
+Note that any modification to DICT *immediately* invalidates all
+iterators created from DICT before the modification (in
+particular, calling `iter-next' will give unpredictable
+results). If DICT is a meta-dict, this includes any modifications
+to its constituent dicts."
+ (let ((stack (dictree-regexp-stack dict regexp reverse)))
+ (while (not (dictree-stack-empty-p stack))
+ (iter-yield (dictree-stack-pop stack))))))
+
+(heap--when-generators
+ (iter-defun dictree-fuzzy-match-iter (dict string distance &optional reverse)
+ "Return an iterator object for fuzzy matches to STRING in DICT.
+
+Calling `iter-next' on this object will retrieve the next match
+\(a cons cell containing a key and its associated data\) in
+\"lexicographic\" order, i.e. the order defined by DICT's
+comparison function, or in reverse order if REVERSE is non-nil.
+
+STRING must be a sequence (vector, list or string), and DISTANCE
+must be an integer. (If STRING is a string, it must be possible
+to apply `string' to individual elements of DICT keys.) The
+returned keys will be sequences of the same type as STRING that
+are within Lewenstein distance DISTANCE of STRING. If STRING is a
+list of sequences, keys withing DISTANCE of any sequences in the
+list are included in the stack. All sequences in the list must be
+of the same type.
+
+Note that any modification to DICT *immediately* invalidates all
+iterators created from DICT before the modification (in
+particular, calling `iter-next' will give unpredictable
+results). If DICT is a meta-dict, this includes any modifications
+to its constituent dicts."
+ (let ((stack (dictree-fuzzy-match-stack dict string distance reverse)))
+ (while (not (dictree-stack-empty-p stack))
+ (iter-yield (dictree-stack-pop stack))))))
+
+
+(heap--when-generators
+ (iter-defun dictree-fuzzy-complete-iter (dict prefix distance &optional
reverse)
+ "Return an iterator object for fuzzy completions of PREFIX in DICT.
+
+Calling `iter-next' on this object will retrieve the next fuzzy
+completion in \"lexicographic\" order, i.e. the order defined by
+DICT's comparison function, or in reverse order if REVERSE is
+non-nil. Each returned element has the form:
+
+ ((KEY . DIST) . DATA)
+
+PREFIX must be a sequence (vector, list or string), and DISTANCE
+must be an integer. (If PREFIX is a string, it must be possible
+to apply `string' to individual elements of DICT keys.) The
+returned keys will be sequences of the same type as STRING that
+are completions of prefixes within Lewenstein distance DISTANCE
+of PREFIX. If PREFIX is a list of sequences, completions within
+DISTANCE of any prefix in the list are included in the stack. All
+sequences in the list must be of the same type.
+
+Note that any modification to DICT *immediately* invalidates all
+iterators created from DICT before the modification (in
+particular, calling `iter-next' will give unpredictable
+results). If DICT is a meta-dict, this includes any modifications
+to its constituent dicts."
+ (let ((stack (dictree-fuzzy-complete-stack dict prefix distance reverse)))
+ (while (not (dictree-stack-empty-p stack))
+ (iter-yield (dictree-stack-pop stack))))))
+
+
+
+
+;; ----------------------------------------------------------------
;; Functions for building advanced queries
(defun dictree--query
- [elpa] externals/dict-tree a1bff31 096/154: Trivial whitespace tidying., (continued)
- [elpa] externals/dict-tree a1bff31 096/154: Trivial whitespace tidying., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree e752b53 101/154: Accept symbols for dictionary arguments., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 8aa6047 106/154: Suppress bogus unused lexical variable byte-compiler warnings., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 4b3cc3c 122/154: Do lexbind test at compile-time instead of load-time., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree a4b2a1b 126/154: Improve edebug pretty-printing., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree b7173e8 152/154: Fix lexical binding bugs., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 3a4d3f1 015/154: Added dictree-mapcar function; code tidying., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 1dde6e1 030/154: Define missing setf methods for data cells, Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 3969702 125/154: Tidy up unnecessary macros by making them into defsubst or defun., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 74c792c 111/154: Add page breaks., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 5cf96da 123/154: Implement iterator generators on collection data structures.,
Stefan Monnier <=
- [elpa] externals/dict-tree 913c84b 129/154: Fix bug in dictree-unload., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 1e5b3f6 130/154: Fix bug in dictree--wrap-fuzzy-rankfun wrapping., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 6544152 139/154: Fix bug causing dictree--do-query to fail to use cached results., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 9242ff7 154/154: * dict-tree/dict-tree.el: Fix typo in Package-Requires., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 1d096b1 141/154: Myriad bug fixes and code refactoring in new fuzzy and ngram completion., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 572c746 149/154: Fix byte-compilation errors and warnings., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 3ddde93 143/154: Switch to keyword arguments for trie/dictree query functions., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 1030ae2 071/154: Require advice when compiling, Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 7a51b21 083/154: Fixed dictree--update-cache to work for lists of prefixes., Stefan Monnier, 2020/12/14
- [elpa] externals/dict-tree 50ae73e 085/154: Fixed bug in Read-Dict preventing completion on dict files in load-path., Stefan Monnier, 2020/12/14