perf(decoder): linear decoded-variants via hash seen-set
ober
c267e7cd10ac3e72dc2141ea598a5d4f5497d541
--- a/gitsafe/decoder.ss +++ b/gitsafe/decoder.ss @@ -168,8 +168,18 @@ (and (decoded-ok? s token) s))) (catch (e) #f))) + (def (hash-unique strings) + (let ([seen (make-hash-table)]) + (let loop ([xs strings] [acc '()]) + (cond + [(null? xs) (reverse acc)] + [(hash-key? seen (car xs)) (loop (cdr xs) acc)] + [else + (hash-put! seen (car xs) #t) + (loop (cdr xs) (cons (car xs) acc))])))) + (def (decode-once content) - (unique + (hash-unique (filter (lambda (s) (and s (string? s) (mostly-printable? s))) (append (filter-map decode-percent-token (regex-matches *percent-token-re* content)) @@ -178,19 +188,25 @@ (filter-map decode-base64-token (regex-matches *base64-token-re* content)))))) (def (decoded-variants content depth) - (let loop ([remaining depth] - [frontier (list content)] - [seen (list content)] - [acc '()]) - (if (<= remaining 0) - (reverse acc) - (let* ([decoded (unique (apply append (map decode-once frontier)))] - [fresh (filter (lambda (s) (not (member s seen))) decoded)]) - (if (null? fresh) - (reverse acc) - (loop (- remaining 1) - fresh - (append fresh seen) - (append fresh acc))))))) + (let ([seen (make-hash-table)]) + (hash-put! seen content #t) + (let loop ([remaining depth] + [frontier (list content)] + [acc '()]) + (if (<= remaining 0) + (reverse acc) + (let* ([decoded (apply append (map decode-once frontier))] + [fresh (let fl ([ds decoded] [out '()]) + (cond + [(null? ds) (reverse out)] + [(hash-key? seen (car ds)) (fl (cdr ds) out)] + [else + (hash-put! seen (car ds) #t) + (fl (cdr ds) (cons (car ds) out))]))]) + (if (null? fresh) + (reverse acc) + (loop (- remaining 1) + fresh + (append fresh acc)))))))) ) ;; end library