From 432dfcdb4a7d912c1559eb1d23f2400925001400 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Tue, 27 Nov 2018 17:42:18 -0700 Subject: [PATCH] hash-{map,for-each}: strengthen `try-order?` guarantee Promise a specific order for a hash table that uses only certain primitive, non-compound datatypes for keys. --- pkgs/base/info.rkt | 2 +- .../scribblings/reference/hashes.scrbl | 31 +++- pkgs/racket-test-core/tests/racket/hash.rktl | 53 +++++- racket/src/cs/rumble/hash.ss | 50 +++++- racket/src/racket/src/schpriv.h | 3 + racket/src/racket/src/schvers.h | 4 +- racket/src/racket/src/sort.c | 154 ++++++++++++++---- racket/src/racket/src/string.c | 15 ++ 8 files changed, 265 insertions(+), 47 deletions(-) diff --git a/pkgs/base/info.rkt b/pkgs/base/info.rkt index 61e2738bb2..2ef83ae057 100644 --- a/pkgs/base/info.rkt +++ b/pkgs/base/info.rkt @@ -12,7 +12,7 @@ (define collection 'multi) -(define version "7.1.0.6") +(define version "7.1.0.7") (define deps `("racket-lib" ["racket" #:version ,version])) diff --git a/pkgs/racket-doc/scribblings/reference/hashes.scrbl b/pkgs/racket-doc/scribblings/reference/hashes.scrbl index 3243d58ed5..6e500f552d 100644 --- a/pkgs/racket-doc/scribblings/reference/hashes.scrbl +++ b/pkgs/racket-doc/scribblings/reference/hashes.scrbl @@ -384,14 +384,30 @@ change does not affect a traversal if the key has been seen already, otherwise the traversal skips a deleted key or uses the remapped key's new value. -If @racket[try-order?] is true, then the order of keys and values -passed to @racket[proc] is normalized under certain circumstances, -such as when the keys are all symbols and @racket[hash] is not an -@tech{impersonator}. - @see-also-concurrency-caveat[] -@history[#:changed "6.3" @elem{Added the @racket[try-order?] argument.}]} +If @racket[try-order?] is true, then the order of keys and values +passed to @racket[proc] is normalized under certain +circumstances---including when every key is one of the following and +with the following order (earlier bullets before later): + +@itemlist[ + @item{@tech{booleans} sorted @racket[#f] before @racket[#t];} + @item{@tech{characters} sorted by @racket[charuninterned-symbol "apple")] + [u/banana (string->uninterned-symbol "banana")] + [u/coconut (string->uninterned-symbol "coconut")] + [apple (string->unreadable-symbol "apple")] + [banana (string->unreadable-symbol "banana")] + [coconut (string->unreadable-symbol "coconut")]) + (test (list #f #t + #\a #\b #\c #\u3BB + (- (expt 2 79)) + -3 -2 -1 + 0 + 1/2 0.75 8.5f-1 + 1 2 3 + (expt 2 79) + u/apple u/banana u/coconut + apple banana coconut + 'apple 'banana 'coconut 'coconut+ + '#:apple '#:banana '#:coconut + "Apple" + "apple" "banana" "coconut" + #"Apple" + #"apple" #"banana" #"coconut" + null + (void) + eof) + 'ordered + (hash-map (hash #t 'x + #f 'x + #\a 'a #\b 'b #\c 'c #\u3BB 'lam + 1 'a 2 'b 3 'c + 1/2 'n 0.75 'n 8.5f-1 'n + 0 'z + -1 'a -2 'b -3 'c + (expt 2 79) 'b + (- (expt 2 79)) 'b + "Apple" 'a + "apple" 'a "banana" 'b "coconut" 'c + #"Apple" 'a + #"apple" 'a #"banana" 'b #"coconut" 'c + u/apple 'a u/banana 'b u/coconut 'c + apple 'a banana 'b coconut 'c + 'apple 'a 'banana 'b 'coconut 'c 'coconut+ '+ + '#:apple 'a '#:banana 'b '#:coconut 'c + null 'one + (void) 'one + eof 'one) + (lambda (k v) k) + #t))) + ;; ---------------------------------------- (test #hash([4 . four] [3 . three] [1 . one] [2 . two]) @@ -412,7 +464,6 @@ (hash-remove-iterate-test* [make-weak-hash make-weak-hasheq make-weak-hasheqv] (p) in-hash-pairs in-weak-hash-pairs car) - ;; ---------------------------------------- (report-errs) diff --git a/racket/src/cs/rumble/hash.ss b/racket/src/cs/rumble/hash.ss index 7a4417ec0e..293997a758 100644 --- a/racket/src/cs/rumble/hash.ss +++ b/racket/src/cs/rumble/hash.ss @@ -320,12 +320,54 @@ ;; deterministic, especially for marshaling operations. (define (try-sort-keys ps) (cond - [(#%andmap (lambda (p) (symbol? (car p))) ps) - (#%list-sort (lambda (a b) (symbol