Update docs for release wrangling.
[salza2.git] / bitstream.lisp
blobfd864e34c8787db0854a9223ddd4b761d1343f58
1 ;;;
2 ;;; Copyright (c) 2007 Zachary Beane, All Rights Reserved
3 ;;;
4 ;;; Redistribution and use in source and binary forms, with or without
5 ;;; modification, are permitted provided that the following conditions
6 ;;; are met:
7 ;;;
8 ;;; * Redistributions of source code must retain the above copyright
9 ;;; notice, this list of conditions and the following disclaimer.
10 ;;;
11 ;;; * Redistributions in binary form must reproduce the above
12 ;;; copyright notice, this list of conditions and the following
13 ;;; disclaimer in the documentation and/or other materials
14 ;;; provided with the distribution.
15 ;;;
16 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
17 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 ;;;
29 (in-package #:salza2)
31 (defun bitstream-callback-missing (&rest args)
32 (declare (ignore args))
33 (error "No callback set in bitstream"))
35 (defun merge-bits (code size buffer bits callback)
36 (declare (type (unsigned-byte 32) code)
37 (type (integer 0 32) size)
38 (type bitstream-buffer-bit-count bits)
39 (type bitstream-buffer buffer)
40 (type function callback)
41 (optimize speed))
42 ;; BITS represents how many bits have been added to BUFFER so far,
43 ;; so the FLOOR of it by 8 will give both the buffer byte index and
44 ;; the bit index within that byte to where new bits should be
45 ;; merged
46 (let ((buffer-index (ash bits -3))
47 (bit (logand #b111 bits)))
48 ;; The first byte to which new bits are merged might have some
49 ;; bits in it already, so pull it out for merging back in the
50 ;; loop. This only has to be done for the first byte, since
51 ;; subsequent bytes in the buffer will consist solely of bits from
52 ;; CODE.
54 ;; The check (PLUSP BIT) is done to make sure that no garbage bits
55 ;; from a previous write are re-used; if (PLUSP BIT) is zero, all
56 ;; bits in the first output byte come from CODE.
57 (let ((merge-byte (if (plusp bit) (aref buffer buffer-index) 0))
58 (end #.+bitstream-buffer-size+)
59 (result (+ bits size)))
60 ;; (ceiling (+ bit size) 8) is the total number of bytes touched
61 ;; in the buffer
62 (dotimes (i (ceiling (+ bit size) 8))
63 (let ((shift (+ bit (* i -8)))
64 (j (+ buffer-index i)))
65 ;; Buffer filled up in the middle of CODE
66 (when (= j end)
67 (funcall callback buffer j))
68 ;; Merge part of CODE into the buffer
69 (setf (aref buffer (logand #.+bitstream-buffer-mask+ j))
70 (logior (logand #xFF (ash code shift)) merge-byte))
71 (setf merge-byte 0)))
72 ;; Writing is done, and the buffer is full, so call the callback
73 (when (= result #.+bitstream-buffer-bits+)
74 (funcall callback buffer #.+bitstream-buffer-size+))
75 ;; Return only the low bits of the sum
76 (logand #.+bitstream-buffer-bitmask+ result))))
78 (defun merge-octet (octet buffer bits callback)
79 (declare (type octet octet)
80 (type bitstream-buffer buffer)
81 (type bitstream-buffer-bit-count bits)
82 (type function callback)
83 (optimize speed))
84 (let ((offset (ceiling bits 8)))
85 ;; End of the buffer beforehand
86 (when (= offset #.+bitstream-buffer-size+)
87 (funcall callback buffer #.+bitstream-buffer-size+)
88 (setf offset 0
89 bits 0))
90 (setf (aref buffer offset) octet
91 bits (+ bits 8))
92 (when (= (1+ offset) #.+bitstream-buffer-size+)
93 (funcall callback buffer #.+bitstream-buffer-size+)
94 (setf bits 0))
95 bits))
97 ;;; Protocol
99 (defclass bitstream ()
100 ((buffer
101 :initarg :buffer
102 :accessor buffer
103 :documentation "Holds accumulated bits packed into octets.")
104 (bits
105 :initarg :bits
106 :accessor bits
107 :documentation "The number of bits written to the buffer so far.")
108 (callback
109 :initarg :callback
110 :accessor callback
111 :documentation "A function of two arguments, BUFFER and END,
112 that should write out all the data in BUFFER up to END."))
113 (:default-initargs
114 :buffer (make-array +bitstream-buffer-size+ :element-type 'octet)
115 :bits 0
116 :callback #'bitstream-callback-missing))
118 (defgeneric write-bits (code size bitstream))
119 (defgeneric write-octet (octet bitstream))
120 (defgeneric write-octet-vector (vector bitstream &key start end))
121 (defgeneric flush (bitstream))
123 (defmethod write-bits (code size (bitstream bitstream))
124 (setf (bits bitstream)
125 (merge-bits code size
126 (buffer bitstream)
127 (bits bitstream)
128 (callback bitstream))))
130 (defmethod write-octet (octet (bitstream bitstream))
131 (setf (bits bitstream)
132 (merge-octet octet
133 (buffer bitstream)
134 (bits bitstream)
135 (callback bitstream))))
137 (defmethod write-octet-vector (vector (bitstream bitstream) &key (start 0) end)
138 ;;; Not efficient in the slightest, but not actually used internally.
139 (let ((end (or end (length vector))))
140 (loop for i from start below end
141 do (write-octet (aref vector i) bitstream))))
143 (defmethod flush ((bitstream bitstream))
144 (let ((end (ceiling (bits bitstream) 8)))
145 (funcall (callback bitstream) (buffer bitstream) end)
146 (setf (bits bitstream) 0)))
148 (defmethod reset ((bitstream bitstream))
149 (fill (buffer bitstream) 0)
150 (setf (bits bitstream) 0))