Add scratch.lisp to .hgignore
author |
Steve Losh <steve@stevelosh.com> |
date |
Sat, 25 Jul 2020 15:48:15 -0400 |
parents |
3835748a929e |
children |
716d1110c12f |
(in-package :tdcb)
;;;; Struct -------------------------------------------------------------------
(defstruct (bits (:constructor make-bits% (underlying-stream))
(:conc-name nil))
(underlying-stream nil :type stream :read-only t)
(rack 0 :type (unsigned-byte 8))
(mask #b10000000 :type (unsigned-byte 8)))
(declaim (inline write-bit% read-bit%))
;;;; Write --------------------------------------------------------------------
(defun write-bit% (b bit)
(declare (type bits b))
(when (plusp bit)
(logiorf (rack b) (mask b)))
(when (zerop (ashf (mask b) -1))
(write-byte (rack b) (underlying-stream b))
(setf (rack b) 0
(mask b) #b10000000)))
(defun write-bit (b bit)
(write-bit% b bit)
bit)
(defun write-bits (b byte count)
(loop :with mask = (ash 1 (1- count))
:until (zerop mask)
:do (progn (write-bit% b (logand mask byte))
(ashf mask -1)))
byte)
(defun flush (b)
(unless (= (mask b) #x80)
(write-byte (rack b) (underlying-stream b))))
;;;; Read ---------------------------------------------------------------------
(defun read-bit% (b)
(declare (type bits b))
(when (= (mask b) #b10000000)
(setf (rack b) (read-byte (underlying-stream b))))
(prog1 (if (zerop (logand (mask b) (rack b)))
0
1)
(when (zerop (ashf (mask b) -1))
(setf (mask b) #b10000000))))
(defun read-bit (b)
(read-bit% b))
(defun read-bits (b count)
(loop :with result = 0
:with mask = (ash 1 (1- count))
:until (zerop mask)
:do (progn (when (plusp (read-bit b))
(logiorf result mask))
(ashf mask -1))
:finally (return result)))
;;;; Create -------------------------------------------------------------------
(defmacro with-bits-output ((var stream) &body body)
`(let ((,var (make-bits% ,stream)))
(unwind-protect (progn ,@body)
(flush ,var))))
(defmacro with-bits-input ((var stream) &body body)
`(let ((,var (make-bits% ,stream)))
,@body))