|
3 | 3 | (require (for-syntax racket/base |
4 | 4 | syntax/contract |
5 | 5 | syntax/for-body) |
| 6 | + racket/performance-hint |
6 | 7 | racket/serialize |
| 8 | + racket/fixnum |
7 | 9 | racket/contract/base |
8 | 10 | racket/dict |
| 11 | + racket/unsafe/ops |
9 | 12 | racket/vector |
10 | 13 | racket/struct) |
11 | 14 |
|
12 | 15 | (define DEFAULT-CAPACITY 10) |
13 | 16 |
|
| 17 | +(define MIN-CAPACITY 8) |
| 18 | + |
14 | 19 | (define (make-gvector #:capacity [capacity DEFAULT-CAPACITY]) |
15 | | - (gvector (make-vector capacity #f) 0)) |
| 20 | + (unless (exact-nonnegative-integer? capacity) |
| 21 | + (raise-argument-error* 'make-gvector 'data/gvector "exact-nonnegative-integer?" capacity)) |
| 22 | + (gvector (make-vector (max capacity MIN-CAPACITY) 0) 0)) |
16 | 23 |
|
17 | 24 | (define gvector* |
18 | 25 | (let ([gvector |
|
29 | 36 | (unless (< index hi) |
30 | 37 | (raise-range-error who "gvector" "" index gv 0 (sub1 hi)))) |
31 | 38 |
|
32 | | -;; ensure-free-space! : GVector Nat -> Void |
33 | | -(define (ensure-free-space! gv needed-free-space) |
34 | | - (define vec (gvector-vec gv)) |
35 | | - (define n (gvector-n gv)) |
36 | | - (define cap (vector-length vec)) |
37 | | - (define needed-cap (+ n needed-free-space)) |
38 | | - (unless (<= needed-cap cap) |
39 | | - (define new-cap |
40 | | - (let loop ([new-cap (max DEFAULT-CAPACITY cap)]) |
41 | | - (if (<= needed-cap new-cap) new-cap (loop (* 2 new-cap))))) |
42 | | - (define new-vec (make-vector new-cap #f)) |
43 | | - (vector-copy! new-vec 0 vec) |
44 | | - (set-gvector-vec! gv new-vec))) |
45 | | - |
46 | | -(define gvector-add! |
47 | | - (case-lambda |
48 | | - [(gv item) |
49 | | - (ensure-free-space! gv 1) |
50 | | - (define n (gvector-n gv)) |
51 | | - (define v (gvector-vec gv)) |
52 | | - (vector-set! v n item) |
53 | | - (set-gvector-n! gv (add1 n))] |
54 | | - [(gv . items) |
55 | | - (define item-count (length items)) |
56 | | - (ensure-free-space! gv item-count) |
57 | | - (define n (gvector-n gv)) |
58 | | - (define v (gvector-vec gv)) |
59 | | - (for ([index (in-naturals n)] [item (in-list items)]) |
60 | | - (vector-set! v index item)) |
61 | | - (set-gvector-n! gv (+ n item-count))])) |
| 39 | +(begin-encourage-inline |
| 40 | + |
| 41 | + (define (check-gvector who gv) |
| 42 | + (unless (gvector? gv) |
| 43 | + (raise-argument-error* who 'data/gvector "gvector?" gv))) |
| 44 | + |
| 45 | + |
| 46 | + ;; ensure-free-space-vec! : Vector Nat Nat -> Vector/#f |
| 47 | + (define (ensure-free-space-vec! vec n needed-free-space) |
| 48 | + (define cap (unsafe-vector*-length vec)) |
| 49 | + (define needed-cap (unsafe-fx+ n needed-free-space)) |
| 50 | + (cond [(<= needed-cap cap) #f] |
| 51 | + [else |
| 52 | + ;; taken from Rust's raw_vec implementation |
| 53 | + (let* ([new-cap (unsafe-fxmax (unsafe-fx* 2 cap) needed-cap)] |
| 54 | + [new-cap (unsafe-fxmax new-cap MIN-CAPACITY)]) |
| 55 | + (vector*-extend vec new-cap 0))])) |
| 56 | + |
| 57 | + (define (ensure-free-space! gv needed-free-space) |
| 58 | + (define v (ensure-free-space-vec! (gvector-vec gv) (gvector-n gv) needed-free-space)) |
| 59 | + (when v (set-gvector-vec! gv v))) |
| 60 | + |
| 61 | + (define-syntax-rule (define/ensure-space! (n v) gv needed-free-space) |
| 62 | + (begin (define n (gvector-n gv)) |
| 63 | + (define v1 (gvector-vec gv)) |
| 64 | + (define v2 (ensure-free-space-vec! v1 n needed-free-space)) |
| 65 | + (define v (if v2 (begin (set-gvector-vec! gv v2) v2) v1)))) |
| 66 | + |
| 67 | + ;; only safe on unchaperoned gvectors |
| 68 | + (define (unsafe-gvector-add! gv item) |
| 69 | + (define/ensure-space! (n v) gv 1) |
| 70 | + (unsafe-vector*-set! v n item) |
| 71 | + (set-gvector-n! gv (unsafe-fx+ 1 n))) |
| 72 | + |
| 73 | + (define gvector-add! |
| 74 | + (case-lambda |
| 75 | + [(gv item) |
| 76 | + (check-gvector 'gvector-add! gv) |
| 77 | + (define/ensure-space! (n v) gv 1) |
| 78 | + (unsafe-vector*-set! v n item) |
| 79 | + (set-gvector-n! gv (unsafe-fx+ 1 n))] |
| 80 | + [(gv . items) |
| 81 | + (check-gvector 'gvector-add! gv) |
| 82 | + (define item-count (length items)) |
| 83 | + (define/ensure-space! (n v) gv item-count) |
| 84 | + (for ([index (in-naturals n)] [item (in-list items)]) |
| 85 | + (unsafe-vector*-set! v index item)) |
| 86 | + (set-gvector-n! gv (+ n item-count))]))) |
62 | 87 |
|
63 | 88 | ;; SLOW! |
64 | 89 | (define (gvector-insert! gv index item) |
65 | 90 | ;; This does (n - index) redundant copies on resize, but that |
66 | 91 | ;; happens rarely and I prefer the simpler code. |
67 | | - (define n (gvector-n gv)) |
| 92 | + (check-gvector 'gvector-insert! gv) |
68 | 93 | (check-index 'gvector-insert! gv index #t) |
| 94 | + (define n (gvector-n gv)) |
69 | 95 | (ensure-free-space! gv 1) |
70 | 96 | (define v (gvector-vec gv)) |
71 | 97 | (vector-copy! v (add1 index) v index n) |
|
97 | 123 |
|
98 | 124 | ;; SLOW! |
99 | 125 | (define (gvector-remove! gv index) |
| 126 | + (check-gvector 'gvector-remove! gv) |
100 | 127 | (define n (gvector-n gv)) |
101 | 128 | (define v (gvector-vec gv)) |
102 | 129 | (check-index 'gvector-remove! gv index #f) |
|
106 | 133 | (trim! gv)) |
107 | 134 |
|
108 | 135 | (define (gvector-remove-last! gv) |
| 136 | + (check-gvector 'gvector-remove-last! gv) |
109 | 137 | (let ([n (gvector-n gv)] |
110 | 138 | [v (gvector-vec gv)]) |
111 | 139 | (unless (> n 0) (error 'gvector-remove-last! "empty")) |
|
114 | 142 | last-val)) |
115 | 143 |
|
116 | 144 | (define (gvector-count gv) |
| 145 | + (check-gvector 'gvector-count gv) |
117 | 146 | (gvector-n gv)) |
118 | 147 |
|
119 | 148 | (define none (gensym 'none)) |
120 | 149 |
|
121 | 150 | (define (gvector-ref gv index [default none]) |
| 151 | + (check-gvector 'gvector-ref gv) |
122 | 152 | (unless (exact-nonnegative-integer? index) |
123 | 153 | (raise-type-error 'gvector-ref "exact nonnegative integer" index)) |
124 | | - (if (< index (gvector-n gv)) |
125 | | - (vector-ref (gvector-vec gv) index) |
126 | | - (cond [(eq? default none) |
127 | | - (check-index 'gvector-ref gv index #f)] |
128 | | - [(procedure? default) (default)] |
129 | | - [else default]))) |
| 154 | + (let ([v (gvector-vec gv)]) |
| 155 | + (if (< index (gvector-n gv)) |
| 156 | + (unsafe-vector*-ref v index) |
| 157 | + (cond [(eq? default none) |
| 158 | + (check-index 'gvector-ref gv index #f)] |
| 159 | + [(procedure? default) (default)] |
| 160 | + [else default])))) |
| 161 | + |
| 162 | +(define (gvector-append! gv gv*) |
| 163 | + (check-gvector 'gvector-append! gv) |
| 164 | + (check-gvector 'gvector-append! gv*) |
| 165 | + (ensure-free-space! gv (gvector-n gv*)) |
| 166 | + (vector-copy! (gvector-vec gv) (gvector-n gv) (gvector-vec gv*))) |
| 167 | + |
| 168 | +(define (gvector-append gv gv*) |
| 169 | + (check-gvector 'gvector-append gv) |
| 170 | + (check-gvector 'gvector-append gv*) |
| 171 | + ;; retain the spare capacity of gv* |
| 172 | + (define gv0 (make-gvector #:capacity (+ (gvector-n gv) (vector-length (gvector-vec gv*))))) |
| 173 | + (define v0 (gvector-vec gv0)) |
| 174 | + (vector-copy! v0 0 (gvector-vec gv) 0 (gvector-n gv)) |
| 175 | + (vector-copy! v0 (gvector-n gv) (gvector-vec gv*) (gvector-n gv*))) |
| 176 | + |
130 | 177 |
|
131 | 178 | ;; gvector-set! with index = |gv| is interpreted as gvector-add! |
132 | 179 | (define (gvector-set! gv index item) |
133 | | - (let ([n (gvector-n gv)]) |
| 180 | + (check-gvector 'gvector-set! gv) |
| 181 | + (let ([v (gvector-vec gv)] |
| 182 | + [n (gvector-n gv)]) |
134 | 183 | (check-index 'gvector-set! gv index #t) |
135 | | - (if (= index n) |
136 | | - (gvector-add! gv item) |
137 | | - (vector-set! (gvector-vec gv) index item)))) |
| 184 | + (if (unsafe-fx= index n) |
| 185 | + (if (impersonator? gv) |
| 186 | + (gvector-add! gv item) |
| 187 | + (unsafe-gvector-add! gv item)) |
| 188 | + (unsafe-vector*-set! v index item)))) |
138 | 189 |
|
139 | 190 | ;; creates a snapshot vector |
140 | 191 | (define (gvector->vector gv) |
141 | | - (vector-copy (gvector-vec gv) 0 (gvector-n gv))) |
| 192 | + (check-gvector 'gvector->vector gv) |
| 193 | + (vector*-copy (gvector-vec gv) 0 (gvector-n gv))) |
142 | 194 |
|
143 | 195 | (define (gvector->list gv) |
| 196 | + (check-gvector 'gvector->list gv) |
144 | 197 | (vector->list (gvector->vector gv))) |
145 | 198 |
|
146 | 199 | ;; constructs a gvector |
147 | 200 | (define (vector->gvector v) |
| 201 | + (unless (vector? v) |
| 202 | + (raise-argument-error* vector->gvector 'data/gvector "vector?" v)) |
148 | 203 | (define lv (vector-length v)) |
149 | | - (define gv (make-gvector #:capacity lv)) |
| 204 | + (define gv (make-gvector #:capacity (max lv DEFAULT-CAPACITY))) |
150 | 205 | (define nv (gvector-vec gv)) |
151 | 206 | (vector-copy! nv 0 v) |
152 | 207 | (set-gvector-n! gv lv) |
153 | 208 | gv) |
154 | 209 |
|
155 | 210 | (define (list->gvector v) |
| 211 | + (unless (list? v) |
| 212 | + (raise-argument-error* list->gvector 'data/gvector "list?" v)) |
156 | 213 | (vector->gvector (list->vector v))) |
157 | 214 |
|
158 | 215 | ;; Iteration methods |
|
165 | 222 | (define (gvector-iterate-next gv iter) |
166 | 223 | (check-index 'gvector-iterate-next gv iter #f) |
167 | 224 | (let ([n (gvector-n gv)]) |
168 | | - (and (< (add1 iter) n) |
169 | | - (add1 iter)))) |
| 225 | + (and (< (unsafe-fx+ 1 iter) n) |
| 226 | + (unsafe-fx+ 1 iter)))) |
170 | 227 |
|
171 | 228 | (define (gvector-iterate-key gv iter) |
172 | 229 | (check-index 'gvector-iterate-key gv iter #f) |
|
177 | 234 | (gvector-ref gv iter)) |
178 | 235 |
|
179 | 236 | (define (in-gvector gv) |
180 | | - (unless (gvector? gv) |
181 | | - (raise-type-error 'in-gvector "gvector" gv)) |
| 237 | + (check-gvector 'in-gvector gv) |
182 | 238 | (in-dict-values gv)) |
183 | 239 |
|
184 | 240 | (define-sequence-syntax in-gvector* |
|
192 | 248 | (:do-in ([(gv) gv-expr-c]) |
193 | 249 | (void) ;; outer-check; handled by contract |
194 | 250 | ([index 0] [vec (gvector-vec gv)] [n (gvector-n gv)]) ;; loop bindings |
195 | | - (< index n) ;; pos-guard |
196 | | - ([(var) (vector-ref vec index)]) ;; inner bindings |
| 251 | + (unsafe-fx< index n) ;; pos-guard |
| 252 | + ([(var) (unsafe-vector*-ref vec index)]) ;; inner bindings |
197 | 253 | #t ;; pre-guard |
198 | 254 | #t ;; post-guard |
199 | | - ((add1 index) (gvector-vec gv) (gvector-n gv)))]))] |
| 255 | + ((unsafe-fx+ 1 index) vec n))]))] |
200 | 256 | [[(var ...) (in-gv gv-expr)] |
201 | 257 | (with-syntax ([gv-expr-c (wrap-expr/c #'gvector? #'gv-expr #:macro #'in-gv)]) |
202 | 258 | (syntax/loc stx |
|
206 | 262 | (define-syntax (for/gvector stx) |
207 | 263 | (syntax-case stx () |
208 | 264 | [(_ (clause ...) . body) |
| 265 | + #'(for/gvector #:capacity DEFAULT-CAPACITY (clause ...) . body)] |
| 266 | + [(_ #:capacity cap (clause ...) . body) |
209 | 267 | (with-syntax ([((pre-body ...) post-body) (split-for-body stx #'body)]) |
210 | 268 | (quasisyntax/loc stx |
211 | | - (let ([gv (make-gvector)]) |
| 269 | + (let ([gv (make-gvector #:capacity cap)]) |
212 | 270 | (for/fold/derived #,stx () (clause ...) |
213 | 271 | pre-body ... |
214 | | - (call-with-values (lambda () . post-body) |
215 | | - (lambda args (apply gvector-add! gv args) (values)))) |
| 272 | + (call-with-values (lambda () . post-body) |
| 273 | + (case-lambda |
| 274 | + [(one) (unsafe-gvector-add! gv one)] |
| 275 | + [args (apply gvector-add! gv args)])) |
| 276 | + (values)) |
216 | 277 | gv)))])) |
217 | 278 |
|
218 | 279 | (define-syntax (for*/gvector stx) |
219 | 280 | (syntax-case stx () |
220 | 281 | [(_ (clause ...) . body) |
| 282 | + #'(for/gvector #:capacity DEFAULT-CAPACITY (clause ...) . body)] |
| 283 | + [(_ #:capacity cap (clause ...) . body) |
221 | 284 | (with-syntax ([((pre-body ...) post-body) (split-for-body stx #'body)]) |
222 | 285 | (quasisyntax/loc stx |
223 | | - (let ([gv (make-gvector)]) |
| 286 | + (let ([gv (make-gvector #:capacity cap)]) |
224 | 287 | (for*/fold/derived #,stx () (clause ...) |
225 | 288 | pre-body ... |
226 | 289 | (call-with-values (lambda () . post-body) |
227 | | - (lambda args (apply gvector-add! gv args) (values)))) |
| 290 | + (case-lambda |
| 291 | + [(one) (begin (unsafe-gvector-add! gv one) (values))] |
| 292 | + [args (begin (apply gvector-add! gv args) (values))]))) |
228 | 293 | gv)))])) |
229 | 294 |
|
230 | 295 | (struct gvector (vec n) |
|
276 | 341 | #t |
277 | 342 | (or (current-load-relative-directory) (current-directory)))) |
278 | 343 |
|
279 | | -(provide/contract |
280 | | - [gvector? |
281 | | - (-> any/c any)] |
282 | | - [rename gvector* gvector |
283 | | - (->* () () #:rest any/c gvector?)] |
284 | | - [make-gvector |
285 | | - (->* () (#:capacity exact-positive-integer?) gvector?)] |
286 | | - [gvector-ref |
287 | | - (->* (gvector? exact-nonnegative-integer?) (any/c) any)] |
288 | | - [gvector-set! |
289 | | - (-> gvector? exact-nonnegative-integer? any/c any)] |
290 | | - [gvector-add! |
291 | | - (->* (gvector?) () #:rest any/c any)] |
292 | | - [gvector-insert! |
293 | | - (-> gvector? exact-nonnegative-integer? any/c any)] |
294 | | - [gvector-remove! |
295 | | - (-> gvector? exact-nonnegative-integer? any)] |
296 | | - [gvector-remove-last! |
297 | | - (-> gvector? any)] |
298 | | - [gvector-count |
299 | | - (-> gvector? any)] |
300 | | - [gvector->vector |
301 | | - (-> gvector? vector?)] |
302 | | - [gvector->list |
303 | | - (-> gvector? list?)] |
304 | | - [vector->gvector |
305 | | - (-> vector? gvector?)] |
306 | | - [list->gvector |
307 | | - (-> list? gvector?)]) |
308 | | - |
309 | | -(provide (rename-out [in-gvector* in-gvector]) |
310 | | - for/gvector |
311 | | - for*/gvector) |
| 344 | +(provide |
| 345 | + gvector? |
| 346 | + (rename-out [gvector* gvector]) |
| 347 | + make-gvector |
| 348 | + gvector-ref |
| 349 | + gvector-set! |
| 350 | + gvector-add! |
| 351 | + gvector-insert! |
| 352 | + gvector-remove! |
| 353 | + gvector-remove-last! |
| 354 | + gvector-append |
| 355 | + gvector-append! |
| 356 | + gvector-count |
| 357 | + gvector->vector |
| 358 | + gvector->list |
| 359 | + vector->gvector |
| 360 | + list->gvector |
| 361 | + (rename-out [in-gvector* in-gvector]) |
| 362 | + for/gvector |
| 363 | + for*/gvector) |
312 | 364 |
|
313 | 365 | (module+ deserialize |
314 | 366 | (provide deserialize-gvector) |
|
0 commit comments