From 050b7050e38dec3b8301356053582505f6677afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9ssica=20Milar=C3=A9?= Date: Fri, 11 Jan 2019 19:41:20 -0200 Subject: [PATCH 07/10] Implemented SRFI-128 --- module/Makefile.am | 2 + module/srfi/srfi-128.scm | 577 +++++++++++++++++++++++++++++++++ module/srfi/srfi-128/gnu.scm | 38 +++ test-suite/Makefile.am | 1 + test-suite/tests/srfi-128.test | 348 ++++++++++++++++++++ 5 files changed, 966 insertions(+) create mode 100644 module/srfi/srfi-128.scm create mode 100644 module/srfi/srfi-128/gnu.scm create mode 100644 test-suite/tests/srfi-128.test diff --git a/module/Makefile.am b/module/Makefile.am index 6e739fed0..5fc3010c1 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -295,6 +295,8 @@ SOURCES = \ srfi/srfi-98.scm \ srfi/srfi-111.scm \ srfi/srfi-126.scm \ + srfi/srfi-128/gnu.scm \ + srfi/srfi-128.scm \ \ statprof.scm \ \ diff --git a/module/srfi/srfi-128.scm b/module/srfi/srfi-128.scm new file mode 100644 index 000000000..bdacfb3c0 --- /dev/null +++ b/module/srfi/srfi-128.scm @@ -0,0 +1,577 @@ +;;; srfi-128.scm --- Comparators + +;; Copyright (C) 2019 Free Software Foundation, Inc. +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 3 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +;; This file contains code from SRFI 128 reference implementation, by +;; John Cowan + +;;; 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. + + +(define-module (srfi srfi-128) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-43) + ;; HASH-BOUND, HASH-SALT and WITH-HASH-SALT are defined here because + ;; the latter is not standard + #:use-module ((srfi srfi-128 gnu) #:select (hash-bound hash-salt)) + #:use-module ((rnrs unicode) #:select (char-foldcase)) + #:use-module (rnrs bytevectors) + #:use-module ((ice-9 generic-hash-tables) + #:select ((hash . equal-hash) + string-ci-hash hash-by-identity hash-by-value)) + #:export (comparator? + make-comparator + comparator-type-test-predicate comparator-equality-predicate + comparator-ordering-predicate comparator-hash-function + comparator-ordered? comparator-hashable? + comparator-test-type comparator-check-type + comparator-hash + make-pair-comparator make-list-comparator make-vector-comparator + make-eq-comparator make-eqv-comparator make-equal-comparator + boolean-hash char-hash char-ci-hash number-hash + make-default-comparator default-hash + comparator-register-default! + =? ? <=? >=? + comparator-if<=>) + #:re-export (string-hash string-ci-hash symbol-hash hash-bound hash-salt)) + +(cond-expand-provide (current-module) '(srfi-128)) + + +;; Arithmetic if +(define-syntax comparator-if<=> + (syntax-rules () + ((if<=> a b less equal greater) + (comparator-if<=> default-comparator a b less equal greater)) + ((comparator-if<=> comparator a b less equal greater) + (cond + ((? 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 boolean-hash hash-by-identity) +(define char-hash hash-by-identity) +(define number-hash hash-by-value) + +(define* (char-ci-hash c #:optional (size most-positive-fixnum)) + (hashq (char-foldcase c) size)) + +;; Lexicographic ordering of complex numbers +(define (complexstring a) (symbol->string b)))))) + +;; Stick to fixnums +(define lower-mask (ash (hash-bound) -5)) ; (/ (hash-bound) 32) + +;; Hash helper +(define (mix h1 h2) + (logxor (* (logand h1 lower-mask) 31) h2)) + + + +;;; 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 lena lenb) #f) + (else + (let loop ((n 0)) + (cond + ((= n lena) #f) + ((elem= type 9)) + (equal-hash obj) + (case type + ((7) (default-vector-hash obj)) + ((8) (default-pair-hash obj)) + ;; Add more here + )) + (let ((comparator (external-object-comparator obj))) + (comparator-hash comparator obj))))) + +(define (default-ordering a b) + (and (not (equal? a b)) ; should be much faster than this procedure + (let ((a-itype (internal-object-type a)) + (b-itype (internal-object-type b))) + (cond + ((not b-itype) + (or a-itype + ;; Neither a nor b are of internal type: + ;; dispatch ordering on external type + (let ((a-etype (external-object-type a)) + (b-etype (external-object-type b))) + (cond + ((< a-etype b-etype) #t) + ((> a-etype b-etype) #f) + (else (external-dispatch-ordering a-etype a b)))))) + ((not a-itype) #f) + ;; Both a and b are of internal type + ((< a-itype b-itype) #t) + ((> a-itype b-itype) #f) + (else (internal-dispatch-ordering a-itype a b)))))) + +(define (default-equality a b) + (or (equal? a b) ; should be much faster than this procedure + (let ((a-itype (internal-object-type a)) + (b-itype (internal-object-type b))) + (and (eqv? a-itype b-itype) + (if a-itype + (internal-dispatch-equality a-itype a b) + (let ((a-comp (external-object-comparator a)) + (b-comp (external-object-comparator b))) + (and (eq? a-comp b-comp) (binary=? a-comp a b)))))))) + +;; Note: comparators are immutable, no reason to allocate a new one +(define default-comparator (make-comparator always-true default-equality + default-ordering default-hash)) + +(define (make-default-comparator) default-comparator) + +(define default-pair-comparator + (make-pair-comparator default-comparator default-comparator)) + +(define default-pair=? + (comparator-equality-predicate default-pair-comparator)) +(define default-pairrandom-state (current-time))))) + +(define-syntax hash-salt + (syntax-rules () + ((hash-salt) (%salt%)))) + +(define-syntax with-hash-salt + (syntax-rules () + ((with-hash-salt new-salt hash-func obj) + (parameterize ((%salt% new-salt)) (hash-func obj))))) + +;; eof diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am index f0ad8bb91..a2f73b329 100644 --- a/test-suite/Makefile.am +++ b/test-suite/Makefile.am @@ -163,6 +163,7 @@ SCM_TESTS = tests/00-initial-env.test \ tests/srfi-105.test \ tests/srfi-111.test \ tests/srfi-126.test \ + tests/srfi-128.test \ tests/srfi-4.test \ tests/srfi-9.test \ tests/statprof.test \ diff --git a/test-suite/tests/srfi-128.test b/test-suite/tests/srfi-128.test new file mode 100644 index 000000000..02a538e22 --- /dev/null +++ b/test-suite/tests/srfi-128.test @@ -0,0 +1,348 @@ +;;;; srfi-128.test --- Test suite for SRFI 128 -*- scheme -*- +;;;; +;;;; Copyright (C) 2019 Free Software Foundation, Inc. +;;;; +;;;; This library is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU Lesser General Public +;;;; License as published by the Free Software Foundation; either +;;;; version 3 of the License, or (at your option) any later version. +;;;; +;;;; This library is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;;; Lesser General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU Lesser General Public +;;;; License along with this library; if not, write to the Free Software +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +;;; The following tests are the tests from SRFI-126 reference +;;; implementation ported to Guile test suite. + +;; This file contains code from SRFI 128 reference implementation, by +;; John Cowan + +;;; 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. + +(define-module (test-srfi-128) + #:use-module (test-suite lib) + #:use-module (srfi srfi-128) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-2) + #:use-module (srfi srfi-8) + #:use-module (rnrs bytevectors)) + +(define (vector-cdr vec) + (let* ((len (vector-length vec)) + (result (make-vector (- len 1)))) + (let loop ((n 1)) + (cond + ((= n len) result) + (else (vector-set! result (- n 1) (vector-ref vec n)) + (loop (+ n 1))))))) + +(define default-comparator (make-default-comparator)) + +(define real-comparator (make-comparator real? = < number-hash)) + +(define degenerate-comparator (make-comparator (lambda (x) #t) equal? #f #f)) + +(define boolean-comparator + (make-comparator boolean? eq? (lambda (x y) (and (not x) y)) boolean-hash)) + +(define bool-pair-comparator + (make-pair-comparator boolean-comparator boolean-comparator)) + +(define num-list-comparator + (make-list-comparator real-comparator list? null? car cdr)) + +(define num-vector-comparator + (make-vector-comparator real-comparator vector? vector-length vector-ref)) + +(define vector-qua-list-comparator + (make-list-comparator + real-comparator + vector? + (lambda (vec) (= 0 (vector-length vec))) + (lambda (vec) (vector-ref vec 0)) + vector-cdr)) + +(define list-qua-vector-comparator + (make-vector-comparator default-comparator list? length list-ref)) + +(define eq-comparator (make-eq-comparator)) + +(define eqv-comparator (make-eqv-comparator)) + +(define equal-comparator (make-equal-comparator)) + +(define symbol-comparator + (make-comparator + symbol? + eq? + (lambda (a b) (stringstring a) (symbol->string b))) + symbol-hash)) + + +(with-test-prefix "SRFI-128" + + (pass-if-equal '#(2 3 4) (vector-cdr '#(1 2 3 4))) + (pass-if-equal '#() (vector-cdr '#(1))) + + (with-test-prefix "comparators/predicates" + (pass-if (comparator? real-comparator)) + (pass-if (not (comparator? =))) + (pass-if (comparator-ordered? real-comparator)) + (pass-if (comparator-hashable? real-comparator)) + (pass-if (not (comparator-ordered? degenerate-comparator))) + (pass-if (not (comparator-hashable? degenerate-comparator))) + ) ; end comparators/predicates + + (with-test-prefix "comparators/constructors" + (pass-if (=? boolean-comparator #t #t)) + (pass-if (not (=? boolean-comparator #t #f))) + (pass-if (? real-comparator 4.0 3.0 2)) + (pass-if (<=? real-comparator 2.0 2 3.0)) + (pass-if (>=? real-comparator 3 3.0 2)) + (pass-if (not (=? real-comparator 1 2 3))) + (pass-if (not (? real-comparator 1 2 3))) + (pass-if (not (<=? real-comparator 4 3 3))) + (pass-if (not (>=? real-comparator 3 4 4.0))) + + ) ; end comparators/comparison + + (with-test-prefix "comparators/syntax" + (pass-if-equal 'less (comparator-if<=> real-comparator 1 2 'less 'equal 'greater)) + (pass-if-equal 'equal (comparator-if<=> real-comparator 1 1 'less 'equal 'greater)) + (pass-if-equal 'greater (comparator-if<=> real-comparator 2 1 'less 'equal 'greater)) + (pass-if-equal 'less (comparator-if<=> "1" "2" 'less 'equal 'greater)) + (pass-if-equal 'equal (comparator-if<=> "1" "1" 'less 'equal 'greater)) + (pass-if-equal 'greater (comparator-if<=> "2" "1" 'less 'equal 'greater)) + + ) ; end comparators/syntax + + (with-test-prefix "comparators/bound-salt" + (pass-if (exact-integer? (hash-bound))) + (pass-if (exact-integer? (hash-salt))) + (pass-if (< (hash-salt) (hash-bound))) + #; (pass-if-equal (hash-salt) (fake-salt-hash #t)) ; no such thing as fake-salt-hash + ) ; end comparators/bound-salt + ) -- 2.19.1