diff --git a/collects/data/interval-map.rkt b/collects/data/interval-map.rkt index 64b242e008..e91bb0463c 100644 --- a/collects/data/interval-map.rkt +++ b/collects/data/interval-map.rkt @@ -3,37 +3,22 @@ (require racket/contract racket/promise racket/dict - data/skip-list) + data/splay-tree) -;; NOTE-1 -;; I need to be able to split intervals. So I can either have -;; closed intervals on the integers or half-open intervals of -;; arbitrary total orders. I'm going to do half-open intervals. +;; Interval-maps support only half-open exact-integer intervals. -;; An interval-map is (make-interval-map skip-list =? (cons End Value) +;; An interval-map is (interval-map adj-splay-tree) +;; splay-tree maps Start => (cons End-Start Value) ;; Invariant: intervals are disjoint (but the end of one interval ;; can be the same as the start of the next, since half-open). -(define make-interval-map* - (let ([make-interval-map - (lambda (=? =? s start)]) - (let ([ixstart (and ix (skip-list-iterate-key s ix))]) - (cond [(and ix (=? s start)]) + (let ([ixstart (and ix (splay-tree-iterate-key s ix))]) + (cond [(and ix (< ixstart end)) ;; First do leading gap, [ start, key(ix) ) - (when (=? s start)]) - (when ix - (let ([ixstart (skip-list-iterate-key s ix)]) - (when ( make-interval-map-iter] + (cond [(splay-tree-iterate-first (interval-map-s im)) + => interval-map-iter] [else #f])) (define (interval-map-iterate-next im iter) - (cond [(skip-list-iterate-next (interval-map-s im) + (cond [(splay-tree-iterate-next (interval-map-s im) (interval-map-iter-si iter)) - => make-interval-map-iter] + => interval-map-iter] [else #f])) (define (interval-map-iterate-key im iter) (let ([s (interval-map-s im)] [is (interval-map-iter-si iter)]) - (cons (skip-list-iterate-key s is) - (car (skip-list-iterate-value s is))))) + (let ([key (splay-tree-iterate-key s is)]) + (cons key (+ key (car (splay-tree-iterate-value s is))))))) (define (interval-map-iterate-value im iter) (let ([s (interval-map-s im)] [is (interval-map-iter-si iter)]) - (cdr (skip-list-iterate-value s is)))) + (cdr (splay-tree-iterate-value s is)))) + +;; ============================================================ ;; Interval map -(define-struct interval-map (s =? =? s to)]) - (when ix - (let* ([ixkey (skip-list-iterate-key s ix)] - [ixvalue (skip-list-iterate-value s ix)]) - (skip-list-iterate-set-key! s ix (translate ixkey)) - (skip-list-iterate-set-value! s ix - (cons (translate (car ixvalue)) (cdr ixvalue)))) - (loop (skip-list-iterate-next s ix))))) +(define (make-interval-map #:key-contract [key-contract any/c] + #:value-contract [value-contract any/c]) + (cond [(and (eq? key-contract any/c) (eq? value-contract any/c)) + (interval-map (make-adjustable-splay-tree))] + [else + (interval-map* (make-adjustable-splay-tree) key-contract value-contract)])) + +;; ============================================================ + +(define (key-c im) + (cond [(interval-map*? im) + (let ([c (interval-map*-key-c im)]) + (if (eq? c any/c) exact-integer? (and/c exact-integer? c)))] + [else exact-integer?])) +(define (val-c im) + (cond [(interval-map*? im) + (interval-map*-value-c im)] + [else any/c])) (provide/contract - [rename make-interval-map* make-interval-map - (-> procedure? procedure? interval-map?)] - [make-numeric-interval-map - (-> interval-map-with-translate?)] + [make-interval-map + (->* () + (#:key-contract contract? #:value-contract contract?) + interval-map?)] [interval-map? - (-> any/c any)] - [interval-map-with-translate? - (-> any/c any)] + (-> any/c boolean?)] [interval-map-ref - (->* (interval-map? any/c) (any/c) any)] + (->i ([im interval-map?] [k (im) (key-c im)]) ([d any/c]) any)] [interval-map-set! - (-> interval-map? any/c any/c any/c any)] + (->i ([im interval-map?] + [start (im) (key-c im)] + [end (im) (key-c im)] + [v (im) (val-c im)]) + [_ void?])] [interval-map-update*! - (->* (interval-map? any/c any/c (-> any/c any/c)) (any/c) any)] + (->i ([im interval-map?] + [start (im) (key-c im)] + [end (im) (key-c im)] + [f (im) (-> (val-c im) (val-c im))]) + ([default any/c]) ;; imprecise + [_ void?])] [interval-map-cons*! - (->* (interval-map? any/c any/c any/c) (any/c) any)] + (->i ([im interval-map?] + [start (im) (key-c im)] + [end (im) (key-c im)] + [v any/c]) ;; imprecise + ([d any/c]) ;; imprecise + [_ void?])] [interval-map-remove! - (-> interval-map? any/c any/c any)] + (->i ([im interval-map?] + [start (im) (or/c -inf.0 (key-c im))] + [end (im) (or/c +inf.0 (key-c im))]) + [_ void?])] [interval-map-contract! - (-> interval-map-with-translate? any/c any/c any)] + (->i ([im interval-map?] + [start (im) (key-c im)] + [end (im) (key-c im)]) + [_ void?])] [interval-map-expand! - (-> interval-map-with-translate? any/c any/c any)] + (->i ([im interval-map?] + [start (im) (key-c im)] + [end (im) (key-c im)]) + [_ void?])] + [interval-map-iterate-first - (-> interval-map? (or/c interval-map-iter? #f))] + (-> interval-map? + (or/c interval-map-iter? #f))] [interval-map-iterate-next - (-> interval-map? interval-map-iter? (or/c interval-map-iter? #f))] + (-> interval-map? interval-map-iter? + (or/c interval-map-iter? #f))] [interval-map-iterate-key - (-> interval-map? interval-map-iter? any)] + (->i ([im interval-map?] [i interval-map-iter?]) + [_ (im) (let ([k (key-c im)]) (cons/c k k))])] [interval-map-iterate-value - (-> interval-map? interval-map-iter? any)] + (->i ([im interval-map?] [i interval-map-iter?]) + [_ (im) (val-c im)])] + [interval-map-iter? - (-> any/c any)]) + (-> any/c boolean?)]) #| ;; Testing diff --git a/collects/data/scribblings/gvector.scrbl b/collects/data/scribblings/gvector.scrbl index 34ae36be62..bfe5cf3526 100644 --- a/collects/data/scribblings/gvector.scrbl +++ b/collects/data/scribblings/gvector.scrbl @@ -5,7 +5,7 @@ racket/dict racket/base)) -@title[#:tag "gvector"]{Growable vectors} +@title[#:tag "gvector"]{Growable Vectors} @(define the-eval (make-base-eval)) @(the-eval '(require data/gvector)) diff --git a/collects/data/scribblings/interval-map.scrbl b/collects/data/scribblings/interval-map.scrbl index ed8f811950..3be0b01a22 100644 --- a/collects/data/scribblings/interval-map.scrbl +++ b/collects/data/scribblings/interval-map.scrbl @@ -15,52 +15,35 @@ @author[@author+email["Ryan Culpepper" "ryanc@racket-lang.org"]] -An interval-map is a mutable dictionary-like data structure where -mappings are added by @emph{half-open} intervals and queried by -discrete points. Interval-maps can be used with any total -order. Internally, an interval-map uses a skip-list -(@racketmodname[data/skip-list]) of intervals for efficient query -and update. +An interval-map is a mutable data structure that maps @emph{half-open} +intervals of exact integers to values. An interval-map is queried at a +discrete point, and the result of the query is the value mapped to the +interval containing the point. + +Internally, interval-maps use a splay-tree +(@racketmodname[data/splay-tree]) of intervals for efficient query and +update, including efficient contraction and expansion of intervals. Interval-maps implement the dictionary (@racketmodname[racket/dict]) interface to a limited extent. Only @racket[dict-ref] and the -iteraction-based methods (@racket[dict-iterate-first], +iteration-based methods (@racket[dict-iterate-first], @racket[dict-map], etc) are supported. For the iteration-based methods, the mapping's keys are considered the pairs of the start and end positions of the mapping's intervals. @examples[#:eval the-eval -(define r (make-numeric-interval-map)) +(define r (make-interval-map)) (interval-map-set! r 1 5 'apple) (interval-map-set! r 6 10 'pear) -(interval-map-set! r 3 6 'banana) +(interval-map-set! r 3 7 'banana) (dict-map r list) ] -@defproc[(make-interval-map [=? (any/c any/c . -> . any/c)] - [ . any/c)] - [translate (or/c (any/c any/c . -> . (any/c . -> . any/c)) #f) #f]) +@defproc[(make-interval-map [#:key-contract key-contract contract? any/c] + [#:value-contract value-contract contract? any/c]) interval-map?]{ -Makes a new empty interval-map. The interval-map uses @racket[=?] and -@racket[ . any/c)] + [start exact-integer?] + [end exact-integer?] + [updater (-> any/c any/c)] [default any/c (lambda () (error ....))]) void?]{ @@ -119,40 +95,36 @@ preserves existing distinctions within [@racket[start], @racket[end]). } @defproc[(interval-map-remove! [interval-map interval-map?] - [start any/c] - [end any/c]) + [start (or/c exact-integer? -inf.0)] + [end (or/c exact-integer? +inf.0)]) void?]{ Removes the value associated with every position in [@racket[start], @racket[end]). } -@defproc[(interval-map-expand! [interval-map interval-map-with-translate?] - [start any/c] - [end any/c]) - void?]{ - -Expands @racket[interval-map]'s domain by introducing a gap -[@racket[start], @racket[end]) and adjusting intervals after -@racket[start] using @racket[(_translate start end)]. - -If @racket[interval-map] was not constructed with a -@racket[_translate] argument, an exception is raised. If -@racket[start] is not less than @racket[end], an exception is raised. -} - -@defproc[(interval-map-contract! [interval-map interval-map-with-translate?] - [start any/c] - [end any/c]) +@defproc[(interval-map-contract! [interval-map interval-map?] + [start exact-integer?] + [end exact-integer?]) void?]{ Contracts @racket[interval-map]'s domain by removing all mappings on -the interval [@racket[start], @racket[end]) and adjusting intervals -after @racket[end] using @racket[(_translate end start)]. +the interval [@racket[start], @racket[end]) and decreasing intervals +initally after @racket[end] by @racket[(- end start)]. -If @racket[interval-map] was not constructed with a -@racket[_translate] argument, an exception is raised. If -@racket[start] is not less than @racket[end], an exception is raised. +If @racket[start] is not less than @racket[end], an exception is raised. +} + +@defproc[(interval-map-expand! [interval-map interval-map?] + [start exact-integer?] + [end exact-integer?]) + void?]{ + +Expands @racket[interval-map]'s domain by introducing a gap +[@racket[start], @racket[end]) and increasing intervals initially after +@racket[start] by @racket[(- end start)]. + +If @racket[start] is not less than @racket[end], an exception is raised. } @defproc[(interval-map-cons*! [interval-map interval-map?] diff --git a/collects/data/scribblings/skip-list.scrbl b/collects/data/scribblings/skip-list.scrbl index 5bf12cc11f..bfaa96f1f5 100644 --- a/collects/data/scribblings/skip-list.scrbl +++ b/collects/data/scribblings/skip-list.scrbl @@ -44,12 +44,28 @@ Makes a new empty skip-list. The skip-list uses @racket[=?] and ] } -@defproc[(skip-list? [v any/c]) - boolean?]{ +@defproc[(make-adjustable-skip-list + [#:key-contract key-contract contract? any/c] + [#:value-contract value-contract contract? any/c]) + adjustable-skip-list?]{ + +Makes a new empty skip-list that permits only exact integers as keys +(in addition to any constraints imposed by @racket[key-contract]). The +resulting skip-list answers true to @racket[adjustable-skip-list?] +and supports key adjustment. +} + +@defproc[(skip-list? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is a skip-list, @racket[#f] otherwise. +} +@defproc[(adjustable-skip-list? [v any/c]) boolean?]{ + +Returns @racket[#t] if @racket[v] is a skip-list that supports key +adjustment; see @racket[skip-list-contract!] and +@racket[skip-list-expand!]. } @deftogether[[ @@ -85,6 +101,40 @@ Implementations of @racket[dict-ref], @racket[dict-set!], respectively. } +@defproc[(skip-list-remove-range! [skip-list skip-list?] + [from any/c] + [to any/c]) + void?]{ + +Removes all keys in [@racket[from], @racket[to]); that is, all keys +greater than or equal to @racket[from] and less than @racket[to]. +} + +@defproc[(skip-list-contract! [skip-list adjustable-skip-list?] + [from exact-integer?] + [to exact-integer?]) + void?]{ + +Like @racket[skip-list-remove-range!], but also decreases the value +of all keys greater than or equal to @racket[to] by @racket[(- to +from)]. + +This operation takes time proportional to the number of elements with +keys greater than or equal to @racket[to]. +} + +@defproc[(skip-list-expand! [skip-list adjustable-skip-list?] + [from exact-integer?] + [to exact-integer?]) + void?]{ + +Increases the value of all keys greater than or equal to @racket[from] +by @racket[(- to from)]. + +This operation takes time proportional to the number of elements with +keys greater than or equal to @racket[from]. +} + @deftogether[[ @defproc[(skip-list-iterate-greatest/list [skip-list skip-list?]) (listof pair?)]{ + +Returns an association list with the keys and values of +@racket[skip-list], in order. +} diff --git a/collects/data/scribblings/splay-tree.scrbl b/collects/data/scribblings/splay-tree.scrbl index 679fbd70c3..9750d74585 100644 --- a/collects/data/scribblings/splay-tree.scrbl +++ b/collects/data/scribblings/splay-tree.scrbl @@ -106,28 +106,39 @@ Implementations of @racket[dict-ref], @racket[dict-set!], respectively. } -@defproc[(splay-tree-remove-range! [s splay-tree?] [from any/c] [to any/c]) +@defproc[(splay-tree-remove-range! [s splay-tree?] + [from any/c] + [to any/c]) void?]{ Removes all keys in [@racket[from], @racket[to]); that is, all keys greater than or equal to @racket[from] and less than @racket[to]. + +This operation takes @italic{O(N)} time, or @italic{O(log N)} time if +@racket[(adjustable-splay-tree? s)]. } @defproc[(splay-tree-contract! [s adjustable-splay-tree?] - [from any/c] [to any/c]) + [from exact-integer?] [to exact-integer?]) void?]{ Like @racket[splay-tree-remove-range!], but also decreases the value of all keys greater than or equal to @racket[to] by @racket[(- to from)]. + +This operation is only allowed on adjustable splay trees, and it takes +@italic{O(log N)} time. } @defproc[(splay-tree-expand! [s adjustable-splay-tree?] - [from any/c] [to any/c]) + [from exact-integer?] [to exact-integer?]) void?]{ Increases the value of all keys greater than or equal to @racket[from] by @racket[(- to from)]. + +This operation is only allowed on adjustable splay trees, and it takes +@italic{O(log N)} time. } @deftogether[[ diff --git a/collects/data/skip-list.rkt b/collects/data/skip-list.rkt index 5acc5823be..b24bea135f 100644 --- a/collects/data/skip-list.rkt +++ b/collects/data/skip-list.rkt @@ -1,5 +1,6 @@ #lang racket/base -(require racket/contract +(require racket/match + racket/contract racket/dict "private/ordered-dict.rkt") ;; owned by ryanc @@ -67,7 +68,7 @@ Levels are indexed starting at 1, as in the paper. ;; closest : Item Nat Key Cmp Cmp -> Item ;; Returns greatest item R s.t. key(R) = level, key = level, key(item) Item ;; Returns greatest item R s.t. key(R) = level. -;; Pre: level(item) >= level, key = level, key(item) data ;; Returns #f to indicate update (existing item changed); ;; returns item to indicate insertion (context's links need updating) -;; Pre: level(item) >= level, key = level, key(item) Item/#f ;; Returns item to indicate deletion (context's links need updating); ;; returns #f if not found. -;; Pre: level(item) >= level; key = level; key(item) void +;; Pre: level(*-item) >= level; key(*-item) =? t-key + (set-item-next! f-item level t-item*) + (delete-range f-item t-item (sub1 level) f-key t-key =? t-key + (set-item-key! item (- (item-key item) delta)) + (loop (item-next item 1))))))])) + +;; expand! : ... -> void +(define (expand! item level from to =? from + (set-item-key! item (+ (item-key item) delta)) + (loop (item-next item 1)))))) + ;; Skip list @@ -163,7 +197,8 @@ Levels are indexed starting at 1, as in the paper. (define result ;; new Item or #f (update/insert head (item-level head) key data =? (item-level result) (item-level head)) (let ([new-head (resize-item head (item-level result))]) (set-item-next! new-head (item-level result) result) @@ -175,7 +210,7 @@ Levels are indexed starting at 1, as in the paper. (define list s) + (let loop ([item (item-next (skip-list-head s) 1)]) + (if item + (cons (cons (item-key item) (item-data item)) + (loop (item-next item 1))) + null))) -(define (skip-list-iterate-set-value! s iter value) - (check-iter 'skip-list-iterate-set-value! s iter) - (set-item-data! (skip-list-iter-item iter) value)) +;; ============================================================ (define dict-methods (vector-immutable skip-list-ref @@ -314,6 +374,21 @@ Levels are indexed starting at 1, as in the paper. #f)) #:property prop:ordered-dict ordered-dict-methods) +(struct adjustable-skip-list skip-list () + #:property prop:dict/contract + (list dict-methods + (vector-immutable exact-integer? any/c skip-list-iter? + #f #f #f))) + +(struct adjustable-skip-list* adjustable-skip-list (key-c value-c) + #:property prop:dict/contract + (list dict-methods + (vector-immutable exact-integer? any/c skip-list-iter? + (lambda (s) (adjustable-skip-list*-key-c s)) + (lambda (s) (adjustable-skip-list*-value-c s)) + #f)) + #:property prop:ordered-dict ordered-dict-methods) + (define (make-skip-list =? * ((-> any/c any/c any/c) (-> any/c any/c any/c)) (#:key-contract contract? #:value-contract contract?) skip-list?)] + [make-adjustable-skip-list + (->* () + (#:key-contract contract? #:value-contract contract?) + adjustable-skip-list?)] [skip-list? (-> any/c boolean?)] + [adjustable-skip-list? + (-> any/c boolean?)] [skip-list-ref (->i ([s skip-list?] [k (s) (key-c s)]) @@ -347,6 +440,17 @@ Levels are indexed starting at 1, as in the paper. (->i ([s skip-list?] [k (s) (key-c s)]) [_ void?])] [skip-list-count (-> skip-list? exact-nonnegative-integer?)] + + [skip-list-remove-range! + (->i ([s skip-list?] [from (s) (key-c s)] [to (s) (key-c s)]) + [_ void?])] + [skip-list-contract! + (->i ([s adjustable-skip-list?] [from (s) (key-c s)] [to (s) (key-c s)]) + [_ void?])] + [skip-list-expand! + (->i ([s adjustable-skip-list?] [from (s) (key-c s)] [to (s) (key-c s)]) + [_ void?])] + [skip-list-iterate-first (-> skip-list? (or/c skip-list-iter? #f))] [skip-list-iterate-next @@ -370,10 +474,8 @@ Levels are indexed starting at 1, as in the paper. [skip-list-iterate-max (-> skip-list? (or/c skip-list-iter? #f))] - [skip-list-iterate-set-key! - (->i ([s skip-list?] [i skip-list-iter?] [k (s) (key-c s)]) [_ void?])] - [skip-list-iterate-set-value! - (->i ([s skip-list?] [i skip-list-iter?] [v (s) (val-c s)]) [_ void?])] - [skip-list-iter? - (-> any/c any)]) + (-> any/c any)] + + [skip-list->list + (-> skip-list? list?)]) diff --git a/collects/macro-debugger/syntax-browser/text.rkt b/collects/macro-debugger/syntax-browser/text.rkt index 8cbcf9c8db..a5b546adc8 100644 --- a/collects/macro-debugger/syntax-browser/text.rkt +++ b/collects/macro-debugger/syntax-browser/text.rkt @@ -105,7 +105,7 @@ invalidate-bitmap-cache) ;; interval-map of Drawings - (define drawings-list (make-numeric-interval-map)) + (define drawings-list (make-interval-map)) (field [hover-position #f])