bit-integers.scm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. (define-module (bit-integers)
  2. #:use-module (rnrs base)
  3. #:use-module ((guile)
  4. #:select (lambda* λ
  5. unless
  6. call-with-output-string
  7. display
  8. string->list))
  9. ;; SRFI 1: list procedures
  10. #:use-module (srfi srfi-1)
  11. ;; SRFI 60: procedures for treating integers as bits
  12. #:use-module (srfi srfi-60)
  13. #:use-module (ice-9 textual-ports)
  14. #:export (bits-left-shift
  15. bits-right-shift
  16. max-int
  17. bit-integer-get-range
  18. format-as-bits
  19. format-as-bits-with-separators
  20. concat-integers))
  21. (define bits-left-shift
  22. (λ (bits count)
  23. "Left shift BITS, an integer, by COUNT positions."
  24. (arithmetic-shift bits count)))
  25. (define bits-right-shift
  26. (λ (bits count)
  27. "Right shift BITS, an integer, by COUNT positions."
  28. (arithmetic-shift bits (* -1 count))))
  29. (define max-int
  30. (λ (num-of-squares)
  31. "Return the maximum integer, for a given number of bits."
  32. (- (expt 2 num-of-squares) 1)))
  33. (define bit-integer-get-range
  34. (λ (bits width offset)
  35. "Treat an integer as bits and get WIDTH bits as a new integer. Start
  36. at OFFSET from the least significant bits. Example: If the least
  37. significant bit is on the left:
  38. 01101010 11101001
  39. width: 6
  40. offset: 8
  41. Then this would look as follows:
  42. offset: 87654321
  43. |
  44. v
  45. 01101010 11101001
  46. bit shift by offset:
  47. 01101010
  48. then mask with max integer of width bits:
  49. bits: 01101010
  50. mask: 00111111
  51. res: 00101010"
  52. (let ([mask (max-int width)])
  53. (bitwise-and (bits-right-shift bits offset) mask))))
  54. (define char->string
  55. (λ (char)
  56. (list->string (list char))))
  57. (define insert-separators
  58. (lambda* (string
  59. #:key
  60. (chunk-width 8)
  61. (separator "|"))
  62. (call-with-output-string
  63. (λ (port)
  64. (let iter ([index 0]
  65. [binary-chars° (string->list string)])
  66. (unless (null? binary-chars°)
  67. (cond
  68. [(and (not (= index 0))
  69. (= (remainder index chunk-width) 0))
  70. (put-string port separator)
  71. (put-char port (car binary-chars°))
  72. (iter (+ index 1)
  73. (cdr binary-chars°))]
  74. [else
  75. (put-char port (car binary-chars°))
  76. (iter (+ index 1)
  77. (cdr binary-chars°))])))))))
  78. (define format-as-bits
  79. (lambda* (bit-int #:key (padding-length 8) (padding-char #\0))
  80. (let ([format-string
  81. (string-append "~"
  82. (number->string padding-length)
  83. ",'"
  84. (char->string padding-char)
  85. "b")])
  86. (format #f format-string bit-int))))
  87. (define format-as-bits-with-separators
  88. (lambda* (bit-int
  89. #:key
  90. (padding-length 8)
  91. (padding-char #\0)
  92. (chunk-width 8)
  93. (separator "|"))
  94. (insert-separators (format-as-bits bit-int
  95. #:padding-length padding-length
  96. #:padding-char padding-char)
  97. #:chunk-width chunk-width
  98. #:separator separator)))
  99. (define concat-integers
  100. (λ (ints ints-width)
  101. "Take a list of integers representing characters and
  102. \"concattenate\". Treat those integers as bits. Shift and add them, to
  103. get one longer sequence of bits. Treat that longer sequence of bits as
  104. a single integer."
  105. (let iter ([ints° (cdr ints)]
  106. [concattenated° (car ints)])
  107. (cond
  108. [(null? ints°) concattenated°]
  109. [else
  110. (iter (drop ints° 1)
  111. (+ (bits-left-shift concattenated° ints-width)
  112. (first ints°)))]))))