Skip to content

Commit

Permalink
Update minimal go version to 1.18
Browse files Browse the repository at this point in the history
Upgrading to 1.18 allows the package to rely on generic implementations
of its internal stack and queue data structures.
  • Loading branch information
beevik committed Jul 6, 2024
1 parent 4fe8b8c commit cd04677
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

strategy:
matrix:
go-version: [ '1.16', '1.21', '1.22.x' ]
go-version: [ '1.18', '1.21', '1.22.x' ]

steps:
- uses: actions/checkout@v4
Expand Down
35 changes: 11 additions & 24 deletions etree.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"errors"
"io"
"os"
"sort"
"slices"

Check failure on line 16 in etree.go

View workflow job for this annotation

GitHub Actions / build (1.18)

package slices is not in GOROOT (/opt/hostedtoolcache/go/1.18.10/x64/src/slices)
"strings"
)

Expand Down Expand Up @@ -858,12 +858,12 @@ func (e *Element) RemoveChildAt(index int) Token {

// autoClose analyzes the stack's top element and the current token to decide
// whether the top element should be closed.
func (e *Element) autoClose(stack *stack, t xml.Token, tags []string) {
func (e *Element) autoClose(stack *stack[*Element], t xml.Token, tags []string) {
if stack.empty() {
return
}

top := stack.peek().(*Element)
top := stack.peek()

for _, tag := range tags {
if strings.EqualFold(tag, top.FullTag()) {
Expand Down Expand Up @@ -891,7 +891,7 @@ func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err er

dec := newDecoder(r, settings)

var stack stack
var stack stack[*Element]
stack.push(e)
for {
if pr != nil {
Expand All @@ -916,7 +916,7 @@ func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err er
return r.Bytes(), ErrXML
}

top := stack.peek().(*Element)
top := stack.peek()

switch t := t.(type) {
case xml.StartElement:
Expand Down Expand Up @@ -1411,25 +1411,12 @@ func (e *Element) RemoveAttr(key string) *Attr {

// SortAttrs sorts this element's attributes lexicographically by key.
func (e *Element) SortAttrs() {
sort.Sort(byAttr(e.Attr))
}

type byAttr []Attr

func (a byAttr) Len() int {
return len(a)
}

func (a byAttr) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}

func (a byAttr) Less(i, j int) bool {
sp := strings.Compare(a[i].Space, a[j].Space)
if sp == 0 {
return strings.Compare(a[i].Key, a[j].Key) < 0
}
return sp < 0
slices.SortFunc(e.Attr, func(a, b Attr) int {
if v := strings.Compare(a.Space, b.Space); v != 0 {
return v
}
return strings.Compare(a.Key, b.Key)
})
}

// FullKey returns this attribute's complete key, including namespace prefix
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/beevik/etree

go 1.16
go 1.18
38 changes: 19 additions & 19 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,36 @@ import (
"unicode/utf8"
)

// A simple stack
type stack struct {
data []interface{}
type stack[E any] struct {
data []E
}

func (s *stack) empty() bool {
func (s *stack[E]) empty() bool {
return len(s.data) == 0
}

func (s *stack) push(value interface{}) {
func (s *stack[E]) push(value E) {
s.data = append(s.data, value)
}

func (s *stack) pop() interface{} {
func (s *stack[E]) pop() E {
value := s.data[len(s.data)-1]
s.data[len(s.data)-1] = nil
var empty E
s.data[len(s.data)-1] = empty
s.data = s.data[:len(s.data)-1]
return value
}

func (s *stack) peek() interface{} {
func (s *stack[E]) peek() E {
return s.data[len(s.data)-1]
}

// A fifo is a simple first-in-first-out queue.
type fifo struct {
data []interface{}
type queue[E any] struct {
data []E
head, tail int
}

func (f *fifo) add(value interface{}) {
func (f *queue[E]) add(value E) {
if f.len()+1 >= len(f.data) {
f.grow()
}
Expand All @@ -50,33 +49,34 @@ func (f *fifo) add(value interface{}) {
}
}

func (f *fifo) remove() interface{} {
func (f *queue[E]) remove() E {
value := f.data[f.head]
f.data[f.head] = nil
var empty E
f.data[f.head] = empty
if f.head++; f.head == len(f.data) {
f.head = 0
}
return value
}

func (f *fifo) len() int {
func (f *queue[E]) len() int {
if f.tail >= f.head {
return f.tail - f.head
}
return len(f.data) - f.head + f.tail
}

func (f *fifo) grow() {
func (f *queue[E]) grow() {
c := len(f.data) * 2
if c == 0 {
c = 4
}
buf, count := make([]interface{}, c), f.len()
buf, count := make([]E, c), f.len()
if f.tail >= f.head {
copy(buf[0:count], f.data[f.head:f.tail])
copy(buf[:count], f.data[f.head:f.tail])
} else {
hindex := len(f.data) - f.head
copy(buf[0:hindex], f.data[f.head:])
copy(buf[:hindex], f.data[f.head:])
copy(buf[hindex:count], f.data[:f.tail])
}
f.data, f.head, f.tail = buf, 0, count
Expand Down
8 changes: 4 additions & 4 deletions path.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ type filter interface {
// a Path object. It collects and deduplicates all elements matching
// the path query.
type pather struct {
queue fifo
queue queue[node]
results []*Element
inResults map[*Element]bool
candidates []*Element
Expand Down Expand Up @@ -180,7 +180,7 @@ func newPather() *pather {
// and filters.
func (p *pather) traverse(e *Element, path Path) []*Element {
for p.queue.add(node{e, path.segments}); p.queue.len() > 0; {
p.eval(p.queue.remove().(node))
p.eval(p.queue.remove())
}
return p.results
}
Expand Down Expand Up @@ -406,9 +406,9 @@ func (s *selectChildren) apply(e *Element, p *pather) {
type selectDescendants struct{}

func (s *selectDescendants) apply(e *Element, p *pather) {
var queue fifo
var queue queue[*Element]
for queue.add(e); queue.len() > 0; {
e := queue.remove().(*Element)
e := queue.remove()
p.candidates = append(p.candidates, e)
for _, c := range e.Child {
if c, ok := c.(*Element); ok {
Expand Down

0 comments on commit cd04677

Please sign in to comment.