M.Hiroi's Home Page

Common Lisp Programming

お気楽 Common Lisp プログラミング入門 : 自作ライブラリ編

[ Common Lisp | library ]

bitio

bitio はビット単位でファイル入出力を行うためのライブラリです。bitio には整数を符号化するための関数も含まれています。詳しい説明は以下の拙作のページをお読みください。

●インストール

アーカイブファイル minlib.tar.gz をインストールする、または プログラムリスト にある以下の 4 つのファイルを、~/common-lisp/ 以下の適当なサブディレクトリ (たとえば bitio など) に配置してください。

●仕様

●簡単なテスト

* (asdf:test-system :bitio)
; ... 略 ...

----- test start -----

(PUTBIT BS 0)
=> NIL OK

(PUTBIT BS 1)
=> NIL OK

(PUTBITS BS 4 10)
=> NIL OK

(PUTBITS BS 8 85)
=> NIL OK

(ALPHA-ENCODE BS 16)
=> NIL OK

(GAMMA-ENCODE BS 17)
=> NIL OK

(DELTA-ENCODE BS 18)
=> NIL OK

(CBT-ENCODE BS 11 12 4)
=> NIL OK

(RICE-ENCODE BS 15 3)
=> NIL OK

(GETBIT BS)
=> 0 OK

(GETBIT BS)
=> 1 OK

(GETBITS BS 4)
=> 10 OK

(GETBITS BS 8)
=> 85 OK

(ALPHA-DECODE BS)
=> 16 OK

(GAMMA-DECODE BS)
=> 17 OK

(DELTA-DECODE BS)
=> 18 OK

(CBT-DECODE BS 12 4)
=> 11 OK

(RICE-DECODE BS 3)
=> 15 OK

----- test end -----
TEST: 18
OK: 18
NG: 0
ERR: 0
T

●サンプルプログラム

●プログラムリスト

;;;
;;; bitio.lisp : ビット入出力
;;;
;;; Copyright (c) 2023 Makoto Hiroi
;;;
;;; Released under the MIT license
;;; https://opensource.org/license/mit/
;;;
(provide :bitio)
(defpackage :bitio (:use :cl))
(in-package :bitio)
(export '(bit-io
          bit-io-p
          call-with-bit-input-file
          call-with-byte-input-file
          call-with-bit-output-file
          call-with-byte-output-file
          getbit
          getbits
          putbit
          putbits
          alpha-encode
          alpha-decode
          gamma-encode
          gamma-decode
          delta-encode
          delta-decode
          cbt-encode
          cbt-decode
          rice-encode
          rice-decode))

;;; 型の定義
(defstruct bit-io direction file buff cnt)

