;;; Copyright (C) John Cowan (2015). All Rights Reserved. ;;; ;;; Permission is hereby granted, free of charge, to any person ;;; obtaining a copy of this software and associated documentation ;;; files (the "Software"), to deal in the Software without ;;; restriction, including without limitation the rights to use, ;;; copy, modify, merge, publish, distribute, sublicense, and/or ;;; sell copies of the Software, and to permit persons to whom the ;;; Software is furnished to do so, subject to the following ;;; conditions: ;;; ;;; The above copyright notice and this permission notice shall be ;;; included in all copies or substantial portions of the Software. ;;; ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ;;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ;;; OTHER DEALINGS IN THE SOFTWARE. ;;;; Main part of the SRFI 114 reference implementation ;;; "There are two ways of constructing a software design: One way is to ;;; make it so simple that there are obviously no deficiencies, and the ;;; other way is to make it so complicated that there are no *obvious* ;;; deficiencies." --Tony Hoare ;;; Syntax (because syntax must be defined before it is used, contra Dr. Hardcase) ;; Arithmetic if (define-syntax comparator-if<=> (syntax-rules () ((if<=> a b less equal greater) (comparator-if<=> (make-default-comparator) a b less equal greater)) ((comparator-if<=> comparator a b less equal greater) (cond ((=? comparator a b) equal) ((? comparator a b) (binary? comparator a b))) (define (binary>=? comparator a b) (not (binary? comparator a b . objs) (let loop ((a a) (b b) (objs objs)) (and (binary>? comparator a b) (if (null? objs) #t (loop b (car objs) (cdr objs)))))) (define (<=? comparator a b . objs) (let loop ((a a) (b b) (objs objs)) (and (binary<=? comparator a b) (if (null? objs) #t (loop b (car objs) (cdr objs)))))) (define (>=? comparator a b . objs) (let loop ((a a) (b b) (objs objs)) (and (binary>=? comparator a b) (if (null? objs) #t (loop b (car objs) (cdr objs)))))) ;;; Simple ordering and hash functions (define (booleaninteger obj)) (hash-bound))) (define (char-ci-hash obj) (modulo (* (%salt%) (char->integer (char-foldcase obj))) (hash-bound))) (define (number-hash obj) (cond ((nan? obj) (%salt%)) ((and (infinite? obj) (positive? obj)) (* 2 (%salt%))) ((infinite? obj) (* (%salt%) 3)) ((real? obj) (abs (exact (round obj)))) (else (+ (number-hash (real-part obj)) (number-hash (imag-part obj)))))) ;; Lexicographic ordering of complex numbers (define (complexstring a) (symbol->string b))) (define (symbol-hash obj) (string-hash (symbol->string obj))) ;;; Wrapped equality predicates ;;; These comparators don't have ordering functions. (define (make-eq-comparator) (make-comparator #t eq? #f default-hash)) (define (make-eqv-comparator) (make-comparator #t eqv? #f default-hash)) (define (make-equal-comparator) (make-comparator #t equal? #f default-hash)) ;;; Sequence ordering and hash functions ;; The hash functions are based on djb2, but ;; modulo 2^25 instead of 2^32 in hopes of sticking to fixnums. (define (make-hasher) (let ((result (%salt%))) (case-lambda (() result) ((n) (set! result (+ (modulo (* result 33) (hash-bound)) n)) result)))) ;;; Pair comparator (define (make-pair-comparator car-comparator cdr-comparator) (make-comparator (make-pair-type-test car-comparator cdr-comparator) (make-pair=? car-comparator cdr-comparator) (make-pair (length a) (length b)) #f) (else (let ((elem=? (comparator-equality-predicate element-comparator)) (eleminteger (string-ref obj n))) (loop (+ n 1)))))))