Skip to content

Commit

Permalink
Optimize allocations in newRouteRegexp
Browse files Browse the repository at this point in the history
  • Loading branch information
Tit Petric committed Apr 2, 2024
1 parent 7d9a6f7 commit ed62916
Showing 1 changed file with 37 additions and 16 deletions.
53 changes: 37 additions & 16 deletions regexp.go
Expand Up @@ -65,67 +65,88 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro
}
varsN := make([]string, len(idxs)/2)
varsR := make([]*regexp.Regexp, len(idxs)/2)
pattern := bytes.NewBufferString("")

var pattern, reverse strings.Builder
pattern.WriteByte('^')
reverse := bytes.NewBufferString("")
var end int

var end, colonIdx, groupIdx int
var err error
var patt, param, name string
for i := 0; i < len(idxs); i += 2 {
// Set all values we are interested in.
groupIdx = i/2

raw := tpl[end:idxs[i]]
end = idxs[i+1]
parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2)
name := parts[0]
patt := defaultPattern
if len(parts) == 2 {
patt = parts[1]

param = tpl[idxs[i]+1 : end-1]
colonIdx = strings.Index(param, ":")
if colonIdx == -1 {
name = param
patt = defaultPattern
} else {
name = param[0:colonIdx]
patt = param[colonIdx+1:]
}
if patt == "" {
patt = defaultPattern
}

// Name or pattern can't be empty.
if name == "" || patt == "" {
return nil, fmt.Errorf("mux: missing name or pattern in %q",
tpl[idxs[i]:end])
return nil, fmt.Errorf("mux: missing name or pattern in %q", param)
}
// Build the regexp pattern.
fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt)
groupName := varGroupName(groupIdx)

pattern.WriteString(regexp.QuoteMeta(raw)+"(?P<" + groupName + ">" + patt + ")")

// Build the reverse template.
fmt.Fprintf(reverse, "%s%%s", raw)
reverse.WriteString(raw+"%s")

// Append variable name and compiled pattern.
varsN[i/2] = name
varsR[i/2], err = RegexpCompileFunc(fmt.Sprintf("^%s$", patt))
varsN[groupIdx] = name
varsR[groupIdx], err = RegexpCompileFunc("^" + patt + "$")
if err != nil {
return nil, err
}
}
// Add the remaining.
raw := tpl[end:]
pattern.WriteString(regexp.QuoteMeta(raw))

if options.strictSlash {
pattern.WriteString("[/]?")
}

if typ == regexpTypeQuery {
// Add the default pattern if the query value is empty
if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
pattern.WriteString(defaultPattern)
}
}

if typ != regexpTypePrefix {
pattern.WriteByte('$')
}

patternStr := pattern.String()

var wildcardHostPort bool
if typ == regexpTypeHost {
if !strings.Contains(pattern.String(), ":") {
if !strings.Contains(patternStr, ":") {
wildcardHostPort = true
}
}

reverse.WriteString(raw)

if endSlash {
reverse.WriteByte('/')
}

// Compile full regexp.
reg, errCompile := RegexpCompileFunc(pattern.String())
reg, errCompile := RegexpCompileFunc(patternStr)
if errCompile != nil {
return nil, errCompile
}
Expand Down

0 comments on commit ed62916

Please sign in to comment.