mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-05-19 05:39:18 +02:00
243 lines
7.8 KiB
Scheme
243 lines
7.8 KiB
Scheme
|
|
(define-record-type Comparator
|
|
(%make-comparator% type-test equality ordering hash)
|
|
comparator?
|
|
(type-test comparator-type-test-predicate)
|
|
(equality comparator-equality-predicate)
|
|
(ordering comparator-ordering-predicate)
|
|
(hash comparator-hash-function))
|
|
|
|
(define (make-comparator type-test equality ordering hash)
|
|
(%make-comparator%
|
|
type-test
|
|
equality
|
|
ordering
|
|
(if (or (opcode? hash)
|
|
(not (procedure? hash))
|
|
(procedure-variadic? hash)
|
|
(> (procedure-arity hash) 1))
|
|
hash
|
|
(lambda (x . o) (hash x)))))
|
|
|
|
(define-syntax hash-bound
|
|
(er-macro-transformer
|
|
(lambda (expr rename compare)
|
|
(if (fixnum? (- (expt 2 62) 1))
|
|
(- (expt 2 62) 1)
|
|
(- (expt 2 30) 1)))))
|
|
|
|
(define-syntax hash-salt
|
|
(er-macro-transformer
|
|
(let ((salt (or (string->number
|
|
(or (get-environment-variable "CHIBI_HASH_SALT") ""))
|
|
(random-integer (hash-bound)))))
|
|
(lambda (expr rename compare)
|
|
salt))))
|
|
|
|
(define-syntax comparator-if<=>
|
|
(syntax-rules ()
|
|
((comparator-if<=> comparator obj1 obj2 less equal greater)
|
|
(let ((cmp comparator)
|
|
(o1 obj1)
|
|
(o2 obj2))
|
|
(cond
|
|
(((comparator-equality-predicate cmp) o1 o2) equal)
|
|
(((comparator-ordering-predicate cmp) o1 o2) less)
|
|
(else greater))))
|
|
((comparator-if<=> obj1 obj2 less equal greater)
|
|
(comparator-if<=> (make-default-comparator) obj1 obj2 less equal greater))))
|
|
|
|
(define (comparator-ordered? comparator)
|
|
(and (comparator-ordering-predicate comparator) #t))
|
|
|
|
(define (comparator-hashable? comparator)
|
|
(and (comparator-hash-function comparator) #t))
|
|
|
|
(define (comparator-test-type comparator obj)
|
|
((comparator-type-test-predicate comparator) obj))
|
|
|
|
(define (comparator-check-type comparator obj)
|
|
(or (comparator-test-type comparator obj)
|
|
(error "not an object of the comparator type" comparator obj)))
|
|
|
|
(define (comparator-hash comparator obj)
|
|
((comparator-hash-function comparator) obj))
|
|
|
|
(define default-comparators
|
|
(make-parameter '()))
|
|
|
|
(define (comparator-register-default! comparator)
|
|
(default-comparators (cons comparator (default-comparators))))
|
|
|
|
(define (make-pair-comparator car-comparator cdr-comparator)
|
|
(make-comparator
|
|
(lambda (x)
|
|
(and (pair? x)
|
|
((comparator-type-test-predicate car-comparator) (car x))
|
|
((comparator-type-test-predicate cdr-comparator) (cdr x))))
|
|
(lambda (x y)
|
|
(and ((comparator-equality-predicate car-comparator) (car x) (car y))
|
|
((comparator-equality-predicate cdr-comparator) (cdr x) (cdr y))))
|
|
(lambda (x y)
|
|
(if ((comparator-equality-predicate car-comparator) (car x) (car y))
|
|
((comparator-ordering-predicate cdr-comparator) (cdr x) (cdr y))
|
|
((comparator-ordering-predicate car-comparator) (car x) (car y))))
|
|
(lambda (x)
|
|
(bitwise-xor ((comparator-hash-function car-comparator) (car x))
|
|
((comparator-hash-function cdr-comparator) (cdr x))))))
|
|
|
|
(define (make-list-comparator element-comparator type-test empty? head tail)
|
|
(make-comparator
|
|
(lambda (x)
|
|
(and (type-test x)
|
|
(let lp ((ls x))
|
|
(or (empty? ls)
|
|
(and ((comparator-type-test-predicate element-comparator) (head ls))
|
|
(lp (tail ls)))))))
|
|
(lambda (x y)
|
|
(let lp ((ls1 x) (ls2 y))
|
|
(cond
|
|
((empty? ls1) (empty? ls2))
|
|
((empty? ls2) #f)
|
|
(else
|
|
(and ((comparator-equality-predicate element-comparator) (head ls1) (head ls2))
|
|
(lp (tail ls1) (tail ls2)))))))
|
|
(lambda (x y)
|
|
(let lp ((ls1 x) (ls2 y))
|
|
(cond
|
|
((empty? ls1) (not (empty? ls2)))
|
|
((empty? ls2) #f)
|
|
(else
|
|
(let ((a (head ls1)) (b (head ls2)))
|
|
(if ((comparator-equality-predicate element-comparator) a b)
|
|
(lp (tail ls1) (tail ls2))
|
|
((comparator-ordering-predicate element-comparator) a b)))))))
|
|
(lambda (x)
|
|
(let lp ((ls x) (acc 0))
|
|
(if (empty? ls)
|
|
acc
|
|
(lp (tail ls)
|
|
(bitwise-xor ((comparator-hash-function element-comparator) (head ls))
|
|
acc)))))
|
|
))
|
|
|
|
(define (make-vector-comparator element-comparator type-test length ref)
|
|
(make-comparator
|
|
(lambda (x)
|
|
(and (type-test x)
|
|
(let ((len (length x)))
|
|
(let lp ((i 0))
|
|
(or (>= i len)
|
|
(and ((comparator-type-test-predicate element-comparator) (ref x i))
|
|
(lp (+ i 1))))))))
|
|
(lambda (x y)
|
|
(let ((lenx (length x)) (leny (length y)))
|
|
(and
|
|
(= lenx leny)
|
|
(let lp ((i 0))
|
|
(or (>= i lenx)
|
|
(let ((a (ref x i)) (b (ref y i)))
|
|
(and ((comparator-equality-predicate element-comparator) a b)
|
|
(lp (+ i 1)))))))))
|
|
(lambda (x y)
|
|
(let ((lenx (length x)) (leny (length y)))
|
|
(cond
|
|
((< lenx leny) #t)
|
|
((> lenx leny) #f)
|
|
(else
|
|
(let lp ((i 0))
|
|
(and (< i lenx)
|
|
(let ((a (ref x i)) (b (ref y i)))
|
|
(if ((comparator-equality-predicate element-comparator) a b)
|
|
(lp (+ i 1))
|
|
((comparator-ordering-predicate element-comparator) a b)))))))))
|
|
(lambda (x)
|
|
(let ((len (length x)))
|
|
(let lp ((i 0) (acc 0))
|
|
(if (>= i len)
|
|
acc
|
|
(lp (+ i 1)
|
|
(bitwise-xor ((comparator-hash-function element-comparator) (ref x i))
|
|
acc))))))
|
|
))
|
|
|
|
(define (make-eq-comparator)
|
|
(make-comparator (lambda (x) #t) eq? object-cmp hash-by-identity))
|
|
|
|
(define (make-eqv-comparator)
|
|
(make-comparator (lambda (x) #t) eqv? object-cmp hash))
|
|
|
|
(define (make-equal-comparator)
|
|
(make-comparator (lambda (x) #t) equal? object-cmp hash))
|
|
|
|
(define boolean-hash hash)
|
|
|
|
(define char-hash hash)
|
|
|
|
(define (char-ci-hash ch)
|
|
(hash (char-foldcase ch)))
|
|
|
|
(define symbol-hash hash)
|
|
|
|
(define number-hash hash)
|
|
|
|
(define (default-hash x . o)
|
|
(if (string? x) (string-hash x) (hash x)))
|
|
|
|
(define default-comparator
|
|
(make-comparator
|
|
(lambda (x) #t)
|
|
(lambda (x y)
|
|
(let lp ((ls (default-comparators)))
|
|
(cond ((null? ls)
|
|
(if (number? x)
|
|
(and (number? y) (= x y))
|
|
(equal? x y)))
|
|
((and (comparator-test-type (car ls) x)
|
|
(comparator-test-type (car ls) y))
|
|
((comparator-equality-predicate (car ls)) x y))
|
|
(else
|
|
(lp (cdr ls))))))
|
|
(lambda (x y)
|
|
(let lp ((ls (default-comparators)))
|
|
(cond ((null? ls)
|
|
(negative? (object-cmp x y)))
|
|
((and (comparator-test-type (car ls) x)
|
|
(comparator-test-type (car ls) y))
|
|
((comparator-ordering-predicate (car ls)) x y))
|
|
(else
|
|
(lp (cdr ls))))))
|
|
default-hash))
|
|
|
|
(define (make-default-comparator)
|
|
default-comparator)
|
|
|
|
(define (=? comparator o1 o2 . o)
|
|
(let ((eq (comparator-equality-predicate comparator)))
|
|
(and (eq o1 o2)
|
|
(let lp ((ls o))
|
|
(or (null? ls)
|
|
(and (eq o1 (car ls))
|
|
(lp (cdr ls))))))))
|
|
|
|
(define (<? comparator o1 o2 . o)
|
|
(let ((less (comparator-ordering-predicate comparator)))
|
|
(and (less o1 o2)
|
|
(let lp ((prev o2) (ls o))
|
|
(or (null? ls)
|
|
(and (less prev (car ls))
|
|
(lp (car ls) (cdr ls))))))))
|
|
|
|
(define (<=? comparator o1 o2 . o)
|
|
(let ((less (comparator-ordering-predicate comparator)))
|
|
(and (not (less o2 o1))
|
|
(let lp ((prev o2) (ls o))
|
|
(or (null? ls)
|
|
(and (not (less (car ls) prev))
|
|
(lp (car ls) (cdr ls))))))))
|
|
|
|
(define (>? comparator . o)
|
|
(apply <? comparator (reverse o)))
|
|
|
|
(define (>=? comparator . o)
|
|
(apply <=? comparator (reverse o)))
|