(define-library (srfi 60) (import (scheme base) (srfi 1)) ;; # Bitwise Operations (define (logand . args) (letrec ((lgand (lambda (x y) (if (or (zero? x) (zero? y)) 0 (+ (* (lgand (floor/ x 2) (floor/ y 2)) 2) (if (or (even? x) (even? y)) 0 1)))))) (fold lgand -1 args))) (define bitwise-and logand) (define (logior . args) (letrec ((lgior (lambda (x y) (cond ((= x y) x) ((zero? x) y) ((zero? y) x) (else (+ (* (lgior (truncate-quotient x 2) (truncate-quotient y 2)) 2) (if (and (even? x) (even? y)) 0 1))))))) (fold lgior 0 args))) (define bitwise-ior logior) (define (logxor . args) (letrec ((lgxor (lambda (x y) (cond ((zero? x) y) ((zero? y) x) (else (+ (* (lgxor (floor/ x 2) (floor/ y 2)) 2) (if (even? x) (if (even? y) 0 1) (if (even? y) 1 0)))))))) (fold lgxor 0 args))) (define bitwise-xor logxor) (define (lognot n) (- -1 n)) (define bitwise-not lognot) (define (bitwise-if mask n0 n1) (logior (logand mask n0) (logand (lognot mask) n1))) (define bitwise-merge bitwise-if) (define (logtest j k) (not (zero? (logand j k)))) (define any-bits-set? logtest) ;; # Integer Properties (define (logcount n) (letrec ((lgcnt (lambda (n) (if (zero? n) 0 (+ (lgcnt (floor/ n 2)) (if (even? n) 0 1)))))) (if (negative? n) (lgcnt (lognot n)) (lgcnt n)))) (define bit-count logcount) (define (integer-length n) (let loop ((n n) (count 0)) (if (zero? n) count (loop (floor/ n 2) (+ count 1))))) (define (log2-binary-factors n) (+ -1 (integer-length (logand n (- n))))) (define first-set-bit log2-binary-factors) ;; # Bit Within Word (define (logbit? index n) (logtest (expt 2 index) n)) (define bit-set? logbit?) (define (copy-bit index from bit) (if bit (logior from (expt 2 index)) (logand from (lognot (expt 2 index))))) ;; # Field of Bits (define (ash n count) (if (negative? count) (let ((k (expt 2 (- count)))) (if (negative? n) (+ -1 (truncate-quotient (+ 1 n) k)) (truncate-quotient n k))) (* (expt 2 count) n))) (define arithmetic-shift ash) (define (bit-field n start end) (logand (lognot (ash -1 (- end start))) (ash n (- start)))) (define (copy-bit-field to from start end) (bitwise-if (ash (lognot (ash -1 (- end start))) start) (ash from start) to)) (define (rotate-bit-field n count start end) (let* ((width (- start end)) (count (floor-remainder count width)) (mask (lognot (ash -1 width))) (zn (logand mask (ash n (- start))))) (logior (ash (logior (logand mask (ash zn count)) (ash zn (- count width))) start) (logand (lognot (ash mask start)) n)))) (define (reverse-bit-field n start end) (letrec ((bit-reverse (lambda (k n) (let loop ((m (if (negative? n) (lognot n) n)) (k (- k 1)) (rvs 0)) (if (negative? k) (if (negative? n) (lognot rvs) rvs) (loop (ash m -1) (- k 1) (logior (ash rvs 1) (logand 1 m)))))))) (let* ((width (- start end)) (mask (lognot (ash -1 width))) (zn (logand mask (ash n (- start))))) (logior (ash (bit-reverse width zn) start) (logand (lognot (ash mask start)) n))))) ;; Bits as Booleans (define (integer->list k . len) (let ((len (if (null? len) (integer-length k) len))) (let loop ((k k) (len len) (acc '())) (if (or (zero? k) (zero? len)) acc (loop (floor/ k 2) (- len 1) (cons (if (even? k) #f #t) acc)))))) (define (list->integer lst) (let loop ((lst lst) (acc 0)) (if (null? lst) acc (loop (cdr lst) (+ (* acc 2) (if (car lst) 1 0)))))) (define (booleans->integer . args) (list->integer args)) (export logand bitwise-and logior bitwise-ior logxor bitwise-xor lognot bitwise-not bitwise-if bitwise-merge logtest any-bits-set? logcount bit-count integer-length log2-binary-factors first-set-bit logbit? bit-set? copy-bit bit-field copy-bit-field ash arithmetic-shift rotate-bit-field reverse-bit-field integer->list list->integer booleans->integer))