added data/gvector, docs (need tests)

This commit is contained in:
Ryan Culpepper 2010-09-03 16:24:03 -06:00
parent 01fa7e9118
commit 5a8d2f010e
4 changed files with 161 additions and 17 deletions

View File

@ -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]))

View File

@ -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"]

View 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.
}

View File

@ -2,7 +2,7 @@
(require racket/class
unstable/class-iop
racket/list
"gvector.rkt"
data/gvector
"../base.rkt"
"interfaces.rkt"
"cache-box.rkt")