工具类
工具类是直接拷贝的 https://github.com/HDT3213/godis 大佬 lib 下面的工具类然后我加上了注释以及改了一些书写的方式,目前用到以下几个,都放在 lib 路径下
atomic.go
// Boolean boolean类型原生不是线程安全的,这里进行改造一下,将其变为线程安全
type Boolean uint32
// Get 加载出数据的值
func (b *Boolean) Get() bool {
return atomic.LoadUint32((*uint32)(b)) != 0
}
// Set 原子化设置bool的值
func (b *Boolean) Set(v bool) {
if v {
atomic.StoreUint32((*uint32)(b), 1)
} else {
atomic.StoreUint32((*uint32)(b), 0)
}
}
utils.go
- ToCmdLine:将字符串转换为二维字节数组
- ToCmdLine2:可以拼接数据,后续aof进行输出的时候需要用到
- BytesEquals:两个字节数据进行对象是否相同
// ToCmdLine convert strings to [][]byte
func ToCmdLine(cmd ...string) [][]byte {
args := make([][]byte, len(cmd))
for i, s := range cmd {
args[i] = []byte(s)
}
return args
}
// ToCmdLine2 convert commandName and []byte-type argument to CmdLine
func ToCmdLine2(commandName string, args ...[]byte) [][]byte {
result := make([][]byte, len(args)+1)
result[0] = []byte(commandName)
for i, s := range args {
result[i+1] = s
}
return result
}
// BytesEquals check whether the given bytes is equal
func BytesEquals(a []byte, b []byte) bool {
if (a == nil && b != nil) || (a != nil && b == nil) {
return false
}
if len(a) != len(b) {
return false
}
size := len(a)
for i := 0; i < size; i++ {
av := a[i]
bv := b[i]
if av != bv {
return false
}
}
return true
}
wait.go
定义了一个可以等待超时的组工具
// Wait 创建一个带有超时的Wait等待组
type Wait struct {
wg sync.WaitGroup
}
// Add adds delta, which may be negative, to the WaitGroup counter.
func (w *Wait) Add(delta int) {
w.wg.Add(delta)
}
// Done 每完成一次就减一次
func (w *Wait) Done() {
w.wg.Done()
}
// Wait 阻塞在这里直到计数器为0
func (w *Wait) Wait() {
w.wg.Wait()
}
// WaitWithTimeout 等待组新增超时的任务
func (w *Wait) WaitWithTimeout(timeout time.Duration) bool {
//创建一个管道
c := make(chan struct{}, 1)
//开启协程
go func() {
//协程退出时关闭管道
defer close(c)
//等待数据
w.Wait()
//写入信号量,通知超时
c <- struct{}{}
}()
//判断c管道中是否有信号通知,如果有信号通知,直接退出
select {
case <-c:
return false // 正常情况退出
case <-time.After(timeout):
return true // 超时
}
}
wildcard.go
用于匹配命令中的表达式的工具类
const (
normal = iota
all // *
any // ?
setSymbol // []
rangSymbol // [a-b]
negSymbol // [^a]
)
type item struct {
character byte
set map[byte]bool
typeCode int
}
func (i *item) contains(c byte) bool {
if i.typeCode == setSymbol {
_, ok := i.set[c]
return ok
} else if i.typeCode == rangSymbol {
if _, ok := i.set[c]; ok {
return true
}
var (
min uint8 = 255
max uint8 = 0
)
for k := range i.set {
if min > k {
min = k
}
if max < k {
max = k
}
}
return c >= min && c <= max
} else {
_, ok := i.set[c]
return !ok
}
}
// Pattern represents a wildcard pattern
type Pattern struct {
items []*item
}
// CompilePattern convert wildcard string to Pattern
func CompilePattern(src string) *Pattern {
items := make([]*item, 0)
escape := false
inSet := false
var set map[byte]bool
for _, v := range src {
c := byte(v)
if escape {
items = append(items, &item{typeCode: normal, character: c})
escape = false
} else if c == '*' {
items = append(items, &item{typeCode: all})
} else if c == '?' {
items = append(items, &item{typeCode: any})
} else if c == '\\' {
escape = true
} else if c == '[' {
if !inSet {
inSet = true
set = make(map[byte]bool)
} else {
set[c] = true
}
} else if c == ']' {
if inSet {
inSet = false
typeCode := setSymbol
if _, ok := set['-']; ok {
typeCode = rangSymbol
delete(set, '-')
}
if _, ok := set['^']; ok {
typeCode = negSymbol
delete(set, '^')
}
items = append(items, &item{typeCode: typeCode, set: set})
} else {
items = append(items, &item{typeCode: normal, character: c})
}
} else {
if inSet {
set[c] = true
} else {
items = append(items, &item{typeCode: normal, character: c})
}
}
}
return &Pattern{
items: items,
}
}
// IsMatch returns whether the given string matches pattern
func (p *Pattern) IsMatch(s string) bool {
if len(p.items) == 0 {
return len(s) == 0
}
m := len(s)
n := len(p.items)
table := make([][]bool, m+1)
for i := 0; i < m+1; i++ {
table[i] = make([]bool, n+1)
}
table[0][0] = true
for j := 1; j < n+1; j++ {
table[0][j] = table[0][j-1] && p.items[j-1].typeCode == all
}
for i := 1; i < m+1; i++ {
for j := 1; j < n+1; j++ {
if p.items[j-1].typeCode == all {
table[i][j] = table[i-1][j] || table[i][j-1]
} else {
table[i][j] = table[i-1][j-1] &&
(p.items[j-1].typeCode == any ||
(p.items[j-1].typeCode == normal && uint8(s[i-1]) == p.items[j-1].character) ||
(p.items[j-1].typeCode >= setSymbol && p.items[j-1].contains(s[i-1])))
}
}
}
return table[m][n]
}