Initial commit
author |
Steve Losh <steve@stevelosh.com> |
date |
Sat, 18 Jul 2020 22:27:52 -0400 |
parents |
(none) |
children |
725fdf7522c8 |
(in-package :tdcb)
;;;; Common -------------------------------------------------------------------
(defclass bit-stream (trivial-gray-streams:fundamental-binary-stream)
((underlying-stream :accessor underlying-stream :initarg :underlying-stream :type stream)
(rack :accessor rack :type (unsigned-byte 8) :initform 0)
(mask :accessor mask :type (unsigned-byte 8) :initform #b10000000)))
(defmethod close ((stream bit-stream) &key abort)
(when (open-stream-p (underlying-stream stream))
(close (underlying-stream stream) :abort abort)))
(defmethod stream-element-type ((stream bit-stream))
'bit)
(defmethod stream-file-position ((stream bit-stream))
(error "Cannot change position of a bit stream."))
;;;; Output -------------------------------------------------------------------
(defclass bit-output-stream (bit-stream trivial-gray-streams:fundamental-binary-output-stream) ())
(defun make-bit-output-stream (stream)
(make-instance 'bit-output-stream :underlying-stream stream))
(declaim (inline write-bit%))
(defun write-bit% (stream bit)
(when (plusp bit)
(logiorf (rack stream) (mask stream)))
(when (zerop (ashf (mask stream) -1))
(write-byte (rack stream) (underlying-stream stream))
(setf (rack stream) 0
(mask stream) #b10000000)))
(defun write-bits (stream byte &optional (count 1))
(loop :with mask = (ash 1 (1- count))
:until (zerop mask)
:do (progn (write-bit% stream (logand mask byte))
(ashf mask -1)))
byte)
(defmethod trivial-gray-streams:stream-write-byte ((stream bit-output-stream) bit)
(write-bit% stream bit))
(defmethod close ((stream bit-output-stream) &key abort)
(declare (ignore abort))
(unless (= (mask stream) #b10000000)
(write-byte (rack stream) (underlying-stream stream)))
(call-next-method))
(with-open-stream (s (make-bit-output-stream *standard-output*)) (write-byte #b00101010 s))
;;;; Input -------------------------------------------------------------------
(defclass bit-input-stream (bit-stream trivial-gray-streams:fundamental-binary-input-stream) ())
(defun make-bit-input-stream (stream)
(make-instance 'bit-input-stream :underlying-stream stream))
(declaim (inline read-bit))
(defun read-bit (stream)
(when (= (mask stream) #b10000000)
(setf (rack stream) (read-byte (underlying-stream stream))))
(prog1 (if (zerop (logand (mask stream) (rack stream)))
0
1)
(when (zerop (ashf (mask stream) -1))
(setf (mask stream) #b10000000))))
(defun read-bits (stream count)
(loop :with result = 0
:with mask = (ash 1 (1- count))
:until (zerop mask)
:do (progn (when (plusp (read-bit stream))
(logiorf result mask))
(ashf mask -1))
:finally (return result)))
(defmethod trivial-gray-streams:stream-read-byte ((stream bit-input-stream))
(read-bit stream))
#; Scratch --------------------------------------------------------------------
(defparameter *o* (make-bit-output-stream *standard-output*))
(defparameter *s* (flexi-streams:make-in-memory-input-stream #(#b00101010 #b01010100)))
(defparameter *i* (make-bit-input-stream *s*))
(losh:bits (read-bits *i* 4))
(read-byte *s*)