bitstream

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 20, 2025 License: Apache-2.0 Imports: 4 Imported by: 0

README

bitstream-go

A Go library for efficient bit-level reading and writing operations on integer slices.

Features

  • BitReader: Read bits from integer slices with configurable padding
    • Block-based reading (Read8R, Read16R, etc.)
    • Cursor-based reading (ReadBit, ReadBitAt, Pos, Seek)
    • Not thread-safe: Use separate instances for concurrent access
  • BitWriter: Write bits to integer slices with automatic allocation
    • Block-based writing (Write8, Write16, etc.)
    • Cursor-based writing (WriteBit, WriteBitAt, Pos, Seek)
    • Thread-safe: All operations protected by mutex
  • Generic support for uint8, uint16, uint32, uint64, and uint
  • Configurable left and right padding for each element
  • Error handling following Go standard library conventions (io.EOF, ErrNegativePosition)

Installation

go get github.com/yyyoichi/bitstream-go

Usage

BitReader

Read bits from an integer slice:

package main

import (
    "fmt"
    "io"
    "github.com/yyyoichi/bitstream-go"
)

func main() {
    data := []uint8{0b10101100, 0b11100011}
    reader := bitstream.NewBitReader(data, 0, 0) // no padding
    
    // Block-based reading
    value := reader.Read16R(12, 0) // returns 0b101011001110
    value2 := reader.Read8R(4, 2)  // returns 0b1110
    
    // Cursor-based sequential reading
    bit, err := reader.ReadBit() // reads first bit (true), advances cursor
    if err == io.EOF {
        fmt.Println("end of data")
    }
    
    // Random access reading (doesn't move cursor)
    bit2, err := reader.ReadBitAt(5) // reads bit at position 5
    
    // Cursor positioning
    reader.Seek(8) // move cursor to position 8
    pos := reader.Pos() // get current position
}
BitWriter

Write bits to create an integer slice:

package main

import "github.com/yyyoichi/bitstream-go"

func main() {
    writer := bitstream.NewBitWriter[uint8](0, 0) // no padding
    
    // Block-based writing
    writer.Write16(0, 12, 0b101011001110)
    writer.WriteBool(true)
    
    // Cursor-based sequential writing
    writer.WriteBit(true)  // writes at current position, advances cursor
    writer.WriteBit(false)
    
    // Random access writing (doesn't move cursor)
    writer.WriteBitAt(5, true) // writes bit at position 5
    
    // Cursor positioning
    writer.Seek(0)  // move cursor to start
    pos := writer.Pos() // get current position
    
    // Get the result
    data := writer.Data()
    bits := writer.Bits()
    // data = []uint8{...}
    // bits = total number of bits written
}
Padding

Configure padding to skip bits at the start or end of each element:

// Skip 2 bits from the left and 1 bit from the right in each uint8
reader := bitstream.NewBitReader(data, 2, 1) // 5 valid bits per element

writer := bitstream.NewBitWriter[uint16](4, 0) // skip 4 top bits, 12 valid bits per element

API

BitReader

Constructor:

  • NewBitReader[T](data []T, leftPadd, rightPadd int) *BitReader[T] - Create a new reader

Block-based reading:

  • Read8R(bits, n int) uint8 - Read up to 8 bits from n-th block
  • Read16R(bits, n int) uint16 - Read up to 16 bits from n-th block
  • Read32R(bits, n int) uint32 - Read up to 32 bits from n-th block
  • Read64R(bits, n int) uint64 - Read up to 64 bits from n-th block

Cursor-based reading:

  • ReadBit() (bool, error) - Read one bit at cursor and advance (returns io.EOF if out of bounds)
  • ReadBitAt(pos int) (bool, error) - Read one bit at position without moving cursor (returns io.EOF if out of bounds, ErrNegativePosition for negative positions)
  • Pos() int - Get current cursor position
  • Seek(pos int) error - Set cursor position (returns ErrNegativePosition for negative positions)

Other:

  • Bits() int - Get total number of valid bits
  • SetBits(bits int) - Limit readable range
  • Data() []T - Get source data slice
  • AnyData() any - Get source data as 'any' type
BitWriter

Constructor:

  • NewBitWriter[T](leftPadd, rightPadd int) *BitWriter[T] - Create a new writer

Block-based writing:

  • Write8(leftPadd, bits int, data uint8) - Write up to 8 bits
  • Write16(leftPadd, bits int, data uint16) - Write up to 16 bits
  • Write32(leftPadd, bits int, data uint32) - Write up to 32 bits
  • Write64(leftPadd, bits int, data uint64) - Write up to 64 bits
  • WriteBool(data bool) - Write a single bit

