@@ -897,50 +897,96 @@ BY is the function to use to move through the list (default `cdr')."
897
897
(setq , list-val (funcall , list-func , list-val )))))))
898
898
899
899
; ;;;;; Map
900
- ; ; TODO: Instead of using `seq-uniq' at the start,
901
- ; ; check as we go.
902
900
(cl-defun loopy--parse-map-command ((name var val &key (unique t )))
903
- " Parse the `map' loop command.
901
+ " Parse the `map' loop command as `(map VAR EXPR &key (unique t))' .
904
902
905
903
Iterates through an alist of (key . value) dotted pairs,
906
904
extracted from a hash-map, association list, property list, or
907
905
vector using the library `map.el' ."
908
906
(when loopy--in-sub-level
909
907
(loopy--signal-bad-iter name 'map ))
910
- (let ((value-holder (gensym " map-" )))
911
- `((loopy--iteration-vars
912
- (, value-holder ,(if unique
913
- `(seq-uniq (map-pairs , val ) #'loopy--car-equal-car )
914
- `(map-pairs , val ))))
915
- ,@(loopy--destructure-for-iteration-command var `(car , value-holder ))
916
- ; ; NOTE: The benchmarks show that `consp' is faster than no `consp' ,
908
+ ; ; Not sure if this is needed, but want to be careful since we could have been
909
+ ; ; incorrectly using pre-macro-expansion forms in the comparison.
910
+ (setq unique (macroexpand-all unique macroexpand-all-environment))
911
+ (loopy--instr-let-var* ((value-holder `(map-pairs , val )))
912
+ loopy--iteration-vars
913
+ `(; ; NOTE: The benchmarks show that `consp' is faster than no `consp' ,
917
914
; ; at least for some commands.
918
915
(loopy--pre-conditions (consp , value-holder ))
919
- (loopy--latter-body (setq , value-holder (cdr , value-holder ))))))
916
+ (loopy--latter-body (setq , value-holder (cdr , value-holder )))
917
+ ,@(cond
918
+ ((null unique)
919
+ (loopy--destructure-for-iteration-command var `(car , value-holder )))
920
+ ; ; If UNIQUE is not evaluable code and is not `nil' , then we know that
921
+ ; ; we can use `member' directly.
922
+ ((and (macroexp-const-p unique)
923
+ unique)
924
+ (loopy--instr-let-var* ((key-list nil ))
925
+ loopy--iteration-vars
926
+ (loopy--destructure-for-iteration-command
927
+ var `(progn
928
+ (while (member (caar , value-holder ) , key-list )
929
+ (setq , value-holder (cdr , value-holder )))
930
+ (push (caar , value-holder ) , key-list )
931
+ (car , value-holder )))))
932
+ (t
933
+ (loopy--instr-let-var* ((key-list nil )
934
+ (test-fn `(if , unique
935
+ #'member
936
+ #'ignore )))
937
+ loopy--iteration-vars
938
+ (loopy--destructure-for-iteration-command
939
+ var `(progn
940
+ (while (funcall , test-fn (caar , value-holder ) , key-list )
941
+ (setq , value-holder (cdr , value-holder )))
942
+ (push (caar , value-holder ) , key-list )
943
+ (car , value-holder )))))))))
920
944
921
945
; ;;;;; Map-Ref
922
946
(cl-defun loopy--parse-map-ref-command ((name var val &key key (unique t )))
923
- " Parse the `map-ref' command as (map-ref VAR VAL).
947
+ " Parse the `map-ref' command as (map-ref VAR VAL &key key (unique t) ).
924
948
925
949
KEY is a variable name in which to store the current key.
926
950
927
951
Uses `map-elt' as a `setf' -able place, iterating through the
928
952
map's keys. Duplicate keys are ignored."
929
953
(when loopy--in-sub-level
930
954
(loopy--signal-bad-iter name 'map-ref ))
931
- (let ((key-list (gensym " map-ref-keys" )))
932
- `((loopy--iteration-vars (, key-list ,(if unique
933
- `(seq-uniq (map-keys , val ))
934
- `(map-keys , val ))))
955
+ ; ; Not sure if this is needed, but want to be careful since we could have been
956
+ ; ; incorrectly using pre-macro-expansion forms in the comparison.
957
+ (setq unique (macroexpand-all unique macroexpand-all-environment))
958
+ (loopy--instr-let-var* ((key-list `(map-keys , val )))
959
+ loopy--iteration-vars
960
+ `(; ; NOTE: The benchmarks show that `consp' is faster than no `consp' ,
961
+ ; ; at least for some commands.
962
+ (loopy--pre-conditions (consp , key-list ))
963
+ (loopy--latter-body (setq , key-list (cdr , key-list )))
964
+ ,@(cond
965
+ ; ; We don't need to do anything if we don't care about uniqueness.
966
+ ((null unique) nil )
967
+ ; ; If UNIQUE is not evaluable code and is not `nil' , then we know that
968
+ ; ; we can use `member' directly.
969
+ ((and (macroexp-const-p unique)
970
+ unique)
971
+ (loopy--instr-let-var* ((found-keys nil ))
972
+ loopy--iteration-vars
973
+ `((loopy--main-body (while (member (car , key-list ) , found-keys )
974
+ (setq , key-list (cdr , key-list ))))
975
+ (loopy--main-body (push (car , key-list ) , found-keys )))))
976
+ (t
977
+ (loopy--instr-let-var* ((found-keys nil )
978
+ (test-fn `(if , unique
979
+ #'member
980
+ #'ignore )))
981
+ loopy--iteration-vars
982
+ `((loopy--main-body (while (funcall , test-fn (car , key-list ) , found-keys )
983
+ (setq , key-list (cdr , key-list ))))
984
+ (loopy--main-body (push (car , key-list ) , found-keys ))))))
935
985
,@(when key
936
986
`((loopy--iteration-vars (, key nil ))
937
987
(loopy--main-body (setq , key (car , key-list )))))
938
988
,@(loopy--destructure-for-generalized-command
939
- var `(map-elt , val ,(or key `(car , key-list ))))
940
- ; ; NOTE: The benchmarks show that `consp' is faster than no `consp' ,
941
- ; ; at least for some commands.
942
- (loopy--pre-conditions (consp , key-list ))
943
- (loopy--latter-body (setq , key-list (cdr , key-list ))))))
989
+ var `(map-elt , val ,(or key `(car , key-list )))))))
944
990
945
991
; ;;;;; Numbers
946
992
0 commit comments