diff --git a/quad/quadwriter/query.rkt b/quad/quadwriter/query.rkt index 0fe75ab5..1c4b76cb 100644 --- a/quad/quadwriter/query.rkt +++ b/quad/quadwriter/query.rkt @@ -36,32 +36,46 @@ (define vec (match quad-or-index [(? quad? q) (make-query-index q)] [idx idx])) + (define (next-occurrence-between pred lidx ridx) + (cond + [(or (not lidx) (not ridx)) ridx] + ;; we are searching between, so add 1 to left idx + [(for/first ([idx (in-range (add1 lidx) ridx)] + #:when (pred (vector-ref vec idx))) + idx)] + [else (vector-length vec)])) (for/fold ([vidx 0] + [maxidx (vector-length vec)] #:result (and vidx (vector-ref vec vidx))) ([query-piece (in-list (parse-query query-str))] #:break (not vidx)) - (match query-piece - [(cons pred 'this) - ;; find the querying quad, and from there search backward - ;; todo: `this` should also cut down the domain of searching - (for/first ([vidx (in-range (vector-memq starting-q vec) -1 -1)] - #:when (pred (vector-ref vec vidx))) - vidx)] - [(cons pred 'last) (error 'unimplemented)] - [(cons pred 'prev) (error 'unimplemented)] - [(cons pred 'next) (error 'unimplemented)] - [(cons pred count) - (for/fold ([vidx vidx] - ;; sub 1 because return values add 1 - ;; and final result should be location of matching quad - #:result (and vidx (sub1 vidx))) - ([seen (in-range count)] - #:break (not vidx)) - (for/first ([vidx (in-range vidx (vector-length vec))] + (match-define (cons pred count) query-piece) + (define res-idx + (match count + [(or (== 'this eq?) (== 'last eq?)) + ;; find a starting point, then search backward + (for/first ([vidx (in-range (if (eq? count 'this) + ;; start at querying quad + (vector-memq starting-q vec) + ;; start at end + (sub1 maxidx)) -1 -1)] #:when (pred (vector-ref vec vidx))) - ;; add 1 so on next iteration, we can find next matcher - ;; and won't re-find this one immediately - (add1 vidx)))]))) + vidx)] + [(== 'prev eq?) (error 'unimplemented)] + [(== 'next eq?) (error 'unimplemented)] + [count + (for/fold ([vidx vidx] + ;; sub 1 because return values add 1 + ;; and final result should be location of matching quad + #:result (and vidx (sub1 vidx))) + ([seen (in-range count)] + #:break (not vidx)) + (for/first ([vidx (in-range vidx maxidx)] + #:when (pred (vector-ref vec vidx))) + ;; add 1 so on next iteration, we can find next matcher + ;; and won't re-find this one immediately + (add1 vidx)))])) + (values res-idx (next-occurrence-between pred res-idx maxidx)))) (module+ test (require rackunit)