mirror of
https://github.com/wader/fq.git
synced 2024-12-23 21:31:33 +03:00
Merge pull request #405 from wader/sort-refactor
sortex: Package with type safe sort helpers
This commit is contained in:
commit
a87616763e
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -137,6 +137,7 @@
|
||||
"SLEB",
|
||||
"SLONG",
|
||||
"SMPTE",
|
||||
"sortex",
|
||||
"SRATIONAL",
|
||||
"stco",
|
||||
"stedolan",
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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})
|
||||
}
|
@ -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 {
|
||||
|
28
internal/sortex/proxysort.go
Normal file
28
internal/sortex/proxysort.go
Normal 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
13
internal/sortex/sort.go
Normal 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]) })
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user