! Copyright (C) 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: sequences-internals USING: errors generic kernel kernel-internals lists math sequences strings vectors words ; : (lexi) ( seq seq i limit -- n ) 2dup >= [ 2drop swap length swap length - ] [ >r 3dup 2nth-unsafe 2dup = [ 2drop 1 + r> (lexi) ] [ r> drop - >r 3drop r> ] ifte ] ifte ; flushable IN: sequences M: object like drop ; M: object empty? ( seq -- ? ) length 0 = ; : (>list) ( n i seq -- list ) pick pick <= [ 3drop [ ] ] [ 2dup nth >r >r 1 + r> (>list) r> swons ] ifte ; M: object >list ( seq -- list ) dup length 0 rot (>list) ; : index ( obj seq -- n ) [ = ] find-with drop ; flushable : index* ( obj i seq -- n ) [ = ] find-with* drop ; flushable : member? ( obj seq -- ? ) [ = ] contains-with? ; flushable : memq? ( obj seq -- ? ) [ eq? ] contains-with? ; flushable : remove ( obj list -- list ) [ = not ] subset-with ; flushable : copy-into-check ( start to from -- ) rot rot length + swap length < [ "Cannot copy beyond end of sequence" throw ] when ; : copy-into ( start to from -- ) 3dup copy-into-check dup length [ >r pick r> + pick set-nth-unsafe ] 2each 2drop ; : nappend ( to from -- ) >r dup length swap r> over length over length + pick set-length copy-into ; : append ( s1 s2 -- s1+s2 ) #! Outputs a new sequence of the same type as s1. swap [ swap nappend ] immutable ; flushable : add ( seq elt -- seq ) #! Outputs a new sequence of the same type as seq. swap [ push ] immutable ; flushable : append3 ( s1 s2 s3 -- s1+s2+s3 ) #! Return a new sequence of the same type as s1. rot [ [ rot nappend ] keep swap nappend ] immutable ; flushable : concat ( seq -- seq ) #! Append a sequence of sequences together. The new sequence #! has the same type as the first sequence. dup empty? [ [ 1024 swap [ dupd nappend ] each ] keep first like ] unless ; flushable M: object peek ( sequence -- element ) #! Get value at end of sequence. dup length 1 - swap nth ; : pop ( sequence -- element ) #! Get value at end of sequence and remove it. dup peek >r dup length 1 - swap set-length r> ; : push-new ( elt seq -- ) 2dup member? [ 2drop ] [ push ] ifte ; : prune ( seq -- seq ) [ dup length swap [ over push-new ] each ] keep like ; flushable : >pop> ( stack -- stack ) dup pop drop ; : join ( seq glue -- seq ) #! The new sequence is of the same type as glue. swap dup empty? [ swap like ] [ dup length swap [ over push 2dup push ] each nip >pop> concat ] ifte ; flushable M: object reverse-slice ( seq -- seq ) ; M: object reverse ( seq -- seq ) [ ] keep like ; ! Set theoretic operations : seq-intersect ( seq1 seq2 -- seq1/\seq2 ) [ swap member? ] subset-with ; flushable : seq-diff ( seq1 seq2 -- seq2-seq1 ) [ swap member? not ] subset-with ; flushable : seq-union ( seq1 seq2 -- seq1\/seq2 ) append prune ; flushable : contained? ( seq1 seq2 -- ? ) #! Is every element of seq1 in seq2 swap [ swap member? ] all-with? ; flushable ! Lexicographic comparison : lexi ( s1 s2 -- n ) #! Lexicographically compare two sequences of numbers #! (usually strings). Negative if s1s2. 0 pick pick min-length (lexi) ; flushable : flip ( seq -- seq ) #! An example illustrates this word best: #! { { 1 2 3 } { 4 5 6 } } ==> { { 1 4 } { 2 5 } { 3 6 } } dup empty? [ dup first length [ swap [ nth ] map-with ] map-with ] unless ; flushable : max-length ( seq -- n ) #! Longest sequence length in a sequence of sequences. 0 [ length max ] reduce ; flushable IN: kernel : depth ( -- n ) #! Push the number of elements on the datastack. datastack length ; : no-cond "cond fall-through" throw ; inline : cond ( conditions -- ) #! Conditions is a sequence of quotation pairs. #! { { [ X ] [ Y ] } { [ Z ] [ T ] } } #! => X [ Y ] [ Z [ T ] [ ] ifte ] ifte #! The last condition should be a catch-all 't'. [ first call ] find nip dup [ second call ] [ no-cond ] ifte ; : with-datastack ( stack word -- stack ) datastack >r >r set-datastack r> execute datastack r> [ push ] keep set-datastack 2nip ;