mirror of
https://github.com/encounter/joy5.git
synced 2026-03-30 11:18:35 -07:00
120 lines
2.0 KiB
Go
120 lines
2.0 KiB
Go
package bits
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
type Reader struct {
|
|
R io.Reader
|
|
n int
|
|
bits uint64
|
|
}
|
|
|
|
func (r *Reader) ReadBits64(n int) (bits uint64, err error) {
|
|
if r.n < n {
|
|
var b [8]byte
|
|
var got int
|
|
want := (n - r.n + 7) / 8
|
|
if got, err = r.R.Read(b[:want]); err != nil {
|
|
return
|
|
}
|
|
if got < want {
|
|
err = fmt.Errorf("bits: EOF")
|
|
return
|
|
}
|
|
for i := 0; i < got; i++ {
|
|
r.bits <<= 8
|
|
r.bits |= uint64(b[i])
|
|
}
|
|
r.n += got * 8
|
|
}
|
|
bits = r.bits >> uint(r.n-n)
|
|
r.bits ^= bits << uint(r.n-n)
|
|
r.n -= n
|
|
return
|
|
}
|
|
|
|
func (r *Reader) ReadBits(n int) (bits uint, err error) {
|
|
var bits64 uint64
|
|
if bits64, err = r.ReadBits64(n); err != nil {
|
|
return
|
|
}
|
|
bits = uint(bits64)
|
|
return
|
|
}
|
|
|
|
func (r *Reader) Read(p []byte) (n int, err error) {
|
|
for n < len(p) {
|
|
want := 8
|
|
if len(p)-n < want {
|
|
want = len(p) - n
|
|
}
|
|
var bits uint64
|
|
if bits, err = r.ReadBits64(want * 8); err != nil {
|
|
break
|
|
}
|
|
for i := 0; i < want; i++ {
|
|
p[n+i] = byte(bits >> uint((want-i-1)*8))
|
|
}
|
|
n += want
|
|
}
|
|
return
|
|
}
|
|
|
|
type Writer struct {
|
|
W io.Writer
|
|
n int
|
|
bits uint64
|
|
}
|
|
|
|
func (w *Writer) WriteBits64(bits uint64, n int) (err error) {
|
|
if w.n+n > 64 {
|
|
move := uint(64 - w.n)
|
|
mask := bits >> move
|
|
w.bits = (w.bits << move) | mask
|
|
w.n = 64
|
|
if err = w.FlushBits(); err != nil {
|
|
return
|
|
}
|
|
n -= int(move)
|
|
bits ^= (mask << move)
|
|
}
|
|
w.bits = (w.bits << uint(n)) | bits
|
|
w.n += n
|
|
return
|
|
}
|
|
|
|
func (w *Writer) WriteBits(bits uint, n int) (err error) {
|
|
return w.WriteBits64(uint64(bits), n)
|
|
}
|
|
|
|
func (w *Writer) Write(p []byte) (n int, err error) {
|
|
for n < len(p) {
|
|
if err = w.WriteBits64(uint64(p[n]), 8); err != nil {
|
|
return
|
|
}
|
|
n++
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w *Writer) FlushBits() (err error) {
|
|
if w.n > 0 {
|
|
var b [8]byte
|
|
bits := w.bits
|
|
if w.n%8 != 0 {
|
|
bits <<= uint(8 - (w.n % 8))
|
|
}
|
|
want := (w.n + 7) / 8
|
|
for i := 0; i < want; i++ {
|
|
b[i] = byte(bits >> uint((want-i-1)*8))
|
|
}
|
|
if _, err = w.W.Write(b[:want]); err != nil {
|
|
return
|
|
}
|
|
w.n = 0
|
|
}
|
|
return
|
|
}
|