added data/gvector, docs (need tests)
This commit is contained in:
parent
01fa7e9118
commit
5a8d2f010e
|
@ -1,17 +1,26 @@
|
|||
#lang racket/base
|
||||
(require racket/contract
|
||||
racket/dict)
|
||||
;; written by ryanc
|
||||
(require (for-syntax racket/base
|
||||
unstable/wrapc)
|
||||
racket/contract/base
|
||||
racket/dict
|
||||
racket/vector)
|
||||
|
||||
(define (make-gvector* #:capacity [capacity 10])
|
||||
(make-gvector (make-vector capacity #f) 0))
|
||||
|
||||
(define (check-index who index n)
|
||||
(define (check-index who index n set-to-add?)
|
||||
(unless (exact-nonnegative-integer? index)
|
||||
(raise-type-error who "exact nonnegative integer" index))
|
||||
(unless (< index n)
|
||||
(if (zero? n)
|
||||
(error who "index out of range for empty gvector: ~s" index)
|
||||
(error who "index out of range [0,~s]: ~s" (sub1 n) index))))
|
||||
(error who "index out of range ~a~a: ~s"
|
||||
(let ([max-index (if set-to-add? (- n 2) (- n 1))])
|
||||
(cond [(< max-index 0) "(empty)"]
|
||||
[else (format "[0,~s]" max-index)]))
|
||||
(if set-to-add?
|
||||
(format " or ~s to add" (- n 1))
|
||||
"")
|
||||
index)))
|
||||
|
||||
(define ((bad-index-error who index))
|
||||
(raise-mismatch-error who "index out of range" index))
|
||||
|
@ -33,7 +42,7 @@
|
|||
(define (gvector-remove! gv index)
|
||||
(let ([n (gvector-n gv)]
|
||||
[v (gvector-vec gv)])
|
||||
(check-index 'gvector-remove! index n)
|
||||
(check-index 'gvector-remove! index n #f)
|
||||
(set-gvector-n! gv (sub1 n))
|
||||
(vector-copy! v index v (add1 index) n)
|
||||
(vector-set! v (sub1 n) #f)))
|
||||
|
@ -51,27 +60,37 @@
|
|||
(default)
|
||||
default)))
|
||||
|
||||
;; gvector-set! with index = |gv| is interpreted as gvector-add!
|
||||
(define (gvector-set! gv index item)
|
||||
(check-index 'gvector-set! index (gvector-n gv))
|
||||
(vector-set! (gvector-vec gv) index item))
|
||||
(let ([n (gvector-n gv)])
|
||||
(check-index 'gvector-set! index (add1 n) #t)
|
||||
(if (= index n)
|
||||
(gvector-add! gv item)
|
||||
(vector-set! (gvector-vec gv) index item))))
|
||||
|
||||
;; creates a snapshot vector
|
||||
(define (gvector->vector gv)
|
||||
(vector-copy (gvector-vec gv) 0 (gvector-n gv)))
|
||||
|
||||
;; Iteration methods
|
||||
|
||||
;; A gvector position is represented as an exact-nonnegative-integer.
|
||||
|
||||
(define (gvector-iterate-first gv)
|
||||
(and (positive? (gvector-n gv)) 0))
|
||||
|
||||
(define (gvector-iterate-next gv iter)
|
||||
(check-index 'gvector-iterate-next iter (gvector-n gv))
|
||||
(check-index 'gvector-iterate-next iter (gvector-n gv) #f)
|
||||
(let ([n (gvector-n gv)])
|
||||
(and (< (add1 iter) n)
|
||||
(add1 iter))))
|
||||
|
||||
(define (gvector-iterate-key gv iter)
|
||||
(check-index 'gvector-iterate-key iter (gvector-n gv))
|
||||
(check-index 'gvector-iterate-key iter (gvector-n gv) #f)
|
||||
iter)
|
||||
|
||||
(define (gvector-iterate-value gv iter)
|
||||
(check-index 'gvector-iterate-value iter (gvector-n gv))
|
||||
(check-index 'gvector-iterate-value iter (gvector-n gv) #f)
|
||||
(gvector-ref gv iter))
|
||||
|
||||
(define (in-gvector gv)
|
||||
|
@ -79,6 +98,28 @@
|
|||
(raise-type-error 'in-gvector "gvector" gv))
|
||||
(in-dict-values gv))
|
||||
|
||||
(define-sequence-syntax in-gvector*
|
||||
(lambda () #'in-vector)
|
||||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
[[(var) (in-gv gv-expr)]
|
||||
(with-syntax ([gv-expr-c (wrap-expr/c #'gvector? #'gv-expr #:macro #'in-gv)])
|
||||
(syntax/loc stx
|
||||
[(var)
|
||||
(:do-in ([(gv) gv-expr-c])
|
||||
(void) ;; outer-check; handled by contract
|
||||
([index 0] [vec (gvector-vec gv)] [n (gvector-n gv)]) ;; loop bindings
|
||||
(< index n) ;; pos-guard
|
||||
([(var) (vector-ref vec index)]) ;; inner bindings
|
||||
#t ;; pre-guard
|
||||
#t ;; post-guard
|
||||
((add1 index) (gvector-vec gv) (gvector-n gv)))]))]
|
||||
[[(var ...) (in-gv gv-expr)]
|
||||
(with-syntax ([gv-expr-c (wrap-expr/c #'gvector? #'gv-expr #:macro #'in-gv)])
|
||||
(syntax/loc stx
|
||||
[(var ...) (in-vector gv-expr-c)]))]
|
||||
[_ #f])))
|
||||
|
||||
(define-struct gvector (vec n)
|
||||
#:mutable
|
||||
#:property prop:dict
|
||||
|
@ -95,10 +136,12 @@
|
|||
#:property prop:sequence in-gvector)
|
||||
|
||||
(provide/contract
|
||||
[gvector?
|
||||
(-> any/c any)]
|
||||
[rename make-gvector* make-gvector
|
||||
(->* () (#:capacity exact-positive-integer?) any)]
|
||||
[gvector-ref
|
||||
(-> gvector? exact-nonnegative-integer? any)]
|
||||
(->* (gvector? exact-nonnegative-integer?) (any/c) any)]
|
||||
[gvector-set!
|
||||
(-> gvector? exact-nonnegative-integer? any/c any)]
|
||||
[gvector-add!
|
||||
|
@ -107,5 +150,7 @@
|
|||
(-> gvector? exact-nonnegative-integer? any)]
|
||||
[gvector-count
|
||||
(-> gvector? any)]
|
||||
[in-gvector
|
||||
(-> gvector? sequence?)])
|
||||
[gvector->vector
|
||||
(-> gvector? vector?)])
|
||||
|
||||
(provide (rename-out [in-gvector* in-gvector]))
|
|
@ -18,4 +18,4 @@ This manual documents data structure libraries available in the
|
|||
@include-section["queue.scrbl"]
|
||||
@include-section["skip-list.scrbl"]
|
||||
@include-section["interval-map.scrbl"]
|
||||
|
||||
@include-section["gvector.scrbl"]
|
||||
|
|
99
collects/data/scribblings/gvector.scrbl
Normal file
99
collects/data/scribblings/gvector.scrbl
Normal file
|
@ -0,0 +1,99 @@
|
|||
#lang scribble/manual
|
||||
@(require scribble/eval
|
||||
(for-label data/gvector
|
||||
racket/contract
|
||||
racket/dict
|
||||
racket/base))
|
||||
|
||||
@title[#:tag "gvector"]{Growable vectors}
|
||||
|
||||
@(define the-eval (make-base-eval))
|
||||
@(the-eval '(require data/gvector))
|
||||
@(the-eval '(require racket/dict))
|
||||
|
||||
@defmodule[data/gvector]
|
||||
|
||||
@author[@author+email["Ryan Culpepper" "ryanc@racket-lang.org"]]
|
||||
|
||||
A growable vector (gvector) is a mutable sequence whose length can
|
||||
change over time. A gvector also acts as a dictionary (@racket[dict?]
|
||||
from @racketmodname[racket/dict]), where the keys are zero-based
|
||||
indexes and the values are the elements of the gvector. A gvector can
|
||||
be extended by adding an element to the end, and it can be shrunk by
|
||||
removing any element, although removal can take time linear in the
|
||||
number of elements in the gvector.
|
||||
|
||||
@defproc[(make-gvector [#:capacity capacity exact-positive-integer? 10])
|
||||
gvector?]{
|
||||
|
||||
Creates a new empty growable vector (gvector) with an initial capacity
|
||||
of @racket[capacity].
|
||||
}
|
||||
|
||||
@defproc[(gvector? [x any/c]) boolean?]{
|
||||
|
||||
Returns @racket[#t] if @racket[x] was created by
|
||||
@racket[make-gvector], @racket[#f] otherwise.
|
||||
}
|
||||
|
||||
@defproc[(gvector-ref [gv gvector?]
|
||||
[index exact-nonnegative-integer?]
|
||||
[default any/c (error ....)])
|
||||
any/c]{
|
||||
|
||||
Returns the element at index @racket[index], if @racket[index] is less
|
||||
than @racket[(gvector-count gv)]. Otherwise, @racket[default] is
|
||||
invoked if it is a procedure, returned otherwise.
|
||||
}
|
||||
|
||||
@defproc[(gvector-add! [gv gvector?]
|
||||
[value any/c])
|
||||
void?]{
|
||||
|
||||
Adds @racket[value] to the end of the gvector @racket[gv].
|
||||
}
|
||||
|
||||
@defproc[(gvector-set! [gv gvector?]
|
||||
[index (and/c exact-nonnegative-integer?
|
||||
(</c (+ 1 (gvector-count gv))))]
|
||||
[value any/c])
|
||||
void?]{
|
||||
|
||||
Sets the value at index @racket[index] to be @racket[value]. If
|
||||
@racket[index] is @racket[(gvector-count gv)]---that is, one more than
|
||||
the greatest used index---the effect is the same as
|
||||
@racket[(gvector-add! gv value)].
|
||||
}
|
||||
|
||||
@defproc[(gvector-remove! [gv gvector?]
|
||||
[index (and/c exact-nonnegative-integer?
|
||||
(</c (gvector-count gv)))])
|
||||
void?]{
|
||||
|
||||
Removes the item at @racket[index], shifting items at higher indexes
|
||||
down. Takes time proportional to @racket[(- (gvector-count gv)
|
||||
index)].
|
||||
}
|
||||
|
||||
@defproc[(gvector-count [gv gvector?])
|
||||
exact-nonnegative-integer?]{
|
||||
|
||||
Returns the number of items in @racket[gv].
|
||||
}
|
||||
|
||||
@defproc[(gvector->vector [gv gvector?])
|
||||
vector?]{
|
||||
|
||||
Returns a vector of length @racket[(gvector-count gv)] containing the
|
||||
elements of @racket[gv] in order.
|
||||
}
|
||||
|
||||
@defproc[(in-gvector [gv gvector?])
|
||||
sequence?]{
|
||||
|
||||
Returns a sequence whose elements are the elements of
|
||||
@racket[gv]. Mutation of @racket[gv] while the sequence is running
|
||||
changes the elements produced by the sequence. To obtain a sequence
|
||||
from a snapshot of @racket[gv], use @racket[(in-vector
|
||||
(gvector->vector gv))] instead.
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
(require racket/class
|
||||
unstable/class-iop
|
||||
racket/list
|
||||
"gvector.rkt"
|
||||
data/gvector
|
||||
"../base.rkt"
|
||||
"interfaces.rkt"
|
||||
"cache-box.rkt")
|
||||
|
|
Loading…
Reference in New Issue
Block a user