You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
naza/pkg/ic/lf_compressor.go

124 lines
2.4 KiB
Go

5 years ago
// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
5 years ago
package ic
import (
"encoding/binary"
)
type LFCompressor struct {
FB uint32 // 用几个字节的 bit 表示跟随的数据
ZlibExt bool // 压缩之后,是否再用 zlib 进一步压缩
oc OriginCompressor // FB 为0时退化成使用 OriginCompressor
}
// 传入的整型切片必须是从小到大有序排列
func (lfc *LFCompressor) Marshal(ids []uint32) (ret []byte) {
if lfc.FB == 0 {
ret = lfc.oc.Marshal(ids)
if lfc.ZlibExt {
ret = zlibWrite(ret)
}
return ret
}
lBuf := make([]byte, 4)
fBuf := make([]byte, lfc.FB)
maxDiff := 8 * lfc.FB
var hasLeader bool
var leader uint32
var stage int
for i := range ids {
if !hasLeader {
stage = 1
leader = ids[i]
hasLeader = true
continue
}
diff := uint32(ids[i] - leader)
if diff > maxDiff {
binary.LittleEndian.PutUint32(lBuf, leader)
ret = append(ret, lBuf...)
ret = append(ret, fBuf...)
resetBuf(fBuf)
stage = 2
leader = ids[i]
} else {
stage = 3
fBuf[(diff-1)/8] = fBuf[(diff-1)/8] | (1 << byte((diff-1)%8))
}
}
switch stage {
case 1:
binary.LittleEndian.PutUint32(lBuf, leader)
ret = append(ret, lBuf...)
dummy := make([]byte, lfc.FB)
ret = append(ret, dummy...)
case 2:
binary.LittleEndian.PutUint32(lBuf, leader)
ret = append(ret, lBuf...)
dummy := make([]byte, lfc.FB)
ret = append(ret, dummy...)
case 3:
binary.LittleEndian.PutUint32(lBuf, leader)
ret = append(ret, lBuf...)
ret = append(ret, fBuf...)
}
if lfc.ZlibExt {
ret = zlibWrite(ret)
}
return
}
func (lfc *LFCompressor) Unmarshal(b []byte) (ids []uint32) {
if lfc.ZlibExt {
b = zlibRead(b)
}
if lfc.FB == 0 {
return lfc.oc.Unmarshal(b)
}
isLeaderStage := true
var item uint32
var leader uint32
var index uint32
for {
if isLeaderStage {
leader = binary.LittleEndian.Uint32(b[index:])
ids = append(ids, leader)
isLeaderStage = false
index += 4
} else {
for i := uint32(0); i < lfc.FB; i++ {
for j := uint32(0); j < 8; j++ {
if ((b[index+i] >> j) & 1) == 1 {
item = leader + (i * 8) + j + 1
ids = append(ids, item)
}
}
}
isLeaderStage = true
index += lfc.FB
}
if int(index) == len(b) {
break
}
}
return
}