Eli's repaired and specialized sort, fix in 'for/fold' binding, generalized integers-bytes functions, and some r6rs work

svn: r8798
This commit is contained in:
Matthew Flatt 2008-02-25 14:42:32 +00:00
parent 871bb0bac5
commit 8311c8f9e4
9 changed files with 1081 additions and 333 deletions

View File

@ -22,7 +22,7 @@
-1
(let loop ([b b][pos 0])
(if (zero? (bitwise-and b 1))
(loop (arithmetic-shift b) (add1 pos))
(loop (arithmetic-shift b -1) (add1 pos))
pos))))

View File

@ -0,0 +1,405 @@
#lang scheme/base
(require rnrs/enums-6)
(provide endianness
native-endianness
(rename-out [bytes? bytevector?]
[bytes-length bytevector-length]
[bytes=? bytevector=?]
[bytes-copy! bytevector-copy!]
[bytes-copy bytevector-copy]
[bytes-ref bytevector-u8-ref]
[bytes-set! bytevector-u8-set!]
[bytes->list bytevector->u8-list]
[list->bytes u8-list->bytevector])
make-bytevector
bytevector-fill!
bytevector-s8-ref
bytevector-s8-set!
bytevector-u16-ref
bytevector-s16-ref
bytevector-u16-native-ref
bytevector-s16-native-ref
bytevector-u16-set!
bytevector-s16-set!
bytevector-u16-native-set!
bytevector-s16-native-set!
bytevector-u32-ref
bytevector-s32-ref
bytevector-u32-native-ref
bytevector-s32-native-ref
bytevector-u32-set!
bytevector-s32-set!
bytevector-u32-native-set!
bytevector-s32-native-set!
bytevector-u64-ref
bytevector-s64-ref
bytevector-u64-native-ref
bytevector-s64-native-ref
bytevector-u64-set!
bytevector-s64-set!
bytevector-u64-native-set!
bytevector-s64-native-set!
bytevector-uint-ref
bytevector-sint-ref
bytevector-uint-set!
bytevector-sint-set!
string->utf8
string->utf16
string->utf32
utf8->string
utf16->string
utf32->string)
(define-enumeration endianness (big little) endianness-set)
(define (native-endianness)
(if (system-big-endian?)
(endianness big)
(endianness little)))
(define (make-bytevector k [fill 0])
(make-bytes k (convert-fill 'make-bytevector fill)))
(define (convert-fill who fill)
(cond
[(byte? fill) fill]
[(and (exact-integer? fill)
(<= -128 fill -1))
(+ fill 256)]
[else (raise-type-error who
"exact integer in [128, 255]"
fill)]))
(define (bytevector-fill! bytes [fill 0])
(bytes-fill! bytes (convert-fill 'bytevector-fill! fill)))
;; ----------------------------------------
(define (bytevector-s8-ref bytes k)
(let ([v (bytes-ref bytes k)])
(if (v . > . 127)
(- v 256)
v)))
(define (bytevector-s8-set! bytes k)
(bytes-set! bytes (convert-fill 'bytevector-s8-set! k)))
(define (check-endian endianness)
(unless (or (eq? endianness 'little)
(eq? endianness 'big))
(raise-type-error 'bytevector-operation "'big or 'little" endianness)))
(define (make-integer-ops size)
(values
;; uXX-ref
(lambda (bytes k endianness)
(check-endian endianness)
(integer-bytes->integer bytes #f (eq? endianness 'big) k (+ k size)))
;; sXX-ref
(lambda (bytes k endianness)
(check-endian endianness)
(integer-bytes->integer bytes #t (eq? endianness 'big) k (+ k size)))
;; uXX-native-ref
(lambda (bytes k)
(integer-bytes->integer bytes #f (system-big-endian?) k (+ k size)))
;; sXX-native-ref
(lambda (bytes k)
(integer-bytes->integer bytes #t (system-big-endian?) k (+ k size)))
;; uXX-set!
(lambda (bytes k n endianness)
(check-endian endianness)
(integer->integer-bytes n size #f (eq? endianness 'big) bytes k)
(void))
;; sXX-set!
(lambda (bytes k n endianness)
(check-endian endianness)
(integer->integer-bytes n size #t (eq? endianness 'big) bytes k)
(void))
;; uXX-native-set!
(lambda (bytes k n)
(integer->integer-bytes n size #f (system-big-endian?) bytes k)
(void))
;; sXX-native-set!
(lambda (bytes k n)
(integer->integer-bytes n size #t (system-big-endian?) bytes k)
(void))))
(define-values (bytevector-u16-ref
bytevector-s16-ref
bytevector-u16-native-ref
bytevector-s16-native-ref
bytevector-u16-set!
bytevector-s16-set!
bytevector-u16-native-set!
bytevector-s16-native-set!)
(make-integer-ops 2))
(define-values (bytevector-u32-ref
bytevector-s32-ref
bytevector-u32-native-ref
bytevector-s32-native-ref
bytevector-u32-set!
bytevector-s32-set!
bytevector-u32-native-set!
bytevector-s32-native-set!)
(make-integer-ops 4))
(define-values (bytevector-u64-ref
bytevector-s64-ref
bytevector-u64-native-ref
bytevector-s64-native-ref
bytevector-u64-set!
bytevector-s64-set!
bytevector-u64-native-set!
bytevector-s64-native-set!)
(make-integer-ops 8))
;; ----------------------------------------
(define (bytevector-int-ref who bstr k endianness size)
(unless (bytes? bstr)
(raise-type-error who "bytevector" bstr))
(unless (exact-nonnegative-integer? k)
(raise-type-error who "exact nonnegative integer" k))
(check-endian endianness)
(unless (exact-positive-integer? size)
(raise-type-error who "exact positive integer" size))
(unless (<= (+ k size) (bytes-length bstr))
(error who "specified range [~a, ~a) beyond string range [0, ~a)"
k (+ k size) (bytes-length bstr)))
(for/fold ([r 0])
([i (in-range size)])
(+ (arithmetic-shift r 8)
(bytes-ref bstr (+ (if (eq? endianness 'big)
i
(- size i 1))
k)))))
(define (bytevector-uint-ref bstr k endianness size)
(bytevector-int-ref 'bytevector-uint-ref bstr k endianness size))
(define (bytevector-sint-ref bstr k endianness size)
(let ([v (bytevector-int-ref 'bytevector-sint-ref bstr k endianness size)]
[max (sub1 (arithmetic-shift 1 (sub1 (* size 8))))])
(if (v . > . max)
(- v (* 2 (add1 max)))
v)))
(define (bytevector-int-set! who bstr k n orig-n endianness size bit-size)
(unless (bytes? bstr)
(raise-type-error who "bytevector" bstr))
(unless (exact-nonnegative-integer? k)
(raise-type-error who "exact nonnegative integer" k))
(check-endian endianness)
(unless (exact-positive-integer? size)
(raise-type-error who "exact positive integer" size))
(unless (<= (+ k size) (bytes-length bstr))
(error who "specified target range [~a, ~a) beyond string range [0, ~a)"
k (+ k size) (bytes-length bstr)))
(unless ((integer-length orig-n) . <= . bit-size)
(error who "integer does not fit into ~a bytes: ~e"
size orig-n))
(for/fold ([n n])
([i (in-range size)])
(bytes-set! bstr (+ (if (eq? endianness 'little)
i
(- size i 1))
k)
(bitwise-and n 255))
(arithmetic-shift n -8))
(void))
(define (bytevector-uint-set! bstr k n endianness size)
(unless (exact-nonnegative-integer? n)
(raise-type-error 'bytevector-uint-set! "exact nonnegative integer" n))
(bytevector-int-set! 'bytevector-uint-set! bstr k n n endianness size (* size 8)))
(define (bytevector-sint-set! bstr k n endianness size)
(let ([pos-n (if (negative? n)
(+ n (arithmetic-shift 1 (* 8 size)))
n)])
(bytevector-int-set! 'bytevector-uint-set! bstr k pos-n n endianness size (* size (sub1 8)))))
;; ----------------------------------------
(define (string->utf8 str)
(string->bytes/utf-8 str))
(define (string->utf16 str [endianness 'big])
(check-endian endianness)
(let ([big? (eq? endianness 'big)])
(let loop ([pos (string-length str)]
[accum null])
(if (zero? pos)
(list->bytes accum)
(let* ([pos (sub1 pos)]
[c (string-ref str pos)]
[v (char->integer c)])
(if (v . >= . #x10000)
(let ([v2 (- v #x10000)])
(let-values ([(a b c d)
(values (bitwise-ior #xD8
(arithmetic-shift v2 -18))
(bitwise-and #xFF
(arithmetic-shift v2 -10))
(bitwise-ior #xDC
(bitwise-and #x3
(arithmetic-shift v2 -8)))
(bitwise-and v2 #xFF))])
(if big?
(loop pos (list* a b c d accum))
(loop pos (list* b a d c accum)))))
(let-values ([(hi lo)
(values (arithmetic-shift v -8)
(bitwise-and v 255))])
(if big?
(loop pos (list* hi lo accum))
(loop pos (list* lo hi accum))))))))))
(define (string->utf32 str [endianness 'big])
(check-endian endianness)
(let ([bstr (make-bytes (* 4 (string-length str)))]
[big? (eq? endianness 'big)])
(for ([c (in-string str)]
[i (in-naturals)])
(let* ([v (char->integer c)]
[a (arithmetic-shift v -24)]
[b (bitwise-and #xFF (arithmetic-shift v -16))]
[c (bitwise-and #xFF (arithmetic-shift v -8))]
[d (bitwise-and #xFF v)]
[pos (* i 4)])
(if big?
(begin
(bytes-set! bstr pos a)
(bytes-set! bstr (+ 1 pos) b)
(bytes-set! bstr (+ 2 pos) c)
(bytes-set! bstr (+ 3 pos) d))
(begin
(bytes-set! bstr pos d)
(bytes-set! bstr (+ 1 pos) c)
(bytes-set! bstr (+ 2 pos) b)
(bytes-set! bstr (+ 3 pos) a)))))
bstr))
(define (utf8->string bstr)
(bytes->string/utf-8 bstr #\uFFFD))
(define (utf16->string bstr endianness [skip-bom? #f])
;; This version skips a two bytes for decoding errors,
;; except those that correspond to a trailing single byte.
(check-endian endianness)
(let ([len (bytes-length bstr)])
(let-values ([(big? offset)
(cond
[skip-bom?
(values (eq? endianness 'big) 0)]
[(len . >= . 2)
(cond
[(and (eq? #xFE (bytes-ref bstr 0))
(eq? #xFF (bytes-ref bstr 1)))
(values #t 2)]
[(and (eq? #xFF (bytes-ref bstr 0))
(eq? #xFE (bytes-ref bstr 1)))
(values #t 1)]
[else (values (eq? endianness 'big) 0)])]
[else (values (eq? endianness 'big) 0)])])
(list->string
(let loop ([pos offset])
(cond
[(= pos len) null]
[(= (add1 pos) len)
;; decoding error
'(#\uFFFD)]
[else
(let ([a (bytes-ref bstr pos)]
[b (bytes-ref bstr (add1 pos))])
(let ([a (if big? a b)]
[b (if big? b a)])
(cond
[(= (bitwise-and a #xD8) #xD8)
(if (len . < . (+ pos 4))
;; decoding error
(cons #\uFFFD (loop (+ pos 2)))
;; Surrogate...
(let ([c (bytes-ref bstr (+ pos 2))]
[d (bytes-ref bstr (+ pos 3))])
(let ([c (if big? c d)]
[d (if big? d c)])
(cond
[(= (bitwise-and c #xDC) #xDC)
;; A valid surrogate
(let ([v (+ #x10000
(bitwise-ior
(arithmetic-shift (bitwise-and #x3 a) 18)
(arithmetic-shift b 10)
(arithmetic-shift (bitwise-and #x3 c) 8)
d))])
(cons (integer->char v) (loop (+ pos 4))))]
[else
;; Invalid surrogate.
(cons #\uFFFD (loop (+ pos 2)))]))))]
[(= (bitwise-and a #xDC) #xDC)
;; invalid surrogate code
(cons #\uFFFD (loop (+ pos 2)))]
[else
(let ([v (bitwise-ior (arithmetic-shift a 8)
b)])
(cons (integer->char v)
(loop (+ pos 2))))])))]))))))
(define (utf32->string bstr endianness [skip-bom? #f])
;; Skips 4 bytes for each dcoding error (except too-few-bytes-at-end
;; errors, obviously).
(check-endian endianness)
(let ([len (bytes-length bstr)])
(let-values ([(big? offset)
(cond
[skip-bom?
(values (eq? endianness 'big) 0)]
[(and (len . >= . 4)
(eq? #x00 (bytes-ref bstr 0))
(eq? #x00 (bytes-ref bstr 1)))
(cond
[(and (eq? #xFE (bytes-ref bstr 2))
(eq? #xFF (bytes-ref bstr 3)))
(values #t 2)]
[(and (eq? #xFF (bytes-ref bstr 2))
(eq? #xFE (bytes-ref bstr 3)))
(values #t 1)]
[else (values (eq? endianness 'big) 0)])]
[else (values (eq? endianness 'big) 0)])])
(list->string
(let loop ([pos offset])
(cond
[(= pos len) null]
[((+ pos 4) . > . len)
;; decoding error
'(#\uFFFD)]
[else
(let ([a (bytes-ref bstr pos)]
[b (bytes-ref bstr (+ pos 1))]
[c (bytes-ref bstr (+ pos 2))]
[d (bytes-ref bstr (+ pos 3))])
(let ([a (if big? a d)]
[b (if big? b c)]
[c (if big? c b)]
[d (if big? d a)])
(let ([v (bitwise-ior
(arithmetic-shift a 24)
(arithmetic-shift b 16)
(arithmetic-shift c 8)
d)])
(if (or (and (v . >= . #xD800)
(v . <= . #xDFFF))
(v . > . #x10FFFF))
(cons #\uFFFD (loop (+ pos 4)))
(cons (integer->char v) (loop (+ pos 4)))))))]))))))

240
collects/rnrs/enums-6.ss Normal file
View File

@ -0,0 +1,240 @@
#lang scheme/base
(require scheme/mpair
rnrs/arithmetic/bitwise-6
(for-syntax scheme/base))
(provide make-enumeration
enum-set-universe
enum-set-indexer
enum-set-constructor
enum-set-member?
enum-set-subset?
enum-set=?
enum-set-union
enum-set-intersection
enum-set-difference
enum-set-complement
enum-set-projection
define-enumeration)
(define-struct enum-set (val ht))
(define (make-enumeration-universe enum)
(let ([bad (lambda ()
(raise-type-error
'make-enumeration
"list of symbols"
enum))])
(unless (mlist? enum) (bad))
(let ([enum (mlist->list enum)])
(unless (andmap symbol? enum) (bad))
(let ([ht (make-hash-table)])
(for ([s (in-list enum)])
(unless (hash-table-get ht s #f)
(hash-table-put! ht s (arithmetic-shift 1 (hash-table-count ht)))))
ht))))
(define (make-enumeration enum)
(let ([ht (make-enumeration-universe enum)])
(make-enum-set (sub1 (arithmetic-shift 1 (hash-table-count ht)))
ht)))
(define (enum-set-universe enum)
(unless (enum-set? enum)
(raise-type-error 'enum-set-universe
"enumeration set"
enum))
(let ([ht (enum-set-ht enum)])
(make-enum-set (sub1 (arithmetic-shift 1 (hash-table-count ht))) ht)))
(define (enum-set-indexer enum)
(unless (enum-set? enum)
(raise-type-error 'enum-set-indexer
"enumeration set"
enum))
(let ([ht (enum-set-ht enum)])
(lambda (sym)
(let ([v (hash-table-get ht sym #f)])
(if v
(bitwise-first-bit-set v)
(error 'generated-enum-set-indexer
(if (symbol? sym)
"symbol not in universe: ~e"
"not a symbol: ~e")
sym))))))
(define (enum-set-constructor enum)
(unless (enum-set? enum)
(raise-type-error 'enum-set-constructor
"enumeration set"
enum))
(let ([ht (enum-set-ht enum)])
(lambda (orig-syms)
(let loop ([syms orig-syms][val 0])
(cond
[(null? syms) (make-enum-set val ht)]
[(not (mpair? syms))
(raise-type-error 'make-enum-set
"list of symbols"
orig-syms)]
[(hash-table-get ht (mcar syms) #f)
=> (lambda (n)
(loop (mcdr syms) (bitwise-ior val n)))]
[else
(error 'make-enum-set
(if (symbol? (mcar syms))
"symbol not in universe: ~e"
"not a symbol: ~e")
(mcar syms))])))))
(define (enum-set-member? sym enum)
(unless (symbol? sym)
(raise-type-error 'enum-set-member?
"symbol"
sym))
(unless (enum-set? enum)
(raise-type-error 'enum-set-member?
"enumeration set"
enum))
(let ([v (hash-table-get (enum-set-ht enum) sym #f)])
(and v
(not (zero? (bitwise-and v (enum-set-val enum)))))))
(define (check-2-enums who enum1 enum2)
(unless (and (enum-set? enum1)
(enum-set? enum2))
(raise-type-error who
"enumeration set"
(if (enum-set? enum1)
enum2
enum1))))
(define (enum-set-subset? enum1 enum2)
(check-2-enums 'enum-set-subset? enum1 enum2)
(if (eq? (enum-set-ht enum1) (enum-set-ht enum2))
(= (enum-set-val enum1)
(bitwise-and (enum-set-val enum1) (enum-set-val enum2)))
(let ([ht2 (enum-set-ht enum2)]
[v1 (enum-set-val enum1)]
[v2 (enum-set-val enum2)])
(for/fold ([sub? #t])
(#:when sub?
[(key1 val1) (in-hash-table (enum-set-ht enum1))])
(or (zero? (bitwise-and v1 val1))
(let ([val2 (hash-table-get ht2 key1 #f)])
(and val2
(not (zero? (bitwise-and v2 val2))))))))))
(define (enum-set=? enum1 enum2)
(check-2-enums 'enum-set=? enum1 enum2)
(if (eq? (enum-set-ht enum1) (enum-set-ht enum2))
(= (enum-set-val enum1) (enum-set-val enum2))
(and (enum-set-subset? enum1 enum2)
(enum-set-subset? enum2 enum1))))
(define (check-2-enums/same who enum1 enum2)
(check-2-enums who enum1 enum2)
(unless (eq? (enum-set-ht enum1)
(enum-set-ht enum2))
(error who
"enumeration sets are not the same enumeration type: ~e ~e"
enum1 enum2)))
(define (enum-set-union enum1 enum2)
(check-2-enums/same 'enum-set-union enum1 enum2)
(make-enum-set (bitwise-ior (enum-set-val enum1)
(enum-set-val enum2))
(enum-set-ht enum1)))
(define (enum-set-intersection enum1 enum2)
(check-2-enums/same 'enum-set-intersection enum1 enum2)
(make-enum-set (bitwise-and (enum-set-val enum1)
(enum-set-val enum2))
(enum-set-ht enum1)))
(define (enum-set-difference enum1 enum2)
(check-2-enums/same 'enum-set-intersection enum1 enum2)
(make-enum-set (- (enum-set-val enum1)
(bitwise-and (enum-set-val enum1)
(enum-set-val enum2)))
(enum-set-ht enum1)))
(define (enum-set-complement enum1)
(unless (enum-set? enum1)
(raise-type-error 'enum-set-complement
"enumeration set"
enum1))
(make-enum-set (bitwise-xor (sub1 (arithmetic-shift
1
(hash-table-count (enum-set-ht enum1))))
(enum-set-val enum1))
(enum-set-ht enum1)))
(define (enum-set-projection enum1 enum2)
(check-2-enums 'enum-set-projection enum1 enum2)
(let ([ht2 (enum-set-ht enum2)]
[v1 (enum-set-val enum1)]
[v2 (enum-set-val enum2)])
(make-enum-set
(for/fold ([val 0])
([(key1 val1) (in-hash-table (enum-set-ht enum1))])
(if (zero? (bitwise-and v1 val1))
val
(let ([val2 (hash-table-get ht2 key1 #f)])
(if val2
(bitwise-ior val val2)
val))))
ht2)))
(define-syntax (define-enumeration stx)
(syntax-case stx ()
[(_ type-name (sym ...) constructor)
(let ([syms (syntax->list #'(sym ...))]
[ht (make-hash-table)])
(unless (identifier? #'type-name)
(raise-syntax-error #f
"not an identifier for type name"
stx
#'type-name))
(for-each (lambda (sym)
(unless (identifier? sym)
(raise-syntax-error #f
"not an identifier (to be used as a symbol)"
stx
sym)))
syms)
(unless (identifier? #'constructor)
(raise-syntax-error #f
"not an identifier for type name"
stx
#'constructor))
(for ([s (in-list syms)])
(unless (hash-table-get ht (syntax-e s) #f)
(hash-table-put! ht (syntax-e s)
(arithmetic-shift 1 (hash-table-count ht)))))
(with-syntax ([(val ...)
(map (lambda (s) (hash-table-get ht (syntax-e s))) syms)])
#'(begin
(define enum-universe (make-enumeration-universe (mlist 'sym ...)))
(define-syntax (type-name stx)
(syntax-case stx (sym ...)
[(_ sym) #''sym]
...
[(_ other)
(identifier? #'other)
(raise-syntax-error #f "not in enumeration" stx #'other)]))
(define-syntax (bit-value stx)
(syntax-case stx (sym ...)
[(_ orig sym) #'val]
...
[(_ orig s)
(raise-syntax-error #f "not in enumeration" #'orig #'s)]))
(...
(define-syntax (constructor stx)
(syntax-case stx ()
[(_ s ...)
(andmap identifier? (syntax->list #'(s ...)))
(with-syntax ([orig stx])
#'(make-enum-set (bitwise-ior (bit-value orig s) ...)
enum-universe))]))))))]))

View File

@ -643,9 +643,10 @@
#'orig-stx)]
;; Guard case, no pending emits:
[(_ [orig-stx nested? #f ()] ([fold-var fold-init] ...) (#:when expr . rest) . body)
#'(if expr
(for/foldX/derived [orig-stx nested? #f ()] ([fold-var fold-init] ...) rest . body)
(values* fold-init ...))]
#'(let ([fold-var fold-init] ...)
(if expr
(for/foldX/derived [orig-stx nested? #f ()] ([fold-var fold-var] ...) rest . body)
(values* fold-var ...)))]
;; Guard case, pending emits need to be flushed first
[(frm [orig-stx nested? #f binds] ([fold-var fold-init] ...) (#:when expr . rest) . body)
#'(frm [orig-stx nested? #t binds] ([fold-var fold-init] ...) (#:when expr . rest) . body)]

View File

@ -25,71 +25,101 @@
compose)
(#%require (for-syntax "stxcase-scheme.ss"))
;; This is a destructive stable merge-sort, adapted from slib and improved by
;; Eli Barzilay
;; The original source said:
;; It uses a version of merge-sort invented, to the best of my knowledge,
;; by David H. D. Warren, and first used in the DEC-10 Prolog system.
;; R. A. O'Keefe adapted it to work destructively in Scheme.
;; but it's a plain destructive merge sort.
(define (sort-internal lst less? n)
(define (merge-sorted! a b)
(define (loop r a b r-a?) ; r-a? for optimization -- is r connected to a?
(if (less? (mcar b) (mcar a))
(begin (when r-a? (set-mcdr! r b))
(if (null? (mcdr b)) (set-mcdr! b a) (loop b a (mcdr b) #f)))
;; (car a) <= (car b)
(begin (unless r-a? (set-mcdr! r a))
(if (null? (mcdr a)) (set-mcdr! a b) (loop a (mcdr a) b #t)))))
(cond [(null? a) b]
[(null? b) a]
[(less? (mcar b) (mcar a))
(if (null? (mcdr b)) (set-mcdr! b a) (loop b a (mcdr b) #f))
b]
[else ; (car a) <= (car b)
(if (null? (mcdr a)) (set-mcdr! a b) (loop a (mcdr a) b #t))
a]))
(let step ([n n])
(cond [(> n 3) (let* (; let* not really needed with mzscheme's l->r eval
[j (quotient n 2)] [a (step j)] [b (step (- n j))])
(merge-sorted! a b))]
;; the following two cases are just explicit treatment of sublists
;; of length 2 and 3, could remove both (and use the above case for
;; n>1) and it would still work, except a little slower
[(= n 3) (let ([p lst] [p1 (mcdr lst)] [p2 (mcdr (mcdr lst))])
(let ([x (mcar p)] [y (mcar p1)] [z (mcar p2)])
(set! lst (mcdr p2))
(cond [(less? y x) ; y x
(cond [(less? z y) ; z y x
(set-mcar! p z)
(set-mcar! p1 y)
(set-mcar! p2 x)]
[(less? z x) ; y z x
(set-mcar! p y)
(set-mcar! p1 z)
(set-mcar! p2 x)]
[else ; y x z
(set-mcar! p y)
(set-mcar! p1 x)])]
[(less? z x) ; z x y
(set-mcar! p z)
(set-mcar! p1 x)
(set-mcar! p2 y)]
[(less? z y) ; x z y
(set-mcar! p1 z)
(set-mcar! p2 y)])
(set-mcdr! p2 '())
p))]
[(= n 2) (let ([x (mcar lst)] [y (mcar (mcdr lst))] [p lst])
(set! lst (mcdr (mcdr lst)))
(when (less? y x) (set-mcar! p y) (set-mcar! (mcdr p) x))
(set-mcdr! (mcdr p) '())
p)]
[(= n 1) (let ([p lst])
(set! lst (mcdr lst))
(set-mcdr! p '())
p)]
[else '()])))
;; but it's a plain destructive merge sort, which I optimized further.
(define sort-internal
(let ()
(define-syntax sort-internal-body
(syntax-rules ()
[(_ lst less? n)
(begin
(define (merge-sorted! a b)
;; r-a? for optimization -- is r connected to a?
(define (loop r a b r-a?)
(if (less? (mcar b) (mcar a))
(begin
(when r-a? (set-mcdr! r b))
(if (null? (mcdr b)) (set-mcdr! b a) (loop b a (mcdr b) #f)))
;; (car a) <= (car b)
(begin
(unless r-a? (set-mcdr! r a))
(if (null? (mcdr a)) (set-mcdr! a b) (loop a (mcdr a) b #t)))))
(cond [(null? a) b]
[(null? b) a]
[(less? (mcar b) (mcar a))
(if (null? (mcdr b)) (set-mcdr! b a) (loop b a (mcdr b) #f))
b]
[else ; (car a) <= (car b)
(if (null? (mcdr a)) (set-mcdr! a b) (loop a (mcdr a) b #t))
a]))
(let step ([n n])
(cond [(> n 3)
(let* (; let* not really needed with mzscheme's l->r eval
[j (quotient n 2)] [a (step j)] [b (step (- n j))])
(merge-sorted! a b))]
;; the following two cases are just explicit treatment of
;; sublists of length 2 and 3, could remove both (and use the
;; above case for n>1) and it would still work, except a
;; little slower
[(= n 3) (let ([p lst] [p1 (mcdr lst)] [p2 (mcdr (mcdr lst))])
(let ([x (mcar p)] [y (mcar p1)] [z (mcar p2)])
(set! lst (mcdr p2))
(cond [(less? y x) ; y x
(cond [(less? z y) ; z y x
(set-mcar! p z)
(set-mcar! p1 y)
(set-mcar! p2 x)]
[(less? z x) ; y z x
(set-mcar! p y)
(set-mcar! p1 z)
(set-mcar! p2 x)]
[else ; y x z
(set-mcar! p y)
(set-mcar! p1 x)])]
[(less? z x) ; z x y
(set-mcar! p z)
(set-mcar! p1 x)
(set-mcar! p2 y)]
[(less? z y) ; x z y
(set-mcar! p1 z)
(set-mcar! p2 y)])
(set-mcdr! p2 '())
p))]
[(= n 2) (let ([x (mcar lst)] [y (mcar (mcdr lst))] [p lst])
(set! lst (mcdr (mcdr lst)))
(when (less? y x)
(set-mcar! p y)
(set-mcar! (mcdr p) x))
(set-mcdr! (mcdr p) '())
p)]
[(= n 1) (let ([p lst])
(set! lst (mcdr lst))
(set-mcdr! p '())
p)]
[else '()])))]))
(define sort-internals (make-hash-table))
(define-syntax make-precompiled-sort
(syntax-rules ()
[(_ less?) (hash-table-put! sort-internals less?
(lambda (lst n) (sort-internal-body lst less? n)))]))
(define ((sort-internal* less?) lst n)
(sort-internal-body lst less? n))
(make-precompiled-sort <)
(make-precompiled-sort string<?)
(make-precompiled-sort string-ci<?)
(make-precompiled-sort keyword<?)
(lambda (less? lst n)
((or (hash-table-get sort-internals less? #f)
(sort-internal* less?))
lst n))))
(define (sort lst less?)
(unless (list? lst)
(raise-type-error 'sort "proper list" lst))
@ -140,7 +170,7 @@
(set-mcdr! last new)
(loop new (cdr lst))))))])
;; mlist->list
(let loop ([r (sort-internal mlst less? n)])
(let loop ([r (sort-internal less? mlst n)])
(if (null? r)
r
(cons (mcar r) (loop (mcdr r))))))])))

View File

@ -1,128 +1,130 @@
#lang scheme/base
(module promise '#%kernel
;;
;; This module implements "lazy promises" and a `force' that is iterated
;; through them.
;; This is similar to the *new* version of srfi-45 -- see the post-finalization
;; discussion at http://srfi.schemers.org/srfi-45/ for more details;
;; specifically, this version is the `lazy2' version from
;; http://srfi.schemers.org/srfi-45/post-mail-archive/msg00013.html and (a
;; `lazy3' variant of `force' that deals with multiple values is included and
;; commented). Note: if you use only `force'+`delay' it behaves as in Scheme
;; (except that `force' is identity for non promise values), and `force'+`lazy'
;; are sufficient for implementing the lazy language.
;; This module implements "lazy promises" and a `force' that is iterated
;; through them.
;; This is similar to the *new* version of srfi-45 -- see the post-finalization
;; discussion at http://srfi.schemers.org/srfi-45/ for more details;
;; specifically, this version is the `lazy2' version from
;; http://srfi.schemers.org/srfi-45/post-mail-archive/msg00013.html and (a
;; `lazy3' variant of `force' that deals with multiple values is included and
;; commented). Note: if you use only `force'+`delay' it behaves as in Scheme
;; (except that `force' is identity for non promise values), and `force'+`lazy'
;; are sufficient for implementing the lazy language.
(#%require "private/more-scheme.ss" "private/small-scheme.ss"
"private/define.ss"
(rename "private/define-struct.ss" define-struct define-struct*)
(for-syntax '#%kernel
"private/stxcase-scheme.ss" "private/small-scheme.ss"))
(require (for-syntax scheme/base))
(#%provide lazy delay force promise?)
(provide lazy delay force promise?)
(define running
(lambda () (error 'force "reentrant promise")))
(define running
(lambda () (error 'force "reentrant promise")))
(define (promise-printer promise port write?)
(let loop ([p (promise-val promise)])
(cond
[(procedure? p)
(cond [(object-name p)
=> (lambda (n) (fprintf port "#<promise:~a>" n))]
[else (display "#<promise>" port)])]
;; no values
[(null? p) (fprintf port "#<promise!(values)>")]
[(pair? p)
;; single or multiple values
(fprintf port
(if write? "#<promise!~a~s" "#<promise!~a~a")
(if (null? (cdr p)) "" "(values ")
(car p))
(when (pair? (cdr p))
(let ([fmt (if write? " ~s" " ~a")])
(for-each (lambda (x) (fprintf port fmt x)) (cdr p))))
(unless (null? (cdr p)) (display ")" port))
(display ">" port)]
[(promise? p) (loop (promise-val p))] ; hide sharing
[else (loop (list p))])))
(define-struct promise (val)
#:mutable
#:property prop:custom-write promise-printer)
;; <promise> ::=
;; | (promise <thunk>) delayed promise, maybe currently running, maybe an exn promise
;; | (promise (list <object>)) forced promise (possibly multi-valued)
;; | (promise <promise>) shared promise
;; | (promise <object>) forced promise, since values
;; Creates a `composable' promise
;; X = (force (lazy X)) = (force (lazy (lazy X))) = (force (lazy^n X))
(define-syntax (lazy stx)
(syntax-case stx ()
[(lazy expr) (with-syntax ([proc (syntax-property
(syntax/loc stx (lambda () expr))
'inferred-name (syntax-local-name))])
(syntax/loc stx (make-promise proc)))]))
;; Creates a promise that does not compose
;; X = (force (delay X)) = (force (lazy (delay X)))
;; = (force (lazy^n (delay X)))
;; X = (force (force (delay (delay X)))) =/= (force (delay (delay X)))
;; so each sequence of `(lazy^n o delay)^m' requires m `force's and a
;; sequence of `(lazy^n o delay)^m o lazy^k' requires m+1 `force's (for k>0)
;; (This is not needed with a lazy language (see the above URL for details),
;; but provided for completeness.)
(define-syntax (delay stx)
(syntax-case stx ()
[(delay expr)
(with-syntax ([proc (syntax-property
(syntax/loc stx (lambda () expr))
'inferred-name (syntax-local-name))])
(syntax/loc stx
(lazy (make-promise (call-with-values proc list)))))]))
;; force iterates on lazy promises (forbid dependency cycles)
;; * (force X) = X for non promises
;; * does not deal with multiple values, since they're not used by the lazy
;; language (but see below)
(define handle-results
(case-lambda
[(single) (values #f single)]
[multi (values #t multi)]))
(define (force-proc p root)
(define (return-vals vals)
;; error here for "library approach" (see above URL)
(set-promise-val! root vals)
(apply values vals))
(let loop1 ([p p])
(let-values ([(multi? v) (call-with-values p handle-results)])
(if multi?
(return-vals v)
(if (promise? v)
(let loop2 ([promise* v])
(let ([p* (promise-val promise*)])
(set-promise-val! promise* root) ; share with root
(cond [(procedure? p*) (loop1 p*)]
[(or (pair? p*) (null? p*)) (return-vals p*)]
[(promise? p*) (loop2 p*)]
[else p*])))
(return-vals
(if (or (null? v) (pair? v) (procedure? v)) (list v) v)))))))
(define (force promise)
(if (promise? promise)
(define (promise-printer promise port write?)
(let loop ([p (promise-val promise)])
(cond
[(procedure? p)
;; mark root for cycle detection:
(set-promise-val! promise running)
(with-handlers*
([void (lambda (e)
(set-promise-val! promise (lambda () (raise e)))
(raise e))])
(force-proc p promise))]
[(or (pair? p) (null? p)) (apply values p)]
[(promise? p) (loop (promise-val p))]
[else p]))
;; different from srfi-45: identity for non-promises
promise))
[(procedure? p)
(cond [(object-name p)
=> (lambda (n) (fprintf port "#<promise:~a>" n))]
[else (display "#<promise>" port)])]
;; no values
[(null? p) (fprintf port "#<promise!(values)>")]
[(pair? p)
;; single or multiple values
(fprintf port
(if write? "#<promise!~a~s" "#<promise!~a~a")
(if (null? (cdr p)) "" "(values ")
(car p))
(when (pair? (cdr p))
(let ([fmt (if write? " ~s" " ~a")])
(for-each (lambda (x) (fprintf port fmt x)) (cdr p))))
(unless (null? (cdr p)) (display ")" port))
(display ">" port)]
[(promise? p) (loop (promise-val p))] ; hide sharing
[else (loop (list p))])))
(define-struct promise (val)
#:mutable
#:property prop:custom-write promise-printer)
;; <promise> ::=
;; | (promise <thunk>) delayed promise, maybe currently running, maybe an exn promise
;; | (promise (list <object>)) forced promise (possibly multi-valued)
;; | (promise <promise>) shared promise
;; | (promise <object>) forced promise, since values
;; Creates a `composable' promise
;; X = (force (lazy X)) = (force (lazy (lazy X))) = (force (lazy^n X))
(define-syntax (lazy stx)
(syntax-case stx ()
[(lazy expr) (with-syntax ([proc (syntax-property
(syntax/loc stx (lambda () expr))
'inferred-name (syntax-local-name))])
(syntax/loc stx (make-promise proc)))]))
;; Creates a promise that does not compose
;; X = (force (delay X)) = (force (lazy (delay X)))
;; = (force (lazy^n (delay X)))
;; X = (force (force (delay (delay X)))) =/= (force (delay (delay X)))
;; so each sequence of `(lazy^n o delay)^m' requires m `force's and a
;; sequence of `(lazy^n o delay)^m o lazy^k' requires m+1 `force's (for k>0)
;; (This is not needed with a lazy language (see the above URL for details),
;; but provided for completeness.)
(define-syntax (delay stx)
(syntax-case stx ()
[(delay expr)
(with-syntax ([proc (syntax-property
(syntax/loc stx (lambda () expr))
'inferred-name (syntax-local-name))])
(syntax/loc stx
(lazy (make-promise (call-with-values proc list)))))]))
;; force iterates on lazy promises (forbid dependency cycles)
;; * (force X) = X for non promises
;; * does not deal with multiple values, since they're not used by the lazy
;; language (but see below)
(define handle-results
(case-lambda
[(single) (values #f single)]
[multi (values #t multi)]))
(define (force-proc p root)
(define (return-vals vals)
;; error here for "library approach" (see above URL)
(set-promise-val! root vals)
(apply values vals))
(let loop1 ([p p])
(let-values ([(multi? v) (call-with-values p handle-results)])
(if multi?
(return-vals v)
(if (promise? v)
(let loop2 ([promise* v])
(let ([p* (promise-val promise*)])
(set-promise-val! promise* root) ; share with root
(cond [(procedure? p*) (loop1 p*)]
[(or (pair? p*) (null? p*)) (return-vals p*)]
[(promise? p*) (loop2 p*)]
[else p*])))
(return-vals
(if (or (null? v) (pair? v) (procedure? v)) (list v) v)))))))
(define (force promise)
(if (promise? promise)
(let loop ([p (promise-val promise)])
(cond
[(procedure? p)
;; mark root for cycle detection:
(set-promise-val! promise running)
(with-handlers*
([void (lambda (e)
(set-promise-val! promise (lambda () (raise e)))
(raise e))])
(force-proc p promise))]
[(or (pair? p) (null? p)) (apply values p)]
[(promise? p) (loop (promise-val p))]
[else p]))
;; different from srfi-45: identity for non-promises
promise)))

View File

@ -708,17 +708,20 @@ padded with trailing zeros if necessary).
@defproc[(integer-bytes->integer [bstr bytes?]
[signed? any/c]
[big-endian? any/c (system-big-endian?)])
[big-endian? any/c (system-big-endian?)]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (bytes-length bstr)])
exact-integer?]{
Converts the machine-format number encoded in @scheme[bstr] to an
exact integer. The @scheme[bstr] must contain either 2, 4, or 8
bytes. If @scheme[signed?] is true, then the bytes are decoded as a
two's-complement number, otherwise it is decoded as an unsigned
integer. If @scheme[big-endian?] is true, then the first character's
ASCII value provides the most significant eight bits of the number,
otherwise the first character provides the least-significant eight
bits, and so on..}
exact integer. The @scheme[start] and @scheme[end] arguments specify
the substring to decode, where @scheme[(- end start)] must be
@scheme[2], @scheme[4], or @scheme[8]. If @scheme[signed?] is true,
then the bytes are decoded as a two's-complement number, otherwise it
is decoded as an unsigned integer. If @scheme[big-endian?] is true,
then the first character's ASCII value provides the most significant
eight bits of the number, otherwise the first character provides the
least-significant eight bits, and so on.}
@defproc[(integer->integer-bytes [n exact-integer?]
@ -727,21 +730,23 @@ bits, and so on..}
[big-endian? any/c (system-big-endian?)]
[dest-bstr (and/c bytes?
(not/c immutable?))
(make-bytes size-n)])
(make-bytes size-n)]
[start exact-nonnegative-integer? 0])
bytes?]{
Converts the exact integer @scheme[n] to a machine-format number
encoded in a byte string of length @scheme[size-n], which must be 2,
4, or 8. If @scheme[signed?] is true, then the number is encoded as
two's complement, otherwise it is encoded as an unsigned bit
stream. If @scheme[big-endian?] is true, then the most significant
eight bits of the number are encoded in the first character of the
resulting byte string, otherwise the least-significant bits are
encoded in the first byte, and so on.
encoded in a byte string of length @scheme[size-n], which must be
@scheme[2], @scheme[4], or @scheme[8]. If @scheme[signed?] is true,
then the number is encoded as two's complement, otherwise it is
encoded as an unsigned bit stream. If @scheme[big-endian?] is true,
then the most significant eight bits of the number are encoded in the
first character of the resulting byte string, otherwise the
least-significant bits are encoded in the first byte, and so on.
The @scheme[dest-bstr] argument must be a mutable byte string of
length @scheme[size-n]. The encoding of @scheme[n] is written into
@scheme[dest-bstr], and @scheme[dest-bstr] is returned as the result.
@scheme[dest-bstr] starting at offset @scheme[start], and
@scheme[dest-bstr] is returned as the result.
If @scheme[n] cannot be encoded in a string of the requested size and
format, the @exnraise[exn:fail:contract]. If @scheme[dest-bstr] is not

View File

@ -2360,128 +2360,153 @@
(test (integer-bytes->integer #"\1\2" #f) integer-bytes->integer #"\1\2" #f (system-big-endian?))
(test 0 integer-bytes->integer #"\0\0" #t)
(test -1 integer-bytes->integer #"\377\377" #t)
(test 65535 integer-bytes->integer #"\377\377" #f)
;;
(test 0 integer-bytes->integer #"\0\0" #t #t)
(test -1 integer-bytes->integer #"\377\377" #t #t)
(test 65535 integer-bytes->integer #"\377\377" #f #t)
(test -256 integer-bytes->integer #"\377\0" #t #t)
(test -255 integer-bytes->integer #"\377\1" #t #t)
(test 511 integer-bytes->integer #"\1\377" #t #t)
(test 513 integer-bytes->integer #"\1\2" #f #f)
;;
(test 0 integer-bytes->integer #"\0\0" #t #f)
(test -1 integer-bytes->integer #"\377\377" #t #f)
(test 65535 integer-bytes->integer #"\377\377" #f #f)
(test 511 integer-bytes->integer #"\377\1" #t #f)
(test -255 integer-bytes->integer #"\1\377" #t #f)
(test 258 integer-bytes->integer #"\1\2" #f #t)
(define (test-integer-bytes->integer integer-bytes->integer)
(test 0 integer-bytes->integer #"\0\0" #t)
(test -1 integer-bytes->integer #"\377\377" #t)
(test 65535 integer-bytes->integer #"\377\377" #f)
;;
(test 0 integer-bytes->integer #"\0\0" #t #t)
(test -1 integer-bytes->integer #"\377\377" #t #t)
(test 65535 integer-bytes->integer #"\377\377" #f #t)
(test -256 integer-bytes->integer #"\377\0" #t #t)
(test -255 integer-bytes->integer #"\377\1" #t #t)
(test 511 integer-bytes->integer #"\1\377" #t #t)
(test 513 integer-bytes->integer #"\1\2" #f #f)
;;
(test 0 integer-bytes->integer #"\0\0" #t #f)
(test -1 integer-bytes->integer #"\377\377" #t #f)
(test 65535 integer-bytes->integer #"\377\377" #f #f)
(test 511 integer-bytes->integer #"\377\1" #t #f)
(test -255 integer-bytes->integer #"\1\377" #t #f)
(test 258 integer-bytes->integer #"\1\2" #f #t)
(test 0 integer-bytes->integer #"\0\0\0\0" #t)
(test -1 integer-bytes->integer #"\377\377\377\377" #t)
(test 4294967295 integer-bytes->integer #"\377\377\377\377" #f)
;;
(test 0 integer-bytes->integer #"\0\0\0\0" #t #t)
(test -1 integer-bytes->integer #"\377\377\377\377" #t #t)
(test 4294967295 integer-bytes->integer #"\377\377\377\377" #f #t)
(test -16777216 integer-bytes->integer #"\377\0\0\0" #t #t)
(test 255 integer-bytes->integer #"\0\0\0\377" #t #t)
;;
(test 0 integer-bytes->integer #"\0\0\0\0" #t #f)
(test -1 integer-bytes->integer #"\377\377\377\377" #t #f)
(test 4294967295 integer-bytes->integer #"\377\377\377\377" #f #f)
(test 16777471 integer-bytes->integer #"\377\0\0\1" #t #f)
(test -16777216 integer-bytes->integer #"\0\0\0\377" #t #f)
(test -16777215 integer-bytes->integer #"\1\0\0\377" #t #f)
(test 0 integer-bytes->integer #"\0\0\0\0" #t)
(test -1 integer-bytes->integer #"\377\377\377\377" #t)
(test 4294967295 integer-bytes->integer #"\377\377\377\377" #f)
;;
(test 0 integer-bytes->integer #"\0\0\0\0" #t #t)
(test -1 integer-bytes->integer #"\377\377\377\377" #t #t)
(test 4294967295 integer-bytes->integer #"\377\377\377\377" #f #t)
(test -16777216 integer-bytes->integer #"\377\0\0\0" #t #t)
(test 255 integer-bytes->integer #"\0\0\0\377" #t #t)
;;
(test 0 integer-bytes->integer #"\0\0\0\0" #t #f)
(test -1 integer-bytes->integer #"\377\377\377\377" #t #f)
(test 4294967295 integer-bytes->integer #"\377\377\377\377" #f #f)
(test 16777471 integer-bytes->integer #"\377\0\0\1" #t #f)
(test -16777216 integer-bytes->integer #"\0\0\0\377" #t #f)
(test -16777215 integer-bytes->integer #"\1\0\0\377" #t #f)
(test 1835103348 integer-bytes->integer #"matt" #t #t)
(test 1953784173 integer-bytes->integer #"matt" #t #f)
(test 1835103348 integer-bytes->integer #"matt" #t #t)
(test 1953784173 integer-bytes->integer #"matt" #t #f)
(test 0 integer-bytes->integer #"\0\0\0\0\0\0\0\0" #t #t)
(test -1 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #t #f)
(test 18446744073709551615 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #f #f)
(test 4294967295 integer-bytes->integer #"\377\377\377\377\0\0\0\0" #t #f)
(test -4294967296 integer-bytes->integer #"\0\0\0\0\377\377\377\377" #t #f)
(test 8589934591 integer-bytes->integer #"\377\377\377\377\1\0\0\0" #t #f)
(test -4294967295 integer-bytes->integer #"\1\0\0\0\377\377\377\377" #t #f)
;;
(test 0 integer-bytes->integer #"\0\0\0\0\0\0\0\0" #t #f)
(test -1 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #t #f)
(test 18446744073709551615 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #f #f)
(test -4294967296 integer-bytes->integer #"\377\377\377\377\0\0\0\0" #t #t)
(test 4294967295 integer-bytes->integer #"\0\0\0\0\377\377\377\377" #t #t)
(test -4294967295 integer-bytes->integer #"\377\377\377\377\0\0\0\1" #t #t)
(test 8589934591 integer-bytes->integer #"\0\0\0\1\377\377\377\377" #t #t)
(test 0 integer-bytes->integer #"\0\0\0\0\0\0\0\0" #t #t)
(test -1 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #t #f)
(test 18446744073709551615 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #f #f)
(test 4294967295 integer-bytes->integer #"\377\377\377\377\0\0\0\0" #t #f)
(test -4294967296 integer-bytes->integer #"\0\0\0\0\377\377\377\377" #t #f)
(test 8589934591 integer-bytes->integer #"\377\377\377\377\1\0\0\0" #t #f)
(test -4294967295 integer-bytes->integer #"\1\0\0\0\377\377\377\377" #t #f)
;;
(test 0 integer-bytes->integer #"\0\0\0\0\0\0\0\0" #t #f)
(test -1 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #t #f)
(test 18446744073709551615 integer-bytes->integer #"\377\377\377\377\377\377\377\377" #f #f)
(test -4294967296 integer-bytes->integer #"\377\377\377\377\0\0\0\0" #t #t)
(test 4294967295 integer-bytes->integer #"\0\0\0\0\377\377\377\377" #t #t)
(test -4294967295 integer-bytes->integer #"\377\377\377\377\0\0\0\1" #t #t)
(test 8589934591 integer-bytes->integer #"\0\0\0\1\377\377\377\377" #t #t))
(arity-test integer-bytes->integer 2 3)
(test-integer-bytes->integer integer-bytes->integer)
(test-integer-bytes->integer (lambda (bstr signed? [big-endian? (system-big-endian?)])
(integer-bytes->integer (bytes-append #"xxx" bstr)
signed?
big-endian?
3)))
(test-integer-bytes->integer (lambda (bstr signed? [big-endian? (system-big-endian?)])
(integer-bytes->integer (bytes-append #"xxx" bstr #"x")
signed?
big-endian?
3
(+ 3 (bytes-length bstr)))))
(arity-test integer-bytes->integer 2 5)
(err/rt-test (integer-bytes->integer 'ok #t))
(err/rt-test (integer-bytes->integer #"" #t))
(err/rt-test (integer-bytes->integer #"a" #t))
(err/rt-test (integer-bytes->integer #"abc" #t))
(err/rt-test (integer-bytes->integer #"abcdefghi" #t))
(err/rt-test (integer-bytes->integer #"abcdefghi" #t #f 0 3))
(err/rt-test (integer-bytes->integer #"abcd" #t #f 1))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(test (integer->integer-bytes 42 2 #f) integer->integer-bytes 42 2 #f (system-big-endian?))
(test #"\0\0" integer->integer-bytes 0 2 #t)
(test #"\377\377" integer->integer-bytes -1 2 #t)
(test #"\377\377" integer->integer-bytes 65535 2 #f)
;;
(test #"\0\0" integer->integer-bytes 0 2 #t #t)
(test #"\377\377" integer->integer-bytes -1 2 #t #t)
(test #"\377\377" integer->integer-bytes 65535 2 #f #t)
(test #"\377\0" integer->integer-bytes -256 2 #t #t)
(test #"\377\1" integer->integer-bytes -255 2 #t #t)
(test #"\1\377" integer->integer-bytes 511 2 #t #t)
(test #"\1\2" integer->integer-bytes 513 2 #f #f)
;;
(test #"\0\0" integer->integer-bytes 0 2 #t #f)
(test #"\377\377" integer->integer-bytes -1 2 #t #f)
(test #"\377\377" integer->integer-bytes 65535 2 #f #f)
(test #"\377\1" integer->integer-bytes 511 2 #t #f)
(test #"\1\377" integer->integer-bytes -255 2 #t #f)
(test #"\1\2" integer->integer-bytes 258 2 #f #t)
(define (test-integer->integer-bytes integer->integer-bytes)
(test #"\0\0" integer->integer-bytes 0 2 #t)
(test #"\377\377" integer->integer-bytes -1 2 #t)
(test #"\377\377" integer->integer-bytes 65535 2 #f)
;;
(test #"\0\0" integer->integer-bytes 0 2 #t #t)
(test #"\377\377" integer->integer-bytes -1 2 #t #t)
(test #"\377\377" integer->integer-bytes 65535 2 #f #t)
(test #"\377\0" integer->integer-bytes -256 2 #t #t)
(test #"\377\1" integer->integer-bytes -255 2 #t #t)
(test #"\1\377" integer->integer-bytes 511 2 #t #t)
(test #"\1\2" integer->integer-bytes 513 2 #f #f)
;;
(test #"\0\0" integer->integer-bytes 0 2 #t #f)
(test #"\377\377" integer->integer-bytes -1 2 #t #f)
(test #"\377\377" integer->integer-bytes 65535 2 #f #f)
(test #"\377\1" integer->integer-bytes 511 2 #t #f)
(test #"\1\377" integer->integer-bytes -255 2 #t #f)
(test #"\1\2" integer->integer-bytes 258 2 #f #t)
(test #"\0\0\0\0" integer->integer-bytes 0 4 #t)
(test #"\377\377\377\377" integer->integer-bytes -1 4 #t)
(test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f)
;;
(test #"\0\0\0\0" integer->integer-bytes 0 4 #t #t)
(test #"\377\377\377\377" integer->integer-bytes -1 4 #t #t)
(test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f #t)
(test #"\377\0\0\0" integer->integer-bytes -16777216 4 #t #t)
(test #"\0\0\0\377" integer->integer-bytes 255 4 #t #t)
;;
(test #"\0\0\0\0" integer->integer-bytes 0 4 #t #f)
(test #"\377\377\377\377" integer->integer-bytes -1 4 #t #f)
(test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f #f)
(test #"\377\0\0\1" integer->integer-bytes 16777471 4 #t #f)
(test #"\0\0\0\377" integer->integer-bytes -16777216 4 #t #f)
(test #"\1\0\0\377" integer->integer-bytes -16777215 4 #t #f)
(test #"\0\0\0\0" integer->integer-bytes 0 4 #t)
(test #"\377\377\377\377" integer->integer-bytes -1 4 #t)
(test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f)
;;
(test #"\0\0\0\0" integer->integer-bytes 0 4 #t #t)
(test #"\377\377\377\377" integer->integer-bytes -1 4 #t #t)
(test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f #t)
(test #"\377\0\0\0" integer->integer-bytes -16777216 4 #t #t)
(test #"\0\0\0\377" integer->integer-bytes 255 4 #t #t)
;;
(test #"\0\0\0\0" integer->integer-bytes 0 4 #t #f)
(test #"\377\377\377\377" integer->integer-bytes -1 4 #t #f)
(test #"\377\377\377\377" integer->integer-bytes 4294967295 4 #f #f)
(test #"\377\0\0\1" integer->integer-bytes 16777471 4 #t #f)
(test #"\0\0\0\377" integer->integer-bytes -16777216 4 #t #f)
(test #"\1\0\0\377" integer->integer-bytes -16777215 4 #t #f)
(test #"matt" integer->integer-bytes 1835103348 4 #t #t)
(test #"matt" integer->integer-bytes 1953784173 4 #t #f)
(test #"matt" integer->integer-bytes 1835103348 4 #t #t)
(test #"matt" integer->integer-bytes 1953784173 4 #t #f)
(test #"\0\0\0\0\0\0\0\0" integer->integer-bytes 0 8 #t #t)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes -1 8 #t #f)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes 18446744073709551615 8 #f #f)
(test #"\377\377\377\377\0\0\0\0" integer->integer-bytes 4294967295 8 #t #f)
(test #"\0\0\0\0\377\377\377\377" integer->integer-bytes -4294967296 8 #t #f)
(test #"\377\377\377\377\1\0\0\0" integer->integer-bytes 8589934591 8 #t #f)
(test #"\1\0\0\0\377\377\377\377" integer->integer-bytes -4294967295 8 #t #f)
;;
(test #"\0\0\0\0\0\0\0\0" integer->integer-bytes 0 8 #t #f)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes -1 8 #t #f)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes 18446744073709551615 8 #f #f)
(test #"\377\377\377\377\0\0\0\0" integer->integer-bytes -4294967296 8 #t #t)
(test #"\0\0\0\0\377\377\377\377" integer->integer-bytes 4294967295 8 #t #t)
(test #"\377\377\377\377\0\0\0\1" integer->integer-bytes -4294967295 8 #t #t)
(test #"\0\0\0\1\377\377\377\377" integer->integer-bytes 8589934591 8 #t #t)
(test #"\0\0\0\0\0\0\0\0" integer->integer-bytes 0 8 #t #t)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes -1 8 #t #f)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes 18446744073709551615 8 #f #f)
(test #"\377\377\377\377\0\0\0\0" integer->integer-bytes 4294967295 8 #t #f)
(test #"\0\0\0\0\377\377\377\377" integer->integer-bytes -4294967296 8 #t #f)
(test #"\377\377\377\377\1\0\0\0" integer->integer-bytes 8589934591 8 #t #f)
(test #"\1\0\0\0\377\377\377\377" integer->integer-bytes -4294967295 8 #t #f)
;;
(test #"\0\0\0\0\0\0\0\0" integer->integer-bytes 0 8 #t #f)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes -1 8 #t #f)
(test #"\377\377\377\377\377\377\377\377" integer->integer-bytes 18446744073709551615 8 #f #f)
(test #"\377\377\377\377\0\0\0\0" integer->integer-bytes -4294967296 8 #t #t)
(test #"\0\0\0\0\377\377\377\377" integer->integer-bytes 4294967295 8 #t #t)
(test #"\377\377\377\377\0\0\0\1" integer->integer-bytes -4294967295 8 #t #t)
(test #"\0\0\0\1\377\377\377\377" integer->integer-bytes 8589934591 8 #t #t))
(arity-test integer->integer-bytes 3 5)
(test-integer->integer-bytes integer->integer-bytes)
(test-integer->integer-bytes (lambda (num sz signed? [bigend? (system-big-endian?)])
(let ([bstr (make-bytes 11 (char->integer #\x))])
(integer->integer-bytes num sz signed? bigend? bstr 3)
(test #"xxx" subbytes bstr 0 3)
(test (make-bytes (- 11 3 sz) (char->integer #\x)) subbytes bstr (+ 3 sz))
(subbytes bstr 3 (+ 3 sz)))))
(arity-test integer->integer-bytes 3 6)
(err/rt-test (integer->integer-bytes 'ack 2 #t))
(err/rt-test (integer->integer-bytes 10 'ack #t))
(err/rt-test (integer->integer-bytes 10 20 #t))
@ -2497,8 +2522,8 @@
(err/rt-test (integer->integer-bytes (expt 2 64) 8 #f) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (expt 2 63) 4 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes (sub1 (- (expt 2 63))) 8 #t) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 100 2 #t #t (make-bytes 3)) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 100 4 #t #t (make-bytes 3)) exn:application:mismatch?)
(err/rt-test (integer->integer-bytes 100 2 #t #t (make-bytes 3) 2) exn:application:mismatch?)
(map (lambda (v)
(let-values ([(n size signed?) (apply values v)])

View File

@ -87,14 +87,14 @@ void scheme_init_numstr(Scheme_Env *env)
env);
scheme_add_global_constant("integer-bytes->integer",
scheme_make_folding_prim(bytes_to_integer,
scheme_make_prim_w_arity(bytes_to_integer,
"integer-bytes->integer",
2, 3, 1),
2, 5),
env);
scheme_add_global_constant("integer->integer-bytes",
scheme_make_prim_w_arity(integer_to_bytes,
"integer->integer-bytes",
3, 5),
3, 6),
env);
scheme_add_global_constant("floating-point-bytes->real",
scheme_make_folding_prim(bytes_to_real,
@ -1599,18 +1599,16 @@ int scheme_check_double(const char *where, double d, const char *dest)
static Scheme_Object *bytes_to_integer (int argc, Scheme_Object *argv[])
{
int slen, sgned;
long strlen, slen;
int sgned;
char *str;
int buf[2], i;
int bigend = MZ_IS_BIG_ENDIAN;
int bigend = MZ_IS_BIG_ENDIAN, offset = 0;
if (!SCHEME_BYTE_STRINGP(argv[0]))
slen = 0;
scheme_wrong_type("integer-bytes->integer", "byte string", 0, argc, argv);
else
slen = SCHEME_BYTE_STRLEN_VAL(argv[0]);
if ((slen != 2) && (slen != 4) && (slen != 8))
scheme_wrong_type("integer-bytes->integer", "byte string (2, 4, or 8 bytes)", 0, argc, argv);
strlen = SCHEME_BYTE_STRLEN_VAL(argv[0]);
str = SCHEME_BYTE_STR_VAL(argv[0]);
@ -1618,11 +1616,42 @@ static Scheme_Object *bytes_to_integer (int argc, Scheme_Object *argv[])
if (argc > 2)
bigend = SCHEME_TRUEP(argv[2]);
if (argc > 3) {
long start, finish;
scheme_get_substring_indices("integer-bytes->integer", argv[0],
argc, argv,
3, 4, &start, &finish);
offset = start;
slen = finish - start;
} else {
offset = 0;
slen = strlen;
}
if ((slen != 2) && (slen != 4) && (slen != 8)) {
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"integer-bytes->integer: length is not 2, 4, or 8 bytes: %ld",
slen);
return NULL;
}
if (offset + slen > strlen) {
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
slen);
return NULL;
}
if (bigend != MZ_IS_BIG_ENDIAN) {
for (i = 0; i < slen; i++) {
((char *)buf)[slen - i - 1] = str[i];
((char *)buf)[slen - i - 1] = str[i + offset];
}
str = (char *)buf;
} else {
memcpy(&buf, str + offset, slen);
str = (char *)buf;
}
switch(slen) {
@ -1696,7 +1725,7 @@ static Scheme_Object *integer_to_bytes(int argc, Scheme_Object *argv[])
Scheme_Object *n, *s;
char *str;
int size, sgned;
long val;
long val, offset, buf[2];
#if !defined(NO_LONG_LONG_TYPE) && !defined(SIXTY_FOUR_BIT_INTEGERS)
mzlonglong llval;
#endif
@ -1725,6 +1754,25 @@ static Scheme_Object *integer_to_bytes(int argc, Scheme_Object *argv[])
if (!SCHEME_MUTABLE_BYTE_STRINGP(s))
scheme_wrong_type("integer->integer-bytes", "mutable byte string", 4, argc, argv);
if (argc > 5) {
long start, finish;
scheme_get_substring_indices("integer-bytes->integer", s,
argc, argv,
5, 6, &start, &finish);
offset = start;
} else
offset = 0;
if (offset + size > SCHEME_BYTE_STRLEN_VAL(s)) {
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"integer-bytes->integer: byte string is %ld bytes,"
" which is shorter than starting position %ld plus size %ld",
SCHEME_BYTE_STRLEN_VAL(s), offset, size);
return NULL;
}
/* Check for mismatch: number doesn't fit */
if (size == 2) {
if (SCHEME_BIGNUMP(n))
@ -1799,17 +1847,8 @@ static Scheme_Object *integer_to_bytes(int argc, Scheme_Object *argv[])
return NULL;
}
/* Check for mismatch: string wrong size */
if (size != SCHEME_BYTE_STRLEN_VAL(s)) {
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"integer->integer-bytes: string size %d does not match indicated %d-byte length: %V",
SCHEME_BYTE_STRLEN_VAL(s), size, s);
return NULL;
}
/* Finally, do the work */
str = SCHEME_BYTE_STR_VAL(s);
str = (char *)buf;
switch (size) {
case 2:
{
@ -1872,15 +1911,16 @@ static Scheme_Object *integer_to_bytes(int argc, Scheme_Object *argv[])
break;
}
str = SCHEME_BYTE_STR_VAL(s);
if (bigend != MZ_IS_BIG_ENDIAN) {
int i;
char buf[8];
for (i = 0; i < size; i++) {
buf[size - i - 1] = str[i];
str[i + offset] = ((char *)buf)[size - i - 1];
}
} else {
int i;
for (i = 0; i < size; i++) {
str[i] = buf[i];
str[i + offset] = ((char *)buf)[i];
}
}