Skip to content

Commit

Permalink
use the existing pattern compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
alicebob committed Jul 20, 2019
1 parent 597660d commit f4d82fd
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 110 deletions.
112 changes: 6 additions & 106 deletions cmd_pubsub.go
Expand Up @@ -4,7 +4,6 @@ package miniredis

import (
"fmt"
"regexp"
"strings"

"github.com/alicebob/miniredis/v2/server"
Expand Down Expand Up @@ -92,116 +91,17 @@ func (m *Miniredis) cmdPsubscribe(c *server.Peer, cmd string, args []string) {
sub := m.subscribedState(c)
for _, pat := range args {
n := sub.Psubscribe(pat)
c.Block(func(c *server.Writer) {
c.WriteLen(3)
c.WriteBulk("psubscribe")
c.WriteBulk(pat)
c.WriteInt(n)
c.Block(func(w *server.Writer) {
w.WriteLen(3)
w.WriteBulk("psubscribe")
w.WriteBulk(pat)
w.WriteInt(n)
})
c.Flush()
}
})
}

func compileChannelPattern(pattern string) *regexp.Regexp {
const readingLiteral uint8 = 0
const afterEscape uint8 = 1
const inClass uint8 = 2

rgx := []rune{'\\', 'A'}
state := readingLiteral
literals := []rune{}
klass := map[rune]struct{}{}

for _, c := range pattern {
switch state {
case readingLiteral:
switch c {
case '\\':
state = afterEscape
case '?':
rgx = append(rgx, append([]rune(regexp.QuoteMeta(string(literals))), '.')...)
literals = []rune{}
case '*':
rgx = append(rgx, append([]rune(regexp.QuoteMeta(string(literals))), '.', '*')...)
literals = []rune{}
case '[':
rgx = append(rgx, []rune(regexp.QuoteMeta(string(literals)))...)
literals = []rune{}
state = inClass
default:
literals = append(literals, c)
}
case afterEscape:
literals = append(literals, c)
state = readingLiteral
case inClass:
if c == ']' {
expr := []rune{'['}

if _, hasDash := klass['-']; hasDash {
delete(klass, '-')
expr = append(expr, '-')
}

flatClass := make([]rune, len(klass))
i := 0

for c := range klass {
flatClass[i] = c
i++
}

klass = map[rune]struct{}{}
expr = append(append(expr, []rune(regexp.QuoteMeta(string(flatClass)))...), ']')

if len(expr) < 3 {
rgx = append(rgx, 'x', '\\', 'b', 'y')
} else {
rgx = append(rgx, expr...)
}

state = readingLiteral
} else {
klass[c] = struct{}{}
}
}
}

switch state {
case afterEscape:
rgx = append(rgx, '\\', '\\')
case inClass:
if len(klass) < 0 {
rgx = append(rgx, '\\', '[')
} else {
expr := []rune{'['}

if _, hasDash := klass['-']; hasDash {
delete(klass, '-')
expr = append(expr, '-')
}

flatClass := make([]rune, len(klass))
i := 0

for c := range klass {
flatClass[i] = c
i++
}

expr = append(append(expr, []rune(regexp.QuoteMeta(string(flatClass)))...), ']')

if len(expr) < 3 {
rgx = append(rgx, 'x', '\\', 'b', 'y')
} else {
rgx = append(rgx, expr...)
}
}
}

return regexp.MustCompile(string(append(rgx, '\\', 'z')))
}

// PUNSUBSCRIBE
func (m *Miniredis) cmdPunsubscribe(c *server.Peer, cmd string, args []string) {
if !m.handleAuth(c) {
Expand Down
4 changes: 2 additions & 2 deletions keys.go
@@ -1,13 +1,13 @@
package miniredis

// Translate the 'KEYS' argument ('foo*', 'f??', &c.) into a regexp.
// Translate the 'KEYS' or 'PSUBSCRIBE' argument ('foo*', 'f??', &c.) into a regexp.

import (
"bytes"
"regexp"
)

// patternRE compiles a KEYS argument to a regexp. Returns nil if the given
// patternRE compiles a glob to a regexp. Returns nil if the given
// pattern will never match anything.
// The general strategy is to sandwich all non-meta characters between \Q...\E.
func patternRE(k string) *regexp.Regexp {
Expand Down
4 changes: 2 additions & 2 deletions pubsub.go
Expand Up @@ -83,7 +83,7 @@ func (s *Subscriber) Psubscribe(pat string) int {
s.mu.Lock()
defer s.mu.Unlock()

s.patterns[pat] = compileChannelPattern(pat)
s.patterns[pat] = patternRE(pat)
return s.count()
}

Expand Down Expand Up @@ -176,7 +176,7 @@ func activeChannels(subs []*Subscriber, pat string) []string {

var cpat *regexp.Regexp
if pat != "" {
cpat = compileChannelPattern(pat)
cpat = patternRE(pat)
}

var cs []string
Expand Down

0 comments on commit f4d82fd

Please sign in to comment.