|
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-positive-integer? capacity) |
| 21 | + (raise-argument-error* 'make-gvector 'data/gvector "exact-positive-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 | + (define new-vec |
| 56 | + ;; An optimization could eliminate this subtraction |
| 57 | + (vector*-extend vec (unsafe-fx- new-cap cap) 0)) |
| 58 | + new-vec)])) |
| 59 | + |
| 60 | + (define (ensure-free-space! gv needed-free-space) |
| 61 | + (define v (ensure-free-space-vec! (gvector-vec gv) (gvector-n gv) needed-free-space)) |
| 62 | + (when v (set-gvector-vec! gv v))) |
| 63 | + |
| 64 | + (define-syntax-rule (gv-ensure-space! gv n v needed-free-space) |
| 65 | + (begin (define n (gvector-n gv)) |
| 66 | + (define v1 (gvector-vec gv)) |
| 67 | + (define v2 (ensure-free-space-vec! v1 n needed-free-space)) |
| 68 | + (define v (if v2 (begin (set-gvector-vec! gv v2) v2) v1)))) |
| 69 | + |
| 70 | + ;; only safe on unchaperoned gvectors |
| 71 | + (define (unsafe-gvector-add! gv item) |
| 72 | + (gv-ensure-space! gv n v 1) |
| 73 | + (unsafe-vector*-set! v n item) |
| 74 | + (set-gvector-n! gv (unsafe-fx+ 1 n))) |
| 75 | + |
| 76 | + (define gvector-add! |
| 77 | + (case-lambda |
| 78 | + [(gv item) |
| 79 | + (check-gvector 'gvector-add! gv) |
| 80 | + (gv-ensure-space! gv n v 1) |
| 81 | + (unsafe-vector*-set! v n item) |
| 82 | + (set-gvector-n! gv (unsafe-fx+ 1 n))] |
| 83 | + [(gv . items) |
| 84 | + (check-gvector 'gvector-add! gv) |
| 85 | + (define item-count (length items)) |
| 86 | + (gv-ensure-space! gv n v item-count) |
| 87 | + (for ([index (in-naturals n)] [item (in-list items)]) |
| 88 | + (unsafe-vector*-set! v index item)) |
| 89 | + (set-gvector-n! gv (+ n item-count))]))) |
62 | 90 |
|
63 | 91 | ;; SLOW! |
64 | 92 | (define (gvector-insert! gv index item) |
65 | 93 | ;; This does (n - index) redundant copies on resize, but that |
66 | 94 | ;; happens rarely and I prefer the simpler code. |
67 | | - (define n (gvector-n gv)) |
| 95 | + (check-gvector 'gvector-insert! gv) |
68 | 96 | (check-index 'gvector-insert! gv index #t) |
| 97 | + (define n (gvector-n gv)) |
69 | 98 | (ensure-free-space! gv 1) |
70 | 99 | (define v (gvector-vec gv)) |
71 | 100 | (vector-copy! v (add1 index) v index n) |
|
97 | 126 |
|
98 | 127 | ;; SLOW! |
99 | 128 | (define (gvector-remove! gv index) |
| 129 | + (check-gvector 'gvector-remove! gv) |
100 | 130 | (define n (gvector-n gv)) |
101 | 131 | (define v (gvector-vec gv)) |
102 | 132 | (check-index 'gvector-remove! gv index #f) |
|
106 | 136 | (trim! gv)) |
107 | 137 |
|
108 | 138 | (define (gvector-remove-last! gv) |
| 139 | + (check-gvector 'gvector-remove-last! gv) |
109 | 140 | (let ([n (gvector-n gv)] |
110 | 141 | [v (gvector-vec gv)]) |
111 | 142 | (unless (> n 0) (error 'gvector-remove-last! "empty")) |
|
114 | 145 | last-val)) |
115 | 146 |
|
116 | 147 | (define (gvector-count gv) |
| 148 | + (check-gvector 'gvector-count gv) |
117 | 149 | (gvector-n gv)) |
118 | 150 |
|
119 | 151 | (define none (gensym 'none)) |
120 | 152 |
|
121 | 153 | (define (gvector-ref gv index [default none]) |
| 154 | + (check-gvector 'gvector-ref gv) |
122 | 155 | (unless (exact-nonnegative-integer? index) |
123 | 156 | (raise-type-error 'gvector-ref "exact nonnegative integer" index)) |
124 | 157 | (if (< index (gvector-n gv)) |
125 | | - (vector-ref (gvector-vec gv) index) |
| 158 | + (unsafe-vector*-ref (gvector-vec gv) index) |
126 | 159 | (cond [(eq? default none) |
127 | 160 | (check-index 'gvector-ref gv index #f)] |
128 | 161 | [(procedure? default) (default)] |
129 | 162 | [else default]))) |
130 | 163 |
|
131 | 164 | ;; gvector-set! with index = |gv| is interpreted as gvector-add! |
132 | 165 | (define (gvector-set! gv index item) |
| 166 | + (check-gvector 'gvector-set gv) |
133 | 167 | (let ([n (gvector-n gv)]) |
134 | 168 | (check-index 'gvector-set! gv index #t) |
135 | | - (if (= index n) |
136 | | - (gvector-add! gv item) |
137 | | - (vector-set! (gvector-vec gv) index item)))) |
| 169 | + (if (unsafe-fx= index n) |
| 170 | + (unsafe-gvector-add! gv item) |
| 171 | + (unsafe-vector*-set! (gvector-vec gv) index item)))) |
138 | 172 |
|
139 | 173 | ;; creates a snapshot vector |
140 | 174 | (define (gvector->vector gv) |
141 | | - (vector-copy (gvector-vec gv) 0 (gvector-n gv))) |
| 175 | + (check-gvector 'gvector->vector gv) |
| 176 | + (vector*-copy (gvector-vec gv) 0 (gvector-n gv))) |
142 | 177 |
|
143 | 178 | (define (gvector->list gv) |
| 179 | + (check-gvector 'gvector->list gv) |
144 | 180 | (vector->list (gvector->vector gv))) |
145 | 181 |
|
146 | 182 | ;; constructs a gvector |
147 | 183 | (define (vector->gvector v) |
| 184 | + (unless (vector? v) |
| 185 | + (raise-argument-error* vector->gvector 'data/gvector "vector?" v)) |
148 | 186 | (define lv (vector-length v)) |
149 | | - (define gv (make-gvector #:capacity lv)) |
| 187 | + (define gv (make-gvector #:capacity (max lv DEFAULT-CAPACITY))) |
150 | 188 | (define nv (gvector-vec gv)) |
151 | 189 | (vector-copy! nv 0 v) |
152 | 190 | (set-gvector-n! gv lv) |
153 | 191 | gv) |
154 | 192 |
|
155 | 193 | (define (list->gvector v) |
| 194 | + (unless (list? v) |
| 195 | + (raise-argument-error* list->gvector 'data/gvector "list?" v)) |
156 | 196 | (vector->gvector (list->vector v))) |
157 | 197 |
|
158 | 198 | ;; Iteration methods |
|
165 | 205 | (define (gvector-iterate-next gv iter) |
166 | 206 | (check-index 'gvector-iterate-next gv iter #f) |
167 | 207 | (let ([n (gvector-n gv)]) |
168 | | - (and (< (add1 iter) n) |
169 | | - (add1 iter)))) |
| 208 | + (and (< (unsafe-fx+ 1 iter) n) |
| 209 | + (unsafe-fx+ 1 iter)))) |
170 | 210 |
|
171 | 211 | (define (gvector-iterate-key gv iter) |
172 | 212 | (check-index 'gvector-iterate-key gv iter #f) |
|
177 | 217 | (gvector-ref gv iter)) |
178 | 218 |
|
179 | 219 | (define (in-gvector gv) |
180 | | - (unless (gvector? gv) |
181 | | - (raise-type-error 'in-gvector "gvector" gv)) |
| 220 | + (check-gvector 'in-gvector gv) |
182 | 221 | (in-dict-values gv)) |
183 | 222 |
|
184 | 223 | (define-sequence-syntax in-gvector* |
|
192 | 231 | (:do-in ([(gv) gv-expr-c]) |
193 | 232 | (void) ;; outer-check; handled by contract |
194 | 233 | ([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 |
| 234 | + (unsafe-fx< index n) ;; pos-guard |
| 235 | + ([(var) (unsafe-vector*-ref vec index)]) ;; inner bindings |
197 | 236 | #t ;; pre-guard |
198 | 237 | #t ;; post-guard |
199 | | - ((add1 index) (gvector-vec gv) (gvector-n gv)))]))] |
| 238 | + ((unsafe-fx+ 1 index) vec n))]))] |
200 | 239 | [[(var ...) (in-gv gv-expr)] |
201 | 240 | (with-syntax ([gv-expr-c (wrap-expr/c #'gvector? #'gv-expr #:macro #'in-gv)]) |
202 | 241 | (syntax/loc stx |
|
206 | 245 | (define-syntax (for/gvector stx) |
207 | 246 | (syntax-case stx () |
208 | 247 | [(_ (clause ...) . body) |
| 248 | + #'(for/gvector #:capacity DEFAULT-CAPACITY (clause ...) . body)] |
| 249 | + [(_ #:capacity cap (clause ...) . body) |
209 | 250 | (with-syntax ([((pre-body ...) post-body) (split-for-body stx #'body)]) |
210 | 251 | (quasisyntax/loc stx |
211 | | - (let ([gv (make-gvector)]) |
| 252 | + (let ([gv (make-gvector #:capacity cap)]) |
212 | 253 | (for/fold/derived #,stx () (clause ...) |
213 | 254 | pre-body ... |
214 | | - (call-with-values (lambda () . post-body) |
215 | | - (lambda args (apply gvector-add! gv args) (values)))) |
| 255 | + (call-with-values (lambda () . post-body) |
| 256 | + (case-lambda |
| 257 | + [(one) (unsafe-gvector-add! gv one)] |
| 258 | + [args (apply gvector-add! gv args)])) |
| 259 | + (values)) |
216 | 260 | gv)))])) |
217 | 261 |
|
218 | 262 | (define-syntax (for*/gvector stx) |
219 | 263 | (syntax-case stx () |
220 | 264 | [(_ (clause ...) . body) |
| 265 | + #'(for/gvector #:capacity DEFAULT-CAPACITY (clause ...) . body)] |
| 266 | + [(_ #:capacity cap (clause ...) . body) |
221 | 267 | (with-syntax ([((pre-body ...) post-body) (split-for-body stx #'body)]) |
222 | 268 | (quasisyntax/loc stx |
223 | | - (let ([gv (make-gvector)]) |
| 269 | + (let ([gv (make-gvector #:capacity cap)]) |
224 | 270 | (for*/fold/derived #,stx () (clause ...) |
225 | 271 | pre-body ... |
226 | 272 | (call-with-values (lambda () . post-body) |
227 | | - (lambda args (apply gvector-add! gv args) (values)))) |
| 273 | + (case-lambda |
| 274 | + [(one) (begin (unsafe-gvector-add! gv one) (values))] |
| 275 | + [args (begin (apply gvector-add! gv args) (values))]))) |
228 | 276 | gv)))])) |
229 | 277 |
|
230 | 278 | (struct gvector (vec n) |
|
276 | 324 | #t |
277 | 325 | (or (current-load-relative-directory) (current-directory)))) |
278 | 326 |
|
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) |
| 327 | +(provide |
| 328 | + gvector? |
| 329 | + (rename-out [gvector* gvector]) |
| 330 | + make-gvector |
| 331 | + gvector-ref |
| 332 | + gvector-set! |
| 333 | + gvector-add! |
| 334 | + gvector-insert! |
| 335 | + gvector-remove! |
| 336 | + gvector-remove-last! |
| 337 | + gvector-count |
| 338 | + gvector->vector |
| 339 | + gvector->list |
| 340 | + vector->gvector |
| 341 | + list->gvector |
| 342 | + (rename-out [in-gvector* in-gvector]) |
| 343 | + for/gvector |
| 344 | + for*/gvector) |
312 | 345 |
|
313 | 346 | (module+ deserialize |
314 | 347 | (provide deserialize-gvector) |
|
0 commit comments