;;; バイト入力用ファイルオープン
(defun call-with-byte-input-file (filename proc)
  (with-open-file (in filename
                      :direction :input
                      :element-type 'unsigned-byte)
    (funcall proc in)))

;;; バイト出力用ファイルオープン
(defun call-with-byte-output-file (filename proc)
  (with-open-file (out filename
                       :direction :output
                       :if-exists :rename-and-delete
                       :element-type 'unsigned-byte)
    (funcall proc out)))

;;; ビット入力用ファイルオープン
(defun call-with-bit-input-file (filename proc)
  (call-with-byte-input-file
   filename
   (lambda (in)
     (funcall proc (make-bit-io :direction :input
                                :file in
                                :cnt 0)))))

;;; ビット出力用ファイルオープン
(defun call-with-bit-output-file (filename proc)
  (call-with-byte-output-file
   filename
   (lambda (out)
     (let ((bs (make-bit-io :direction :output
                            :file out
                            :buff 0
                            :cnt 8)))
       (funcall proc bs)
       (if (< (bit-io-cnt bs) 8)
           (write-byte (bit-io-buff bs) out))))))

;;; 1 ビット入力
(defun getbit (bs)
  (decf (bit-io-cnt bs))
  (when (minusp (bit-io-cnt bs))
    (setf (bit-io-buff bs)
          (read-byte (bit-io-file bs) nil))
    (if (null (bit-io-buff bs))
        (return-from getbit nil))
    (setf (bit-io-cnt bs) 7))
  (if (logbitp (bit-io-cnt bs) (bit-io-buff bs)) 1 0))

;;; 1 ビット出力
(defun putbit (bs val)
  (decf (bit-io-cnt bs))
  (when (plusp val)
    (setf (bit-io-buff bs)
          (logior (bit-io-buff bs) (ash 1 (bit-io-cnt bs)))))
  (when (zerop (bit-io-cnt bs))
    (write-byte (bit-io-buff bs) (bit-io-file bs))
    (setf (bit-io-buff bs) 0
          (bit-io-cnt bs) 8)))

;;; n ビット入力
(defun getbits (bs n)
  (do ((pat (ash 1 (1- n)) (ash pat -1))
       (val 0))
      ((zerop pat) val)
    (case (getbit bs)
      (1 (setf val (logior val pat)))
      (nil (return)))))

;;; n ビット出力
(defun putbits (bs n x)
  (do ((pat (ash 1 (1- n)) (ash pat -1)))
      ((zerop pat))
      (putbit bs (logand x pat))))

;;;
;;; 整数の符号化
;;;

;;; α符号
(defun alpha-encode (bs n)
  (putbits bs n 0)
  (putbit bs 1))

(defun alpha-decode (bs)
  (do ((n 0 (1+ n)))
      ((plusp (getbit bs)) n)))

;;; γ符号
(defun gamma-encode (bs n)
  (do ((n1 0 (1+ n1))
       (n2 (ash (1+ n) -1) (ash n2 -1)))
      ((zerop n2)
       (alpha-encode bs n1)
       (if (plusp n1) (putbits bs n1 (1+ n))))))

(defun gamma-decode (bs)
  (let ((n1 (alpha-decode bs)))
    (if (zerop n1)
        0
      (+ (ash 1 n1) (getbits bs n1) -1))))

;;; δ符号
(defun delta-encode (bs n)
  (do ((n1 0 (1+ n1))
       (n2 (ash (1+ n) -1) (ash n2 -1)))
      ((zerop n2)
       (gamma-encode bs n1)
       (if (plusp n1) (putbits bs n1 (1+ n))))))

(defun delta-decode (bs)
  (let ((n1 (gamma-decode bs)))
    (if (zerop n1)
        0
      (+ (ash 1 n1) (getbits bs n1) -1))))

;;; CBT 符号
(defun cbt-encode (bs n m k)
  (let ((limit (- (ash 1 k) m)))
    (if (< n limit)
        (putbits bs (1- k) n)
      (putbits bs k (+ n limit)))))

(defun cbt-decode (bs m k)
  (let ((limit (- (ash 1 k) m))
        (n (getbits bs (1- k))))
    (if (< n limit)
        n
      (+ (ash n 1) (getbit bs) (- limit)))))

;;; Rice 符号
(defun rice-encode (bs n k)
  (alpha-encode bs (ash n (- k)))
  (putbits bs k n))

(defun rice-decode (bs k)
  (let ((n (alpha-decode bs)))
    (+ (ash n k) (getbits bs k))))
リスト : bitio.asd

(defsystem :bitio
  :description "bit input / output"
  :version "0.1.0"
  :author "Makoto Hiroi"
  :license "MIT"
  :depends-on ()
  :in-order-to ((test-op (test-op :bitio_tst)))
  :components ((:file "bitio")))
;;;
;;; bitio_tst.lisp : bitio のテスト
;;;
;;; Copyright (c) 2023 Makoto Hiroi
;;;
;;; Released under the MIT license
;;; https://opensource.org/license/mit/
;;;
(provide :bitio_tst)
(defpackage :bitio_tst (:use :cl :bitio :mintst))
(in-package :bitio_tst)
(export '(test))

(defvar bs nil)

(defun test ()
  (initial)
  (call-with-bit-output-file
   "bitio_tst.dat"
   (lambda (s)
     (setq bs s)
     (run (putbit bs 0) nil)
     (run (putbit bs 1) nil)
     (run (putbits bs 4 #b1010) nil)
     (run (putbits bs 8 #b01010101) nil)
     (run (alpha-encode bs 16) nil)
     (run (gamma-encode bs 17) nil)
     (run (delta-encode bs 18) nil)
     (run (cbt-encode bs 11 12 4) nil)
     (run (rice-encode bs 15 3) nil)
     (setq bs nil)))
  (call-with-bit-input-file
   "bitio_tst.dat"
   (lambda (s)
     (setq bs s)
     (run (getbit bs) 0)
     (run (getbit bs) 1)
     (run (getbits bs 4) #b1010)
     (run (getbits bs 8) #b01010101)
     (run (alpha-decode bs) 16)
     (run (gamma-decode bs) 17)
     (run (delta-decode bs) 18)
     (run (cbt-decode bs 12 4) 11)
     (run (rice-decode bs 3) 15)
     (setq bs nil)))
  (final))
リスト : bitio_tst.asd

(defsystem :bitio_tst
  :description "test for bitio"
  :version "0.1.0"
  :author "Makoto Hiroi"
  :license "MIT"
  :depends-on (:mintst :bitio)
  :components ((:file "bitio_tst"))
  :perform (test-op (o s) (symbol-call :bitio_tst :test)))

Copyright (C) 2023 Makoto Hiroi
All rights reserved.

[ Common Lisp | library ]