Skip to content

Instantly share code, notes, and snippets.

@oplanre
Last active February 24, 2025 07:04
Show Gist options
  • Save oplanre/de0bba4f1e2f769458ca1adff7f12280 to your computer and use it in GitHub Desktop.
Save oplanre/de0bba4f1e2f769458ca1adff7f12280 to your computer and use it in GitHub Desktop.
Added NextBitField
package bitfield
import "fmt"
type BitField[T ~uint32 | ~uint64, U ~uint32 | ~uint64] struct {
Shift int
Size int
Mask U
}
// NewBitField creates a new BitField with the given shift and size.
func NewBitField[T ~uint32 | ~uint64, U ~uint32 | ~uint64](shift, size int) BitField[T, U] {
switch bSize := bitSize[U](); {
case shift >= bSize:
panic("invalid shift parameter")
case size >= bSize:
panic("invalid size parameter")
case shift+size > bSize:
panic("invalid shift/size parameters")
case size <= 0:
panic("invalid size parameter")
}
mask := ((U(1) << shift) << size) - (U(1) << shift)
return BitField[T, U]{Shift: shift, Size: size, Mask: mask}
}
// bitSize returns the bit size of a given type.
func bitSize[T any]() int {
var zero T
switch any(zero).(type) {
case uint32:
return 32
case uint64:
return 64
default:
panic("unsupported type")
}
}
// IsValid checks if the value fits within the bit field.
func (bf BitField[T, U]) IsValid(value T) bool {
maxValue := (U(1) << bf.Size) - 1
return U(value)&^maxValue == 0
}
// Encode encodes a value into the bit field.
func (bf BitField[T, U]) Encode(value T) U {
if !bf.IsValid(value) {
panic(fmt.Sprintf("value %v out of range", value))
}
return U(value) << bf.Shift
}
// Update updates the bit field within an existing value.
func (bf BitField[T, U]) Update(previous U, value T) U {
return (previous &^ bf.Mask) | bf.Encode(value)
}
// Decode extracts the bit field from a value.
func (bf BitField[T, U]) Decode(value U) T {
return T((value & bf.Mask) >> bf.Shift)
}
// NextBitField returns a new BitField starting from the previous one.
func (bf BitField[T, U]) NextBitField(size int) BitField[T, U] {
return NewBitField[T, U](bf.Shift+bf.Size, size)
}
/* Examples
// Example 1: Using BitField with uint32
func Example_uint32() {
// Create a bit field for a 4-bit value starting at position 4
bf := NewBitField[uint32, uint32](4, 4)
// Encode the value 5 (0101 in binary) into the bit field
encoded := bf.Encode(5) // Result: 0000 0000 0000 0000 0000 0000 0101 0000
fmt.Printf("Encoded: %032b\n", encoded)
// Decode the value back
decoded := bf.Decode(encoded) // Result: 5
fmt.Printf("Decoded: %d\n", decoded)
// Update an existing value
previous := uint32(0xFF) // 1111 1111
updated := bf.Update(previous, 3) // Will preserve bits outside the field
fmt.Printf("Updated: %032b\n", updated)
}
// Example 2: Using BitField with uint64 for larger values
func Example_uint64() {
// Create three adjacent bit fields in a uint64
colorR := NewBitField[uint32, uint64](0, 8) // 8 bits for red
colorG := colorR.NextBitField(8) // 8 bits for green, equivalent to NewBitField[uint32, uint64](8, 8)
colorB := colorG.NextBitField(8) // 8 bits for blue, equivalent to NewBitField[uint32, uint64](16, 8)
// Build a color value
var color uint64
color = colorR.Update(color, 255) // Set red to max
color = colorG.Update(color, 128) // Set green to mid
color = colorB.Update(color, 64) // Set blue to quarter
// Extract individual components
r := colorR.Decode(color)
g := colorG.Decode(color)
b := colorB.Decode(color)
fmt.Printf("Color RGB: (%d, %d, %d)\n", r, g, b)
}
// Example 3: Demonstrating validation
func Example_validation() {
bf := NewBitField[uint32, uint32](0, 3) // 3-bit field at position 0
// This is valid (value 5 doesn't fit in 3 bits)
fmt.Printf("Is 7 valid? %v\n", bf.IsValid(7)) // true
fmt.Printf("Is 8 valid? %v\n", bf.IsValid(8)) // false
// This will panic due to value being too large for the field
// bf.Encode(8) // Would panic: "value 8 out of range"
}
type Example4Enum uint32
const (
Example4EnumValue1 Example4Enum = 1
Example4EnumValue2 Example4Enum = 2
Example4EnumValue3 Example4Enum = 3
)
func Example4() {
bf := NewBitField[Example4Enum, uint32](0, 2)
// Encode the value Example4EnumValue2
encoded := bf.Encode(Example4EnumValue2)
fmt.Printf("Encoded: %032b\n", encoded)
encoded = bf.Encode(1)
fmt.Printf("Encoded: %032b\n", encoded)
// Decode the value back
decoded := bf.Decode(encoded)
fmt.Printf("Decoded: %d\n", decoded)
//should panic
// bf.Encode(10)
}
func main() {
Example_uint32()
Example_uint64()
Example_validation()
Example4()
}
*/
@oplanre
Copy link
Author

oplanre commented Feb 24, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment