diff --git a/bench_query_test.go b/bench_query_test.go index 9994cc4..2a68ad6 100644 --- a/bench_query_test.go +++ b/bench_query_test.go @@ -16,7 +16,7 @@ func BenchmarkIs(b *testing.B) { b.Logf("Is=%v", y) } -func BenchmarkIsRequiresContext(b *testing.B) { +func BenchmarkIsPositional(b *testing.B) { var y bool b.StopTimer() @@ -25,7 +25,7 @@ func BenchmarkIsRequiresContext(b *testing.B) { for i := 0; i < b.N; i++ { y = sel.Is("li:nth-child(2)") } - b.Logf("IsRequiresContext=%v", y) + b.Logf("IsPositional=%v", y) } func BenchmarkIsFunction(b *testing.B) { diff --git a/bench_traversal_test.go b/bench_traversal_test.go index bc2e4e4..23daa11 100644 --- a/bench_traversal_test.go +++ b/bench_traversal_test.go @@ -5,7 +5,162 @@ import ( ) func BenchmarkFind(b *testing.B) { + var n int + for i := 0; i < b.N; i++ { - DocB().Root.Find("dd") + if n == 0 { + n = DocB().Root.Find("dd").Length() + + } else { + DocB().Root.Find("dd") + } } + b.Logf("Find=%d", n) +} + +func BenchmarkFindWithinSelection(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find("ul") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.Find("a[class]").Length() + } else { + sel.Find("a[class]") + } + } + b.Logf("FindWithinSelection=%d", n) +} + +func BenchmarkFindSelection(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find("ul") + sel2 := DocW().Root.Find("span") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.FindSelection(sel2).Length() + } else { + sel.FindSelection(sel2) + } + } + b.Logf("FindSelection=%d", n) +} + +func BenchmarkFindNodes(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find("ul") + sel2 := DocW().Root.Find("span") + nodes := sel2.Nodes + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.FindNodes(nodes...).Length() + } else { + sel.FindNodes(nodes...) + } + } + b.Logf("FindNodes=%d", n) +} + +func BenchmarkContents(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find(".toclevel-1") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.Contents().Length() + } else { + sel.Contents() + } + } + b.Logf("Contents=%d", n) +} + +func BenchmarkContentsFiltered(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find(".toclevel-1") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.ContentsFiltered("a[href=\"#Examples\"]").Length() + } else { + sel.ContentsFiltered("a[href=\"#Examples\"]") + } + } + b.Logf("ContentsFiltered=%d", n) +} + +func BenchmarkChildren(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find(".toclevel-2") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.Children().Length() + } else { + sel.Children() + } + } + b.Logf("Children=%d", n) +} + +func BenchmarkChildrenFiltered(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find("h3") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.ChildrenFiltered(".editsection").Length() + } else { + sel.ChildrenFiltered(".editsection") + } + } + b.Logf("ChildrenFiltered=%d", n) +} + +func BenchmarkParent(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find("li") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.Parent().Length() + } else { + sel.Parent() + } + } + b.Logf("Parent=%d", n) +} + +func BenchmarkParentFiltered(b *testing.B) { + var n int + + b.StopTimer() + sel := DocW().Root.Find("li") + b.StartTimer() + for i := 0; i < b.N; i++ { + if n == 0 { + n = sel.ParentFiltered("ul[id]").Length() + } else { + sel.ParentFiltered("ul[id]") + } + } + b.Logf("ParentFiltered=%d", n) } diff --git a/query.go b/query.go index daf0cef..fb687ea 100644 --- a/query.go +++ b/query.go @@ -7,14 +7,19 @@ import ( "strings" ) -var rxNeedsContext = `^[\x20\t\r\n\f]*[>+~]|:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\)|)(?:[^-]|$)` +//var rxNeedsContext = `^[\x20\t\r\n\f]*[>+~]|:(nth|eq|gt|lt|first|last|even|odd)(-child)?(?:\((\d*)\)|)(?:[^-]|$)` // Is() checks the current matched set of elements against a selector and // returns true if at least one of these elements matches. func (this *Selection) Is(selector string) bool { if len(this.Nodes) > 0 { // The selector must be done on the document if it has positional criteria - if ok, e := regexp.MatchString(rxNeedsContext, selector); ok { + + // TODO : Not sure it is required, as Cascadia's selector checks within the parent of the + // node when there is such a positionaly selector... In jQuery, this is for the + // non-css selectors (Sizzle-implemented selectors, an extension of CSS) + + /*if ok, e := regexp.MatchString(rxNeedsContext, selector); ok { sel := this.document.Root.Find(selector) for _, n := range this.Nodes { if sel.IndexOfNode(n) > -1 { @@ -25,15 +30,15 @@ func (this *Selection) Is(selector string) bool { } else if e != nil { panic(e.Error()) + } else {*/ + // Attempt a match with the selector + cs := cascadia.MustCompile(selector) + if len(this.Nodes) == 1 { + return cs.Match(this.Nodes[0]) } else { - // Attempt a match with the selector - cs := cascadia.MustCompile(selector) - if len(this.Nodes) == 1 { - return cs.Match(this.Nodes[0]) - } else { - return len(cs.Filter(this.Nodes)) > 0 - } + return len(cs.Filter(this.Nodes)) > 0 } + //} } return false