Cursor-based writing:

  • WriteBit(bit bool) error - Write one bit at cursor and advance (auto-extends data slice)
  • WriteBitAt(pos int, bit bool) error - Write one bit at position without moving cursor (supports overwriting, returns ErrNegativePosition for negative positions)
  • Pos() int - Get current cursor position (thread-safe)
  • Seek(pos int) error - Set cursor position (returns ErrNegativePosition for negative positions)

Other:

  • Data() []T - Get accumulated data slice
  • AnyData() any - Get data as 'any' type
  • Bits() int - Get total number of bits written

License

Apache 2.0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNegativePosition is returned when a negative position is provided to Seek or WriteBitAt/ReadBitAt.
	ErrNegativePosition = errors.New("bitstream: negative position")
)

Functions

This section is empty.

Types

type BitReader

type BitReader[T Unsigned] struct {
	// contains filtered or unexported fields
}

BitReader provides bit-level reading operations on integer slice data. It treats the data as a continuous bit stream, allowing precise bit extraction.

BitReader is not safe for concurrent use. If multiple goroutines access the same BitReader, external synchronization is required. For concurrent reading scenarios, create separate BitReader instances for each goroutine.

func NewBitReader

func NewBitReader[T Unsigned](data []T, leftPadd, rightPadd int) *BitReader[T]

NewBitReader creates a new BitReader for manipulating bits from integer slice data. leftPadd specifies how many upper bits in each element should be treated as padding. rightPadd specifies how many lower bits in each element should be treated as padding. For example, if each element has 2 bits of padding at the top and 1 bit at the bottom, set leftPadd=2 and rightPadd=1. The reader will only access bits from position leftPadd to (element size - rightPadd).

Panics if leftPadd + rightPadd >= element bit size, as this would leave no valid bits to read.

func (*BitReader[T]) AnyData added in v0.2.0

func (r *BitReader[T]) AnyData() any

AnyData returns the source data as an any type. This is useful when the exact type of the underlying data slice is not known at compile time. Use Bits() to get the total number of valid bits.

func (*BitReader[T]) Bits added in v0.1.1

func (r *BitReader[T]) Bits() int

Bits returns the total number of valid bits in the BitReader.

func (*BitReader[T]) Data added in v0.2.0

func (r *BitReader[T]) Data() []T

Data returns the source data slice. Use Bits() to get the total number of valid bits.

func (*BitReader[T]) Pos added in v0.2.0

func (r *BitReader[T]) Pos() int

Pos returns the current read position (cursor).

func (*BitReader[T]) Read16R added in v0.2.0

func (r *BitReader[T]) Read16R(bits, n int) (b uint16)

Read16R reads a specified number of bits from the n-th position in the data. bits specifies how many bits to read (up to 16 bits). n specifies which block to read (0-indexed). Returns the bits as a uint16 value, right-aligned (LSB-aligned).

Panics if bits > 16, as uint16 can only hold 16 bits.

func (*BitReader[T]) Read32R added in v0.2.0

func (r *BitReader[T]) Read32R(bits, n int) (b uint32)

Read32R reads a specified number of bits from the n-th position in the data. bits specifies how many bits to read (up to 32 bits). n specifies which block to read (0-indexed). Returns the bits as a uint16 value, right-aligned (LSB-aligned).

Panics if bits > 32, as uint16 can only hold 32 bits.

func (*BitReader[T]) Read64R added in v0.2.0

func (r *BitReader[T]) Read64R(bits, n int) (b uint64)

Read64R reads a specified number of bits from the n-th position in the data. bits specifies how many bits to read (up to 64 bits). n specifies which block to read (0-indexed). Returns the bits as a uint16 value, right-aligned (LSB-aligned).

Panics if bits > 64, as uint16 can only hold 64 bits.

func (*BitReader[T]) Read8R added in v0.2.0

func (r *BitReader[T]) Read8R(bits, n int) uint8

Read8R reads a specified number of bits from the n-th position in the data. bits specifies how many bits to read (up to 8 bits). n specifies which block to read (0-indexed). Returns the bits as a uint16 value, right-aligned (LSB-aligned).

Panics if bits > 8, as uint16 can only hold 8 bits.

func (*BitReader[T]) ReadBit added in v0.2.0

func (r *BitReader[T]) ReadBit() (bool, error)

ReadBit reads one bit at the current position and advances the cursor. Returns false and io.EOF if the position is beyond the valid bits.

func (*BitReader[T]) ReadBitAt added in v0.2.0

func (r *BitReader[T]) ReadBitAt(pos int) (bool, error)

ReadBitAt reads one bit at the specified position without moving the cursor. Returns false and io.EOF if the position is beyond the valid bits. Returns false and ErrNegativePosition for negative positions.

func (*BitReader[T]) Seek added in v0.2.0

func (r *BitReader[T]) Seek(pos int) error

