mirror of
https://github.com/wader/fq.git
synced 2024-12-24 13:52:02 +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",
|
"SLEB",
|
||||||
"SLONG",
|
"SLONG",
|
||||||
"SMPTE",
|
"SMPTE",
|
||||||
|
"sortex",
|
||||||
"SRATIONAL",
|
"SRATIONAL",
|
||||||
"stco",
|
"stco",
|
||||||
"stedolan",
|
"stedolan",
|
||||||
|
@ -18,9 +18,9 @@ package mp4
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/wader/fq/format"
|
"github.com/wader/fq/format"
|
||||||
|
"github.com/wader/fq/internal/sortex"
|
||||||
"github.com/wader/fq/pkg/decode"
|
"github.com/wader/fq/pkg/decode"
|
||||||
"github.com/wader/fq/pkg/interp"
|
"github.com/wader/fq/pkg/interp"
|
||||||
)
|
)
|
||||||
@ -210,7 +210,7 @@ func mp4Tracks(d *decode.D, ctx *decodeContext) {
|
|||||||
for _, t := range ctx.tracks {
|
for _, t := range ctx.tracks {
|
||||||
sortedTracks = append(sortedTracks, t)
|
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) {
|
d.FieldArray("tracks", func(d *decode.D) {
|
||||||
for _, t := range sortedTracks {
|
for _, t := range sortedTracks {
|
||||||
|
@ -14,13 +14,12 @@ import (
|
|||||||
"html"
|
"html"
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/wader/fq/format"
|
"github.com/wader/fq/format"
|
||||||
"github.com/wader/fq/internal/gojqex"
|
"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/internal/stringsex"
|
||||||
"github.com/wader/fq/pkg/bitio"
|
"github.com/wader/fq/pkg/bitio"
|
||||||
"github.com/wader/fq/pkg/decode"
|
"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 one #seq was found, assume all have them, otherwise sort by name
|
||||||
if orderHasSeq {
|
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 {
|
} 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 {
|
sortex.Slice(n.Attrs, func(a, b xml.Attr) bool { return xmlNameSort(a.Name, b.Name) })
|
||||||
return xmlNameSort(n.Attrs[i].Name, n.Attrs[j].Name)
|
|
||||||
})
|
|
||||||
|
|
||||||
return n, seq, hasSeq
|
return n, seq, hasSeq
|
||||||
}
|
}
|
||||||
@ -472,9 +469,7 @@ func toXMLFromArray(c any, opts ToXMLOpts) any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(n.Attrs, func(i, j int) bool {
|
sortex.Slice(n.Attrs, func(a, b xml.Attr) bool { return xmlNameSort(a.Name, b.Name) })
|
||||||
return xmlNameSort(n.Attrs[i].Name, n.Attrs[j].Name)
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, c := range children {
|
for _, c := range children {
|
||||||
c, ok := c.([]any)
|
c, ok := c.([]any)
|
||||||
|
@ -34,9 +34,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/wader/fq/internal/sortex"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Colors struct {
|
type Colors struct {
|
||||||
@ -238,9 +239,7 @@ func (e *Encoder) encodeMap(vs map[string]any) {
|
|||||||
kvs[i] = keyVal{k, v}
|
kvs[i] = keyVal{k, v}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
sort.Slice(kvs, func(i, j int) bool {
|
sortex.Slice(kvs, func(a, b keyVal) bool { return a.key < b.key })
|
||||||
return kvs[i].key < kvs[j].key
|
|
||||||
})
|
|
||||||
for i, kv := range kvs {
|
for i, kv := range kvs {
|
||||||
if e.wErr != nil {
|
if e.wErr != nil {
|
||||||
return
|
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"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/wader/fq/internal/shquote"
|
"github.com/wader/fq/internal/shquote"
|
||||||
|
"github.com/wader/fq/internal/sortex"
|
||||||
"github.com/wader/fq/pkg/bitio"
|
"github.com/wader/fq/pkg/bitio"
|
||||||
"github.com/wader/fq/pkg/interp"
|
"github.com/wader/fq/pkg/interp"
|
||||||
)
|
)
|
||||||
@ -273,9 +273,7 @@ type Case struct {
|
|||||||
func (c *Case) ToActual() string {
|
func (c *Case) ToActual() string {
|
||||||
var partsLineSorted []part
|
var partsLineSorted []part
|
||||||
partsLineSorted = append(partsLineSorted, c.Parts...)
|
partsLineSorted = append(partsLineSorted, c.Parts...)
|
||||||
sort.Slice(partsLineSorted, func(i, j int) bool {
|
sortex.Slice(partsLineSorted, func(a, b part) bool { return a.Line() < b.Line() })
|
||||||
return partsLineSorted[i].Line() < partsLineSorted[j].Line()
|
|
||||||
})
|
|
||||||
|
|
||||||
sb := &strings.Builder{}
|
sb := &strings.Builder{}
|
||||||
for _, p := range partsLineSorted {
|
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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sort"
|
|
||||||
|
|
||||||
|
"github.com/wader/fq/internal/sortex"
|
||||||
"github.com/wader/fq/pkg/bitio"
|
"github.com/wader/fq/pkg/bitio"
|
||||||
"github.com/wader/fq/pkg/ranges"
|
"github.com/wader/fq/pkg/ranges"
|
||||||
"github.com/wader/fq/pkg/scalar"
|
"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
|
// 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
|
// of value with same range start, think null values etc
|
||||||
if vv.RangeSorted {
|
if vv.RangeSorted {
|
||||||
sort.SliceStable(vv.Children, func(i, j int) bool {
|
sortex.SliceStable(vv.Children, func(a, b *Value) bool { return a.Range.Start < b.Range.Start })
|
||||||
return (vv.Children)[i].Range.Start < (vv.Children)[j].Range.Start
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v.Index = -1
|
v.Index = -1
|
||||||
|
@ -4,10 +4,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"sort"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/wader/fq/internal/gojqex"
|
"github.com/wader/fq/internal/gojqex"
|
||||||
|
"github.com/wader/fq/internal/sortex"
|
||||||
"github.com/wader/fq/pkg/decode"
|
"github.com/wader/fq/pkg/decode"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,11 +67,11 @@ func (r *Registry) Func(funcFn EnvFuncFn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sortFormats(g decode.Group) {
|
func sortFormats(g decode.Group) {
|
||||||
sort.Slice(g, func(i, j int) bool {
|
sortex.Slice(g, func(a, b decode.Format) bool {
|
||||||
if g[i].ProbeOrder == g[j].ProbeOrder {
|
if a.ProbeOrder == b.ProbeOrder {
|
||||||
return g[i].Name < g[j].Name
|
return a.Name < b.Name
|
||||||
}
|
}
|
||||||
return g[i].ProbeOrder < g[j].ProbeOrder
|
return a.ProbeOrder < b.ProbeOrder
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@ package ranges
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wader/fq/internal/sortex"
|
||||||
)
|
)
|
||||||
|
|
||||||
func max(a, b int64) int64 {
|
func max(a, b int64) int64 {
|
||||||
@ -62,9 +63,7 @@ func Gaps(total Range, ranges []Range) []Range {
|
|||||||
return []Range{total}
|
return []Range{total}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(ranges, func(i, j int) bool {
|
sortex.Slice(ranges, func(a, b Range) bool { return a.Start < b.Start })
|
||||||
return ranges[i].Start < ranges[j].Start
|
|
||||||
})
|
|
||||||
|
|
||||||
// worst case ranges+1 gaps
|
// worst case ranges+1 gaps
|
||||||
merged := make([]Range, 0, len(ranges)+1)
|
merged := make([]Range, 0, len(ranges)+1)
|
||||||
|
Loading…
Reference in New Issue
Block a user