bytevector.scm 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Harald Glab-Phlak, Mike Sperber, Will Clinger
  3. ; This is taken from the R6RS reference implementation by Mike
  4. ; Sperber, modified by Will Clinger.
  5. (import-dynamic-externals "=scheme48external/r6rs")
  6. (define-enumeration endianness
  7. (little big)
  8. endianness*)
  9. (define bytevector? byte-vector?)
  10. (define make-bytevector
  11. (opt-lambda (size (fill 0))
  12. (if (and (>= fill -128)
  13. (<= fill 255))
  14. (make-byte-vector size fill)
  15. (error #f "wrong value to fill a byte vector must be octet" fill))))
  16. (define bytevector-length byte-vector-length)
  17. (define bytevector=? byte-vector=?)
  18. (define (bytevector-fill! vector fill)
  19. (let loop ((index 0))
  20. (if (< index (bytevector-length vector))
  21. (begin (bytevector-u8-set! vector index fill)
  22. (loop (+ index 1))))))
  23. ;; may be we need a few checks to fit the need -- look carefully
  24. (define (bytevector-copy! source source-start target target-start count)
  25. (copy-bytes! source source-start target target-start count))
  26. (define (bytevector-copy vector)
  27. (let* ((size (byte-vector-length vector))
  28. (copy (make-byte-vector size 0)))
  29. (bytevector-copy! vector 0 copy 0 size)
  30. copy))
  31. ;; now the stuff with the typed bytevectors begins
  32. (define (u8->s8 val)
  33. (if (> val 127)
  34. (- val 256)
  35. val))
  36. (define (s8->u8 val)
  37. (if (negative? val)
  38. (+ val 256)
  39. val))
  40. (define (bytevector-u8-ref vector k)
  41. (check-index vector k)
  42. (byte-vector-ref vector k))
  43. (define (bytevector-u8-set! vector k val)
  44. (check-index vector k)
  45. (check-range val 1 #f)
  46. (byte-vector-set! vector k val))
  47. (define (bytevector-s8-ref vector k)
  48. (check-index vector k)
  49. (u8->s8 (bytevector-u8-ref vector k)))
  50. (define (bytevector-s8-set! vector k val)
  51. (check-index vector k)
  52. (check-range val 1 #t)
  53. ( bytevector-u8-set! vector k (s8->u8 val)))
  54. (define (bytevector->u8-list octets)
  55. (let loop ((n (bytevector-length octets)) (r '()))
  56. (if (zero? n)
  57. r
  58. (loop (- n 1)
  59. (cons (bytevector-u8-ref octets (- n 1)) r)))))
  60. (define (u8-list->bytevector list)
  61. (let ((vect (make-bytevector (length list))))
  62. (let loop ((l list)
  63. (index 0))
  64. (if (not (eq? l '()))
  65. (begin (bytevector-u8-set! vect index (car l))
  66. (loop (cdr l)
  67. (+ index 1)))))
  68. vect))
  69. ;; the integer view (native integers) to a bytevector
  70. (define (bytevector-uint-ref bytevector index endness size)
  71. (case endness
  72. ((big)
  73. (do ((i 0 (+ i 1))
  74. (result 0 (+ (arithmetic-shift result 8)
  75. (bytevector-u8-ref bytevector (+ index i)))))
  76. ((>= i size)
  77. result)))
  78. ((little)
  79. (do ((i (- size 1) (- i 1))
  80. (result 0 (+ (arithmetic-shift result 8)
  81. (bytevector-u8-ref bytevector (+ index i)))))
  82. ((< i 0)
  83. result)))
  84. (else
  85. (error 'bytevector-uint-ref "Invalid endianness: " endness))))
  86. (define (bytevector-sint-ref bytevector index endness size)
  87. (let* ((high-byte (bytevector-u8-ref bytevector
  88. (if (eq? endness (endianness big))
  89. index
  90. (+ index size -1))))
  91. (uresult (bytevector-uint-ref bytevector index endness size)))
  92. (if (> high-byte 127)
  93. (- uresult (expt 256 size))
  94. uresult)))
  95. (define (bytevector-uint-set! bytevector index val endness size)
  96. (check-range val size #f)
  97. (case endness
  98. ((little)
  99. (do ((i 0 (+ i 1))
  100. (val val (quotient val 256)))
  101. ((>= i size))
  102. (bytevector-u8-set! bytevector (+ index i) (remainder val 256))))
  103. ((big)
  104. (do ((i (- size 1) (- i 1))
  105. (val val (quotient val 256)))
  106. ((< i 0))
  107. (bytevector-u8-set! bytevector (+ index i) (remainder val 256))))
  108. (else
  109. (error 'bytevector-uint-set! "Invalid endianness: " endness))))
  110. (define (bytevector-sint-set! bytevector index val endness size)
  111. (check-range val size #t)
  112. (let ((uval (if (< val 0)
  113. (+ val (* 128 (expt 256 (- size 1))))
  114. val)))
  115. (bytevector-uint-set! bytevector index uval endness size)))
  116. (define (bytevector->uint-list vector endness size)
  117. ((make-bytevect->int-list bytevector-uint-ref)
  118. vector endness size))
  119. (define (bytevector->sint-list vector endness size)
  120. ((make-bytevect->int-list bytevector-sint-ref)
  121. vector endness size))
  122. (define (uint-list->bytevector list endness size)
  123. ((make-int-list->bytevect bytevector-uint-set!)
  124. list endness size))
  125. (define (sint-list->bytevector list endness size)
  126. ((make-int-list->bytevect bytevector-sint-set!)
  127. list endness size))
  128. (define (make-uint-ref size)
  129. (lambda (bytevector k endianness)
  130. (bytevector-uint-ref bytevector k endianness size)))
  131. (define (make-sint-ref size)
  132. (lambda (bytevector k endianness)
  133. (bytevector-sint-ref bytevector k endianness size)))
  134. (define (make-uint-set! size)
  135. (lambda (bytevector k n endianness)
  136. (bytevector-uint-set! bytevector k n endianness size)))
  137. (define (make-sint-set! size)
  138. (lambda (bytevector k n endianness)
  139. (bytevector-sint-set! bytevector k n endianness size)))
  140. (define (make-ref/native base base-ref)
  141. (lambda (bytevector index)
  142. (ensure-aligned index base)
  143. (base-ref bytevector index (native-endianness))))
  144. (define (make-set!/native base base-set!)
  145. (lambda (bytevector index val)
  146. (ensure-aligned index base)
  147. (base-set! bytevector index val (native-endianness))))
  148. ;; uint16
  149. (define bytevector-u16-ref (make-uint-ref 2))
  150. (define bytevector-s16-ref (make-sint-ref 2))
  151. (define bytevector-u16-native-ref (make-ref/native 2 bytevector-u16-ref))
  152. (define bytevector-s16-native-ref (make-ref/native 2 bytevector-s16-ref))
  153. (define bytevector-u16-set! (make-uint-set! 2))
  154. (define bytevector-s16-set! (make-sint-set! 2))
  155. (define bytevector-u16-native-set! (make-set!/native 2 bytevector-u16-set!))
  156. (define bytevector-s16-native-set! (make-set!/native 2 bytevector-s16-set!))
  157. ;; uint32
  158. (define bytevector-u32-ref (make-uint-ref 4))
  159. (define bytevector-s32-ref (make-sint-ref 4))
  160. (define bytevector-u32-native-ref (make-ref/native 4 bytevector-u32-ref))
  161. (define bytevector-s32-native-ref (make-ref/native 4 bytevector-s32-ref))
  162. (define bytevector-u32-set! (make-uint-set! 4))
  163. (define bytevector-s32-set! (make-sint-set! 4))
  164. (define bytevector-u32-native-set! (make-set!/native 4 bytevector-u32-set!))
  165. (define bytevector-s32-native-set! (make-set!/native 4 bytevector-s32-set!))
  166. ;; uint64
  167. (define bytevector-u64-ref (make-uint-ref 8))
  168. (define bytevector-s64-ref (make-sint-ref 8))
  169. (define bytevector-u64-native-ref (make-ref/native 8 bytevector-u64-ref))
  170. (define bytevector-s64-native-ref (make-ref/native 8 bytevector-s64-ref))
  171. (define bytevector-u64-set! (make-uint-set! 8))
  172. (define bytevector-s64-set! (make-sint-set! 8))
  173. (define bytevector-u64-native-set! (make-set!/native 8 bytevector-u64-set!))
  174. (define bytevector-s64-native-set! (make-set!/native 8 bytevector-s64-set!))
  175. ;; helper procedures
  176. (define (make-bytevect->int-list bytevect-ref)
  177. (lambda (vect endness size)
  178. (let ((length (bytevector-length vect)))
  179. (let loop ((i 0) (r '()))
  180. (if (>= i length)
  181. (reverse r)
  182. (loop (+ i size)
  183. (cons (bytevect-ref vect i endness size) r)))))))
  184. (define (make-int-list->bytevect bytevect-set!)
  185. (lambda (l endness size)
  186. (let ((bytevect (make-bytevector (* size (length l)))))
  187. (let loop ((i 0) (l l))
  188. (if (null? l)
  189. bytevect
  190. (begin
  191. (bytevect-set! bytevect i (car l) endness size)
  192. (loop (+ i size) (cdr l))))))))
  193. ;; general checks
  194. (define (ensure-aligned index base)
  195. (if (not (zero? (remainder index base)))
  196. (assertion-violation 'ensure-aligned "non-aligned bytevector access" index base)))
  197. (define (check-range value byte-count signed-check?)
  198. (let* ((bits (* byte-count 8))
  199. (unsigned-low 0)
  200. (unsigned-high (- (expt 2 bits) 1))
  201. (signed-low (* -1 (expt 2 (- bits 1))))
  202. (signed-high (- (expt 2 (- bits 1)) 1)))
  203. (if signed-check?
  204. (if (not (and (>= value signed-low) (<= value signed-high)))
  205. (assertion-violation 'check-range
  206. "range check for value failed / signed - value does not fit into "
  207. byte-count 'bytes 'checked-value: value))
  208. (if (not (and (>= value unsigned-low) (<= value unsigned-high)))
  209. (assertion-violation 'check-range
  210. "range check for value failed / unsigned - value does not fit into "
  211. byte-count 'bytes 'checked-value: value)))))
  212. (define (check-index b i)
  213. (if (or (> i (- (bytevector-length b) 1)) (< i 0))
  214. (assertion-violation 'check-index
  215. "invalid index forr vector must be in the range of"
  216. 0 'to (- (bytevector-length b) 1))))
  217. (define (native-endianness)
  218. (if (external-r6rs-big-endian?)
  219. (endianness big)
  220. (endianness little)))
  221. ;; external fun definition
  222. (import-lambda-definition-2 external-r6rs-big-endian?
  223. ()
  224. "r6rs_is_big_endian")