Seek sets the read position (cursor). Allows seeking to any non-negative position, including beyond the valid bits. Subsequent reads will return io.EOF if the position is at or beyond the valid bits. Returns ErrNegativePosition for negative positions.

func (*BitReader[T]) SetBits

func (r *BitReader[T]) SetBits(bits int)

SetBits sets the total number of valid bits in the BitReader. if bits exceeds the maximum possible bits based on the data length and padding, it will be capped to that maximum. Data beyond the specified bits position will be treated as zero, regardless of the actual padding configuration. This is useful for limiting the readable range within the data.

type BitWriter

type BitWriter[T Unsigned] struct {
	// contains filtered or unexported fields
}

BitWriter provides bit-level writing operations to integer slice data. It treats the destination as a continuous bit stream, allowing precise bit insertion.

BitWriter is safe for concurrent use. All methods are protected by an internal mutex, allowing multiple goroutines to safely write to the same BitWriter instance.

func NewBitWriter

func NewBitWriter[T Unsigned](leftPadd, rightPadd int) *BitWriter[T]

NewBitWriter creates a new BitWriter for writing bits to integer slice data. leftPadd specifies how many upper bits in each element should be treated as padding. rightPadd specifies how many lower bits in each element should be treated as padding. The writer will only write bits to the valid range between paddings.

Panics if leftPadd + rightPadd >= element bit size, as this would leave no valid bits to write.

func (*BitWriter[T]) AnyData added in v0.1.2

func (w *BitWriter[T]) AnyData() any

AnyData returns the accumulated data as an any type. This is useful when the exact type of the underlying data slice is not known at compile time. Use Bits() to get the total number of valid bits written.

func (*BitWriter[T]) Bits added in v0.2.0

func (w *BitWriter[T]) Bits() int

Bits returns the total number of valid bits in the BitWriter.

func (*BitWriter[T]) Data

func (w *BitWriter[T]) Data() []T

Data returns the accumulated data slice. Use Bits() to get the total number of valid bits written.

func (*BitWriter[T]) Pos added in v0.2.0

func (w *BitWriter[T]) Pos() int

Pos returns the current write position (cursor).

func (*BitWriter[T]) Seek added in v0.2.0

func (w *BitWriter[T]) Seek(pos int) error

Seek sets the write position (cursor). Allows seeking to any non-negative position, including beyond current data. Returns ErrNegativePosition for negative positions.

func (*BitWriter[T]) Write16 added in v0.2.0

func (w *BitWriter[T]) Write16(leftPadd, bits int, data uint16)

Write16 writes the specified bits from a uint16 value to the stream. leftPadd specifies how many upper bits to skip in the source data. bits specifies how many bits to write after skipping leftPadd bits.

Panics if leftPadd + bits > 16.

func (*BitWriter[T]) Write32 added in v0.2.0

func (w *BitWriter[T]) Write32(leftPadd, bits int, data uint32)

Write32 writes the specified bits from a uint32 value to the stream. leftPadd specifies how many upper bits to skip in the source data. bits specifies how many bits to write after skipping leftPadd bits.

Panics if leftPadd + bits > 32.

func (*BitWriter[T]) Write64 added in v0.2.0

func (w *BitWriter[T]) Write64(leftPadd, bits int, data uint64)

Write64 writes the specified bits from a uint64 value to the stream. leftPadd specifies how many upper bits to skip in the source data. bits specifies how many bits to write after skipping leftPadd bits.

Panics if leftPadd + bits > 64.

func (*BitWriter[T]) Write8 added in v0.2.0

func (w *BitWriter[T]) Write8(leftPadd, bits int, data uint8)

Write8 writes the specified bits from a uint8 value to the stream. leftPadd specifies how many upper bits to skip in the source data. bits specifies how many bits to write after skipping leftPadd bits.

Panics if leftPadd + bits > 8.

func (*BitWriter[T]) WriteBit added in v0.2.0

func (w *BitWriter[T]) WriteBit(bit bool) error

WriteBit writes one bit at the current position and advances the cursor. Automatically extends the data slice if writing beyond current length.

func (*BitWriter[T]) WriteBitAt added in v0.2.0

func (w *BitWriter[T]) WriteBitAt(pos int, bit bool) error

WriteBitAt writes one bit at the specified position without moving the cursor. Automatically extends the data slice if writing beyond current length. Returns ErrNegativePosition for negative positions.

func (*BitWriter[T]) WriteBool added in v0.2.0

func (w *BitWriter[T]) WriteBool(data bool)

WriteBool writes a single boolean value as one bit to the stream.

type Unsigned added in v0.2.0

type Unsigned interface {
	~uint64 | ~uint32 | ~uint16 | ~uint8 | ~uint
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL