mirror of
https://github.com/tiny-craft/tiny-rdm.git
synced 2026-04-22 16:07:06 +08:00
feat: add 'BitSet' viewer (#503)
This commit is contained in:
@@ -7,6 +7,7 @@ const FORMAT_YAML = "YAML"
|
||||
const FORMAT_XML = "XML"
|
||||
const FORMAT_HEX = "Hex"
|
||||
const FORMAT_BINARY = "Binary"
|
||||
const FORMAT_BITSET = "BitSet"
|
||||
|
||||
const DECODE_NONE = "None"
|
||||
const DECODE_BASE64 = "Base64"
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package convutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BitSetConvert struct{}
|
||||
|
||||
func (BitSetConvert) Enable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (BitSetConvert) Encode(str string) (string, bool) {
|
||||
var result strings.Builder
|
||||
|
||||
str = strings.ReplaceAll(str, "\r\n", "\n") // CRLF → LF
|
||||
str = strings.ReplaceAll(str, "\r", "\n") // CR → LF
|
||||
|
||||
lines := strings.Split(str, "\n")
|
||||
bytes := EncodeToRedisBitset(lines)
|
||||
result.Write(bytes)
|
||||
|
||||
return result.String(), true
|
||||
}
|
||||
|
||||
// EncodeToRedisBitset encodes a list of strings with integers (positions) into a Redis bitset byte array.
|
||||
// The bit at position 'n' will be set to 1 if n is in the input array.
|
||||
// The resulting byte slice can be stored in Redis using SET command.
|
||||
func EncodeToRedisBitset(numbers []string) []byte {
|
||||
if len(numbers) == 0 {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// Find the maximum number to determine the required bit length and convert strings to numbers
|
||||
maxNum := uint64(0)
|
||||
var validNumbers []uint64
|
||||
for _, s := range numbers {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
num, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil || num < 0 || num > math.MaxUint32 {
|
||||
fmt.Printf("Warning: skipping invalid number '%s': %v\n", s, err)
|
||||
continue
|
||||
}
|
||||
validNumbers = append(validNumbers, num)
|
||||
if num > maxNum {
|
||||
maxNum = num
|
||||
}
|
||||
}
|
||||
|
||||
if len(validNumbers) == 0 {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// Calculate required byte length (8 bits per byte)
|
||||
byteLen := ((maxNum + 7) / 8) + 1
|
||||
|
||||
// Initialize byte array
|
||||
bitset := make([]byte, byteLen)
|
||||
|
||||
// Set bits for each number
|
||||
for _, num := range validNumbers {
|
||||
byteIndex := num / 8
|
||||
if byteIndex < byteLen {
|
||||
bitIndex := uint(num % 8)
|
||||
// Set the bit (big-endian bit order within byte)
|
||||
bitset[byteIndex] |= 1 << (7 - bitIndex)
|
||||
}
|
||||
}
|
||||
|
||||
return bitset
|
||||
}
|
||||
|
||||
func (BitSetConvert) Decode(str string) (string, bool) {
|
||||
bitset := getBitSet([]byte(str))
|
||||
|
||||
var binBuilder strings.Builder
|
||||
for key, value := range bitset {
|
||||
if value {
|
||||
binBuilder.WriteString(fmt.Sprintf("%v\n", key))
|
||||
//binBuilder.WriteString(fmt.Sprintf("Bit %v = %v \n", key, value))
|
||||
}
|
||||
}
|
||||
|
||||
return binBuilder.String(), true
|
||||
}
|
||||
|
||||
func getBitSet(redisResponse []byte) []bool {
|
||||
bitset := make([]bool, len(redisResponse)*8)
|
||||
for i := range redisResponse {
|
||||
for j := 7; j >= 0; j-- {
|
||||
bit_n := uint(i*8 + (7 - j))
|
||||
bitset[bit_n] = (redisResponse[i] & (1 << uint(j))) > 0
|
||||
}
|
||||
}
|
||||
return bitset
|
||||
}
|
||||
@@ -20,6 +20,7 @@ var (
|
||||
xmlConv XmlConvert
|
||||
base64Conv Base64Convert
|
||||
binaryConv BinaryConvert
|
||||
bitSetConv BitSetConvert
|
||||
hexConv HexConvert
|
||||
gzipConv GZipConvert
|
||||
deflateConv DeflateConvert
|
||||
@@ -38,6 +39,7 @@ var BuildInFormatters = map[string]DataConvert{
|
||||
types.FORMAT_XML: xmlConv,
|
||||
types.FORMAT_HEX: hexConv,
|
||||
types.FORMAT_BINARY: binaryConv,
|
||||
types.FORMAT_BITSET: bitSetConv,
|
||||
}
|
||||
|
||||
var BuildInDecoders = map[string]DataConvert{
|
||||
|
||||
@@ -10,6 +10,7 @@ export const formatTypes = {
|
||||
XML: 'XML',
|
||||
HEX: 'Hex',
|
||||
BINARY: 'Binary',
|
||||
BITSET: 'BitSet',
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user