Skip to content

proposal: math/bits: add Select to select bit fields #66200

@dsnet

Description

@dsnet

Proposal Details

In many wire formats (e.g., CBOR, zstandard, brotli, etc.), it is common to have fields in a integer semantically represent something else. Examples: zstd frame descriptor, window descriptor, CBOR packing for major type and "additional information", etc.

Bit fields can be trivial selected out an integer through bit-shift and mask operations, but the code is not as readable:

blockType := (blockHeader >> 1) & 3

I propose adding:

// Selects selects n bits starting at the ith bit.
// Indexing begins with the least-significant bit.
// Bit fields beyond the representation are implicitly treated as zero.
func Select(x uint, i, n uint) uint {
    return (x >> i) & ((1 <<  n) - 1)
}

along with the 8, 16, 32, and 64 variants.

Example usage:

lastBlock := bits.Select32(blockHeader, 0, 1)
blockType := bits.Select32(blockHeader, 1, 2)
blockSize := bits.Select32(blockHeader, 3, 21)

The goal of this API is for readability of bit-twiddling code, rather than performance (which should not be affected).
Since Select is inlineable, it will practically be identical to the bitwise code that someone may write after the compiler applies constant folding.

An open API question is whether to represent a selection as:

  • an offset and length as currently proposed, or
  • a start offset and inclusive end offset, or
  • a start offset and exclusive end offset (similar to slicing).

I chose to represent it as a length as this avoids any edge cases for when the end offset is before the start offset.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions