! Copyright (C) 2008, 2023 Slava Pestov and Raghu Ranganathan. ! See https://factorcode.org/license.txt for BSD license. USING: arrays math kernel accessors sequences sequences.private deques search-deques hashtables ; IN: unrolled-lists CONSTANT: unroll-factor 32 TUPLE: unrolled-list { front ?node } { front-pos fixnum } { back ?node } { back-pos fixnum } ; : ( -- list ) unrolled-list new unroll-factor >>back-pos ; inline : ( -- search-deque ) 20 ; ERROR: empty-unrolled-list list ; > ] [ back>> ] bi dup [ eq? [ [ front-pos>> ] [ back-pos>> ] bi eq? ] [ drop f ] if ] [ 3drop t ] if ; M: unrolled-list clear-deque f >>front 0 >>front-pos f >>back unroll-factor >>back-pos drop ; : ( elt front -- node ) [ unroll-factor 0 [ unroll-factor 1 - swap set-nth ] keep f ] dip [ node boa dup ] keep [ prev<< ] [ drop ] if* ; inline : normalize-back ( list -- ) dup back>> [ dup prev>> [ drop ] [ swap front>> >>prev ] if ] [ dup front>> >>back ] if* drop ; inline : clear-if-empty ( list -- ) dup deque-empty? [ dup clear-deque ] when drop ; : push-front/new ( elt list -- ) unroll-factor 1 - >>front-pos [ ] change-front normalize-back ; inline : push-front/existing ( elt list front -- ) [ [ 1 - ] change-front-pos ] dip [ front-pos>> ] [ data>> ] bi* set-nth-unsafe ; inline M: unrolled-list push-front* dup [ front>> ] [ front-pos>> 0 eq? not ] bi [ drop ] [ and ] 2bi [ push-front/existing ] [ drop push-front/new ] if f ; M: unrolled-list peek-front* dup front>> [ [ front-pos>> ] dip data>> nth-unsafe t ] [ drop f f ] if* ; : pop-front/new ( list front -- ) [ 0 >>front-pos ] dip [ f ] change-next drop dup [ f >>prev ] when >>front dup front>> [ normalize-back ] [ f >>back drop ] if ; inline : pop-front/existing ( list front -- ) [ dup front-pos>> ] [ data>> ] bi* [ 0 ] 2dip set-nth-unsafe [ 1 + ] change-front-pos clear-if-empty ; inline M: unrolled-list pop-front* dup front>> [ empty-unrolled-list ] unless* over front-pos>> unroll-factor 1 - eq? [ pop-front/new ] [ pop-front/existing ] if ; : ( elt back -- node ) [ unroll-factor 0 [ set-first ] keep ] dip [ f node boa dup ] keep [ next<< ] [ drop ] if* ; inline : normalize-front ( list -- ) dup front>> [ dup next>> [ drop ] [ swap back>> >>next ] if ] [ dup back>> >>front ] if* drop ; inline : push-back/new ( elt list -- ) 1 >>back-pos [ ] change-back normalize-front ; inline : push-back/existing ( elt list back -- ) [ [ 1 + ] change-back-pos ] dip [ back-pos>> 1 - ] [ data>> ] bi* set-nth-unsafe ; inline M: unrolled-list push-back* dup [ back>> ] [ back-pos>> unroll-factor eq? not ] bi [ drop ] [ and ] 2bi [ push-back/existing ] [ drop push-back/new ] if f ; M: unrolled-list peek-back* dup back>> [ [ back-pos>> 1 - ] dip data>> nth-unsafe t ] [ drop f f ] if* ; : pop-back/new ( list back -- ) [ unroll-factor >>back-pos ] dip [ f ] change-prev drop dup [ f >>next ] when >>back dup back>> [ normalize-front ] [ f >>front drop ] if ; inline : pop-back/existing ( list back -- ) [ [ 1 - ] change-back-pos ] dip [ dup back-pos>> ] [ data>> ] bi* [ 0 ] 2dip set-nth-unsafe clear-if-empty ; inline M: unrolled-list pop-back* dup back>> [ empty-unrolled-list ] unless* over back-pos>> 1 eq? [ pop-back/new ] [ pop-back/existing ] if ; PRIVATE> INSTANCE: unrolled-list deque