1
1
mirror of https://github.com/wader/fq.git synced 2024-12-23 13:22:58 +03:00

Merge pull request #405 from wader/sort-refactor

sortex: Package with type safe sort helpers
This commit is contained in:
Mattias Wadman 2022-08-30 11:11:10 +02:00 committed by GitHub
commit a87616763e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 64 additions and 59 deletions

View File

@ -137,6 +137,7 @@
"SLEB",
"SLONG",
"SMPTE",
"sortex",
"SRATIONAL",
"stco",
"stedolan",

View File

@ -18,9 +18,9 @@ package mp4
import (
"embed"
"fmt"
"sort"
"github.com/wader/fq/format"
"github.com/wader/fq/internal/sortex"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
)
@ -210,7 +210,7 @@ func mp4Tracks(d *decode.D, ctx *decodeContext) {
for _, t := range ctx.tracks {
sortedTracks = append(sortedTracks, t)
}
sort.Slice(sortedTracks, func(i, j int) bool { return sortedTracks[i].id < sortedTracks[j].id })
sortex.Slice(sortedTracks, func(a, b *track) bool { return a.id < b.id })
d.FieldArray("tracks", func(d *decode.D) {
for _, t := range sortedTracks {

View File

@ -14,13 +14,12 @@ import (
"html"
"io"
"regexp"
"sort"
"strconv"
"strings"
"github.com/wader/fq/format"
"github.com/wader/fq/internal/gojqex"
"github.com/wader/fq/internal/proxysort"
"github.com/wader/fq/internal/sortex"
"github.com/wader/fq/internal/stringsex"
"github.com/wader/fq/pkg/bitio"
"github.com/wader/fq/pkg/decode"
@ -392,14 +391,12 @@ func toXMLFromObject(c any, opts ToXMLOpts) any {
// if one #seq was found, assume all have them, otherwise sort by name
if orderHasSeq {
proxysort.Sort(orderSeqs, n.Nodes, func(ss []int, i, j int) bool { return ss[i] < ss[j] })
sortex.ProxySort(orderSeqs, n.Nodes, func(a, b int) bool { return a < b })
} else {
proxysort.Sort(orderNames, n.Nodes, func(ss []string, i, j int) bool { return ss[i] < ss[j] })
sortex.ProxySort(orderNames, n.Nodes, func(a, b string) bool { return a < b })
}
sort.Slice(n.Attrs, func(i, j int) bool {
return xmlNameSort(n.Attrs[i].Name, n.Attrs[j].Name)
})
sortex.Slice(n.Attrs, func(a, b xml.Attr) bool { return xmlNameSort(a.Name, b.Name) })
return n, seq, hasSeq
}
@ -472,9 +469,7 @@ func toXMLFromArray(c any, opts ToXMLOpts) any {
}
}
sort.Slice(n.Attrs, func(i, j int) bool {
return xmlNameSort(n.Attrs[i].Name, n.Attrs[j].Name)
})
sortex.Slice(n.Attrs, func(a, b xml.Attr) bool { return xmlNameSort(a.Name, b.Name) })
for _, c := range children {
c, ok := c.([]any)

View File

@ -34,9 +34,10 @@ import (
"io"
"math"
"math/big"
"sort"
"strconv"
"unicode/utf8"
"github.com/wader/fq/internal/sortex"
)
type Colors struct {
@ -238,9 +239,7 @@ func (e *Encoder) encodeMap(vs map[string]any) {
kvs[i] = keyVal{k, v}
i++
}
sort.Slice(kvs, func(i, j int) bool {
return kvs[i].key < kvs[j].key
})
sortex.Slice(kvs, func(a, b keyVal) bool { return a.key < b.key })
for i, kv := range kvs {
if e.wErr != nil {
return

View File

@ -1,26 +0,0 @@
// proxysort sorts one slice and but swaps index in two
// assumes both slices have same length.
package proxysort
import "sort"
type proxySort[Tae any, Ta []Tae, Tbe any, Tb []Tbe] struct {
a Ta
b Tb
fn func(Ta []Tae, i, j int) bool
}
func (p proxySort[Tae, Ta, Tbe, Tb]) Len() int { return len(p.a) }
func (p proxySort[Tae, Ta, Tbe, Tb]) Less(i, j int) bool { return p.fn(p.a, i, j) }
func (p proxySort[Tae, Ta, Tbe, Tb]) Swap(i, j int) {
p.a[i], p.a[j] = p.a[j], p.a[i]
p.b[i], p.b[j] = p.b[j], p.b[i]
}
func Sort[Tae any, Ta []Tae, Tbe any, Tb []Tbe](a Ta, b Tb, fn func(Ta []Tae, i, j int) bool) {
sort.Sort(proxySort[Tae, Ta, Tbe, Tb]{a: a, b: b, fn: fn})
}
func Stable[Tae any, Ta []Tae, Tbe any, Tb []Tbe](a Ta, b Tb, fn func(Ta []Tae, i, j int) bool) {
sort.Stable(proxySort[Tae, Ta, Tbe, Tb]{a: a, b: b, fn: fn})
}

View File

@ -10,11 +10,11 @@ import (
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"github.com/wader/fq/internal/shquote"
"github.com/wader/fq/internal/sortex"
"github.com/wader/fq/pkg/bitio"
"github.com/wader/fq/pkg/interp"
)
@ -273,9 +273,7 @@ type Case struct {
func (c *Case) ToActual() string {
var partsLineSorted []part
partsLineSorted = append(partsLineSorted, c.Parts...)
sort.Slice(partsLineSorted, func(i, j int) bool {
return partsLineSorted[i].Line() < partsLineSorted[j].Line()
})
sortex.Slice(partsLineSorted, func(a, b part) bool { return a.Line() < b.Line() })
sb := &strings.Builder{}
for _, p := range partsLineSorted {

View File

@ -0,0 +1,28 @@
package sortex
import "sort"
type proxySort[Tae any, Ta []Tae, Tbe any, Tb []Tbe] struct {
a Ta
b Tb
fn func(a, b Tae) bool
}
func (p proxySort[Tae, Ta, Tbe, Tb]) Len() int { return len(p.a) }
func (p proxySort[Tae, Ta, Tbe, Tb]) Less(i, j int) bool { return p.fn(p.a[i], p.a[j]) }
func (p proxySort[Tae, Ta, Tbe, Tb]) Swap(i, j int) {
p.a[i], p.a[j] = p.a[j], p.a[i]
p.b[i], p.b[j] = p.b[j], p.b[i]
}
// ProxySort same as sort.Sort but is type safe, swaps an additional slice b and also does indexing
// Assumes both slices have same length.
func ProxySort[Tae any, Ta []Tae, Tbe any, Tb []Tbe](a Ta, b Tb, fn func(a, b Tae) bool) {
sort.Sort(proxySort[Tae, Ta, Tbe, Tb]{a: a, b: b, fn: fn})
}
// ProxyStable same as sort.Proxy but is type safe, swaps an additional slice b and also does indexing
// Assumes both slices have same length.
func ProxyStable[Tae any, Ta []Tae, Tbe any, Tb []Tbe](a Ta, b Tb, fn func(a, b Tae) bool) {
sort.Stable(proxySort[Tae, Ta, Tbe, Tb]{a: a, b: b, fn: fn})
}

13
internal/sortex/sort.go Normal file
View File

@ -0,0 +1,13 @@
package sortex
import "sort"
// Slice same as sort.Slice but type safe and also indexes for you
func Slice[T any](s []T, less func(a, b T) bool) {
sort.Slice(s, func(i, j int) bool { return less(s[i], s[j]) })
}
// SliceStable same as sort.SliceStable but type safe and also indexes for you
func SliceStable[T any](s []T, less func(a, b T) bool) {
sort.SliceStable(s, func(i, j int) bool { return less(s[i], s[j]) })
}

View File

@ -2,8 +2,8 @@ package decode
import (
"errors"
"sort"
"github.com/wader/fq/internal/sortex"
"github.com/wader/fq/pkg/bitio"
"github.com/wader/fq/pkg/ranges"
"github.com/wader/fq/pkg/scalar"
@ -200,9 +200,7 @@ func (v *Value) postProcess() {
// TODO: really sort array? if sort it needs to be stable to keep the order
// of value with same range start, think null values etc
if vv.RangeSorted {
sort.SliceStable(vv.Children, func(i, j int) bool {
return (vv.Children)[i].Range.Start < (vv.Children)[j].Range.Start
})
sortex.SliceStable(vv.Children, func(a, b *Value) bool { return a.Range.Start < b.Range.Start })
}
v.Index = -1

View File

@ -4,10 +4,10 @@ import (
"errors"
"fmt"
"io/fs"
"sort"
"sync"
"github.com/wader/fq/internal/gojqex"
"github.com/wader/fq/internal/sortex"
"github.com/wader/fq/pkg/decode"
)
@ -67,11 +67,11 @@ func (r *Registry) Func(funcFn EnvFuncFn) {
}
func sortFormats(g decode.Group) {
sort.Slice(g, func(i, j int) bool {
if g[i].ProbeOrder == g[j].ProbeOrder {
return g[i].Name < g[j].Name
sortex.Slice(g, func(a, b decode.Format) bool {
if a.ProbeOrder == b.ProbeOrder {
return a.Name < b.Name
}
return g[i].ProbeOrder < g[j].ProbeOrder
return a.ProbeOrder < b.ProbeOrder
})
}

View File

@ -2,9 +2,10 @@ package ranges
import (
"fmt"
"sort"
"strconv"
"strings"
"github.com/wader/fq/internal/sortex"
)
func max(a, b int64) int64 {
@ -62,9 +63,7 @@ func Gaps(total Range, ranges []Range) []Range {
return []Range{total}
}
sort.Slice(ranges, func(i, j int) bool {
return ranges[i].Start < ranges[j].Start
})
sortex.Slice(ranges, func(a, b Range) bool { return a.Start < b.Start })
// worst case ranges+1 gaps
merged := make([]Range, 0, len(ranges)+1)