Skip to content

Commit

Permalink
🛶 domainset: add DomainBinarySearchMatcher
Browse files Browse the repository at this point in the history
And it immediately became dead code, because it's slower than linear search at all lengths.

Still, keep the code to participate in benchmarks, just to remind us how slow it is.
  • Loading branch information
database64128 committed Mar 23, 2023
1 parent 44e7125 commit 4d47fb1
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 5 deletions.
55 changes: 54 additions & 1 deletion domainset/matcher_domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

// MaxLinearDomains is the maximum number of domain rules under which a linear matcher can outperform a map matcher.
const MaxLinearDomains = 8
const MaxLinearDomains = 16

// DomainLinearMatcher matches domain rules using linear search.
// It is faster than [DomainMapMatcher] when the number of rules is
Expand Down Expand Up @@ -58,6 +58,59 @@ func (dlmp *DomainLinearMatcher) AppendTo(matchers []Matcher) ([]Matcher, error)
return append(matchers, dlmp), nil
}

// DomainBinarySearchMatcher matches domain rules using binary search.
type DomainBinarySearchMatcher []string

// NewDomainBinarySearchMatcher creates a [DomainBinarySearchMatcher] with the specified initial capacity.
func NewDomainBinarySearchMatcher(capacity int) MatcherBuilder {
dbsm := make(DomainBinarySearchMatcher, 0, capacity)
return &dbsm
}

// DomainBinarySearchMatcherFromSlice creates a [DomainBinarySearchMatcher] from a slice of domain rules.
func DomainBinarySearchMatcherFromSlice(domains []string) DomainBinarySearchMatcher {
slices.Sort(domains)
return domains
}

// Match implements the Matcher Match method.
func (dbsm DomainBinarySearchMatcher) Match(domain string) bool {
_, found := slices.BinarySearch(dbsm, domain)
return found
}

// Insert implements the MatcherBuilder Insert method.
func (dbsmp *DomainBinarySearchMatcher) Insert(rule string) {
index, found := slices.BinarySearch(*dbsmp, rule)
if !found {
*dbsmp = slices.Insert(*dbsmp, index, rule)
}
}

// Rules implements the MatcherBuilder Rules method.
func (dbsm DomainBinarySearchMatcher) Rules() []string {
return dbsm
}

// MatcherCount implements the MatcherBuilder MatcherCount method.
func (dbsm DomainBinarySearchMatcher) MatcherCount() int {
if len(dbsm) == 0 {
return 0
}
return 1
}

// AppendTo implements the MatcherBuilder AppendTo method.
func (dbsmp *DomainBinarySearchMatcher) AppendTo(matchers []Matcher) ([]Matcher, error) {
dbsm := *dbsmp

if len(dbsm) == 0 {
return matchers, nil
}

return append(matchers, dbsmp), nil
}

// DomainMapMatcher matches domain rules using a map.
// It is faster than [DomainLinearMatcher] when the number of rules is
// greater than [MaxLinearDomains].
Expand Down
22 changes: 19 additions & 3 deletions domainset/matcher_domain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ import (

const testMissDomain = "aur.archlinux.org"

var testDomains = [12]string{
var testDomains = [...]string{
"example.com",
"github.com",
"cube64128.xyz",
"www.cube64128.xyz",
"api.ipify.org",
"api6.ipify.org",
"archlinux.org",
"aur.archlinux.org",
"wiki.archlinux.org",
"dash.cloudflare.com",
"api.cloudflare.com",
"google.com",
"www.google.com",
"youtube.com",
"www.youtube.com",
"localdomain",
}

Expand All @@ -43,14 +47,19 @@ func testDomainMatcher(t *testing.T, m Matcher) {
testMatcher(t, m, "api64.ipify.org", false)
testMatcher(t, m, "www.ipify.org", false)
testMatcher(t, m, "archlinux.org", true)
testMatcher(t, m, "aur.archlinux.org", false)
testMatcher(t, m, "aur.archlinux.org", true)
testMatcher(t, m, "bugs.archlinux.org", false)
testMatcher(t, m, "wiki.archlinux.org", true)
testMatcher(t, m, "cloudflare", false)
testMatcher(t, m, "cloudflare.com", false)
testMatcher(t, m, "dash.cloudflare.com", true)
testMatcher(t, m, "api.cloudflare.com", true)
testMatcher(t, m, "google.com", true)
testMatcher(t, m, "www.google.com", true)
testMatcher(t, m, "amervice.google.com", false)
testMatcher(t, m, "youtube.com", true)
testMatcher(t, m, "www.youtube.com", true)
testMatcher(t, m, "m.youtube.com", false)
testMatcher(t, m, "localdomain", true)
testMatcher(t, m, "www.localdomain", false)
}
Expand All @@ -60,6 +69,11 @@ func TestDomainLinearMatcher(t *testing.T) {
testDomainMatcher(t, &dlm)
}

func TestDomainBinarySearchMatcher(t *testing.T) {
dbsm := DomainBinarySearchMatcherFromSlice(testDomains[:])
testDomainMatcher(t, &dbsm)
}

func TestDomainMapMatcher(t *testing.T) {
dmm := DomainMapMatcherFromSlice(testDomains[:])
testDomainMatcher(t, &dmm)
Expand All @@ -79,10 +93,12 @@ func benchmarkDomainMatcher(b *testing.B, count int, name string, m Matcher) {
}

func BenchmarkDomainMatchers(b *testing.B) {
for i := len(testDomains) / 2; i <= len(testDomains); i += 2 {
for i := len(testDomains) / 4; i <= len(testDomains); i += 3 {
dlm := DomainLinearMatcher(testDomains[:i])
dbsm := DomainBinarySearchMatcherFromSlice(testDomains[:i])
dmm := DomainMapMatcherFromSlice(testDomains[:i])
benchmarkDomainMatcher(b, i, "DomainLinearMatcher", &dlm)
benchmarkDomainMatcher(b, i, "DomainBinarySearchMatcher", &dbsm)
benchmarkDomainMatcher(b, i, "DomainMapMatcher", &dmm)
}
}
2 changes: 1 addition & 1 deletion domainset/matcher_suffix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const (
longDomain = "cant.come.up.with.a.long.domain.name"
)

var testSuffixes = [8]string{
var testSuffixes = [...]string{
"example.com",
"github.com",
"cube64128.xyz",
Expand Down

0 comments on commit 4d47fb1

Please sign in to comment.