cs: faster list?

This commit is contained in:
Matthew Flatt 2019-12-22 16:24:57 -07:00
parent 11e7598021
commit 723232081c

View File

@ -5,34 +5,51 @@
;; where a second request will cache at the N/4-tail pair, etc. ;; where a second request will cache at the N/4-tail pair, etc.
;; Detect cycles using the same `slow` tortoise that is used for ;; Detect cycles using the same `slow` tortoise that is used for
;; caching. ;; caching.
;;
;; To reduce the overhead of checking the hash table, only
;; start using it after the first `CHECK-AFTER-LEN` pairs.
;; Then, check only every `CHECK-EVERY` pairs --- and record
;; a sequence of `CHECK-EVERY` results so one will hit when
;; checking every `CHECK-EVERY` pairs.
(define-thread-local lists (make-weak-eq-hashtable)) (define-thread-local lists (make-weak-eq-hashtable))
(define CHECK-AFTER-LEN 32)
(define CHECK-EVERY 4)
(define (list? v) (define (list? v)
(let loop ([v v] [depth 0]) (let loop ([v v] [count 0])
(cond (cond
[(null? v) #t] [(null? v) #t]
[(not (pair? v)) #f] [(not (pair? v)) #f]
[(pair? v) [else
(cond (cond
[(fx<= depth 32) [(fx<= count CHECK-AFTER-LEN)
(loop (cdr v) (fx+ depth 1))] (loop (cdr v) (fx+ count 1))]
[else [else
(let loop ([fast (cdr v)] [slow v] [slow-step? #f]) (let ([lists lists])
(let ([return (lambda (result) (let loop ([fast (cdr v)] [slow v] [slow-step? #f] [countdown 0])
(hashtable-set! lists slow result) (let ([return (lambda (result)
result)]) (eq-hashtable-set! lists slow result)
(cond (let loop ([slow slow] [count (fx- CHECK-EVERY 1)])
[(null? fast) (return #t)] (unless (or (eq? slow fast)
[(not (pair? fast)) (return #f)] (fx= count 0))
[(eq? fast slow) (return #f)] ; cycle (eq-hashtable-set! lists slow result)
[else (loop (cdr slow) (fx- count 1))))
(let ([is-list? (hashtable-ref lists fast none)]) result)])
(cond (cond
[(eq? is-list? none) [(null? fast) (return #t)]
(loop (cdr fast) (if slow-step? (cdr slow) slow) (not slow-step?))] [(not (pair? fast)) (return #f)]
[else [(eq? fast slow) (return #f)] ; cycle
(return is-list?)]))])))])]))) [(fx= 0 countdown)
(let ([is-list? (eq-hashtable-ref lists fast none)])
(cond
[(eq? is-list? none)
(loop (cdr fast) (if slow-step? (cdr slow) slow) (not slow-step?) CHECK-EVERY)]
[else
(return is-list?)]))]
[else
(loop (cdr fast) (if slow-step? (cdr slow) slow) (not slow-step?) (fx- countdown 1))]))))])])))
(define (append-n l n l2) (define (append-n l n l2)
(cond (cond