Cleanup sorting logic
There was an unused error value as well as unnecessary usage of the sort interface. There should now be less copying so a bit better performance in some cases.
This commit is contained in:
parent
583b129c94
commit
e8b7b3bcc1
1 changed files with 55 additions and 155 deletions
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.sr.ht/~sircmpwn/aerc/models"
|
"git.sr.ht/~sircmpwn/aerc/models"
|
||||||
"git.sr.ht/~sircmpwn/aerc/worker/types"
|
"git.sr.ht/~sircmpwn/aerc/worker/types"
|
||||||
|
@ -15,51 +14,44 @@ func Sort(messageInfos []*models.MessageInfo,
|
||||||
// loop through in reverse to ensure we sort by non-primary fields first
|
// loop through in reverse to ensure we sort by non-primary fields first
|
||||||
for i := len(criteria) - 1; i >= 0; i-- {
|
for i := len(criteria) - 1; i >= 0; i-- {
|
||||||
criterion := criteria[i]
|
criterion := criteria[i]
|
||||||
var err error
|
|
||||||
switch criterion.Field {
|
switch criterion.Field {
|
||||||
case types.SortArrival:
|
case types.SortArrival:
|
||||||
err = sortDate(messageInfos, criterion,
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
||||||
func(msgInfo *models.MessageInfo) time.Time {
|
return messageInfos[i].InternalDate.Before(messageInfos[j].InternalDate)
|
||||||
return msgInfo.InternalDate
|
|
||||||
})
|
})
|
||||||
case types.SortCc:
|
case types.SortCc:
|
||||||
err = sortAddresses(messageInfos, criterion,
|
sortAddresses(messageInfos, criterion,
|
||||||
func(msgInfo *models.MessageInfo) []*models.Address {
|
func(msgInfo *models.MessageInfo) []*models.Address {
|
||||||
return msgInfo.Envelope.Cc
|
return msgInfo.Envelope.Cc
|
||||||
})
|
})
|
||||||
case types.SortDate:
|
case types.SortDate:
|
||||||
err = sortDate(messageInfos, criterion,
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
||||||
func(msgInfo *models.MessageInfo) time.Time {
|
return messageInfos[i].Envelope.Date.Before(messageInfos[j].Envelope.Date)
|
||||||
return msgInfo.Envelope.Date
|
|
||||||
})
|
})
|
||||||
case types.SortFrom:
|
case types.SortFrom:
|
||||||
err = sortAddresses(messageInfos, criterion,
|
sortAddresses(messageInfos, criterion,
|
||||||
func(msgInfo *models.MessageInfo) []*models.Address {
|
func(msgInfo *models.MessageInfo) []*models.Address {
|
||||||
return msgInfo.Envelope.From
|
return msgInfo.Envelope.From
|
||||||
})
|
})
|
||||||
case types.SortRead:
|
case types.SortRead:
|
||||||
err = sortFlags(messageInfos, criterion, models.SeenFlag)
|
sortFlags(messageInfos, criterion, models.SeenFlag)
|
||||||
case types.SortSize:
|
case types.SortSize:
|
||||||
err = sortInts(messageInfos, criterion,
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
||||||
func(msgInfo *models.MessageInfo) uint32 {
|
return messageInfos[i].Size < messageInfos[j].Size
|
||||||
return msgInfo.Size
|
|
||||||
})
|
})
|
||||||
case types.SortSubject:
|
case types.SortSubject:
|
||||||
err = sortStrings(messageInfos, criterion,
|
sortStrings(messageInfos, criterion,
|
||||||
func(msgInfo *models.MessageInfo) string {
|
func(msgInfo *models.MessageInfo) string {
|
||||||
subject := strings.ToLower(msgInfo.Envelope.Subject)
|
subject := strings.ToLower(msgInfo.Envelope.Subject)
|
||||||
subject = strings.TrimPrefix(subject, "re: ")
|
subject = strings.TrimPrefix(subject, "re: ")
|
||||||
return strings.TrimPrefix(subject, "fwd: ")
|
return strings.TrimPrefix(subject, "fwd: ")
|
||||||
})
|
})
|
||||||
case types.SortTo:
|
case types.SortTo:
|
||||||
err = sortAddresses(messageInfos, criterion,
|
sortAddresses(messageInfos, criterion,
|
||||||
func(msgInfo *models.MessageInfo) []*models.Address {
|
func(msgInfo *models.MessageInfo) []*models.Address {
|
||||||
return msgInfo.Envelope.To
|
return msgInfo.Envelope.To
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var uids []uint32
|
var uids []uint32
|
||||||
// copy in reverse as msgList displays backwards
|
// copy in reverse as msgList displays backwards
|
||||||
|
@ -69,142 +61,10 @@ func Sort(messageInfos []*models.MessageInfo,
|
||||||
return uids, nil
|
return uids, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortDate(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
|
||||||
getValue func(*models.MessageInfo) time.Time) error {
|
|
||||||
var slice []*dateStore
|
|
||||||
for _, msgInfo := range messageInfos {
|
|
||||||
slice = append(slice, &dateStore{
|
|
||||||
Value: getValue(msgInfo),
|
|
||||||
MsgInfo: msgInfo,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sortSlice(criterion, dateSlice{slice})
|
|
||||||
for i := 0; i < len(messageInfos); i++ {
|
|
||||||
messageInfos[i] = slice[i].MsgInfo
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortAddresses(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
func sortAddresses(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
||||||
getValue func(*models.MessageInfo) []*models.Address) error {
|
getValue func(*models.MessageInfo) []*models.Address) {
|
||||||
var slice []*addressStore
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
||||||
for _, msgInfo := range messageInfos {
|
addressI, addressJ := getValue(messageInfos[i]), getValue(messageInfos[j])
|
||||||
slice = append(slice, &addressStore{
|
|
||||||
Value: getValue(msgInfo),
|
|
||||||
MsgInfo: msgInfo,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sortSlice(criterion, addressSlice{slice})
|
|
||||||
for i := 0; i < len(messageInfos); i++ {
|
|
||||||
messageInfos[i] = slice[i].MsgInfo
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortFlags(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
|
||||||
testFlag models.Flag) error {
|
|
||||||
var slice []*boolStore
|
|
||||||
for _, msgInfo := range messageInfos {
|
|
||||||
flagPresent := false
|
|
||||||
for _, flag := range msgInfo.Flags {
|
|
||||||
if flag == testFlag {
|
|
||||||
flagPresent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slice = append(slice, &boolStore{
|
|
||||||
Value: flagPresent,
|
|
||||||
MsgInfo: msgInfo,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sortSlice(criterion, boolSlice{slice})
|
|
||||||
for i := 0; i < len(messageInfos); i++ {
|
|
||||||
messageInfos[i] = slice[i].MsgInfo
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortInts(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
|
||||||
getValue func(*models.MessageInfo) uint32) error {
|
|
||||||
var slice []*intStore
|
|
||||||
for _, msgInfo := range messageInfos {
|
|
||||||
slice = append(slice, &intStore{
|
|
||||||
Value: getValue(msgInfo),
|
|
||||||
MsgInfo: msgInfo,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sortSlice(criterion, intSlice{slice})
|
|
||||||
for i := 0; i < len(messageInfos); i++ {
|
|
||||||
messageInfos[i] = slice[i].MsgInfo
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortStrings(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
|
||||||
getValue func(*models.MessageInfo) string) error {
|
|
||||||
var slice []*lexiStore
|
|
||||||
for _, msgInfo := range messageInfos {
|
|
||||||
slice = append(slice, &lexiStore{
|
|
||||||
Value: getValue(msgInfo),
|
|
||||||
MsgInfo: msgInfo,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sortSlice(criterion, lexiSlice{slice})
|
|
||||||
for i := 0; i < len(messageInfos); i++ {
|
|
||||||
messageInfos[i] = slice[i].MsgInfo
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type lexiStore struct {
|
|
||||||
Value string
|
|
||||||
MsgInfo *models.MessageInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type lexiSlice struct{ Slice []*lexiStore }
|
|
||||||
|
|
||||||
func (s lexiSlice) Len() int { return len(s.Slice) }
|
|
||||||
func (s lexiSlice) Swap(i, j int) { s.Slice[i], s.Slice[j] = s.Slice[j], s.Slice[i] }
|
|
||||||
func (s lexiSlice) Less(i, j int) bool {
|
|
||||||
return s.Slice[i].Value < s.Slice[j].Value
|
|
||||||
}
|
|
||||||
|
|
||||||
type dateStore struct {
|
|
||||||
Value time.Time
|
|
||||||
MsgInfo *models.MessageInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type dateSlice struct{ Slice []*dateStore }
|
|
||||||
|
|
||||||
func (s dateSlice) Len() int { return len(s.Slice) }
|
|
||||||
func (s dateSlice) Swap(i, j int) { s.Slice[i], s.Slice[j] = s.Slice[j], s.Slice[i] }
|
|
||||||
func (s dateSlice) Less(i, j int) bool {
|
|
||||||
return s.Slice[i].Value.Before(s.Slice[j].Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type intStore struct {
|
|
||||||
Value uint32
|
|
||||||
MsgInfo *models.MessageInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type intSlice struct{ Slice []*intStore }
|
|
||||||
|
|
||||||
func (s intSlice) Len() int { return len(s.Slice) }
|
|
||||||
func (s intSlice) Swap(i, j int) { s.Slice[i], s.Slice[j] = s.Slice[j], s.Slice[i] }
|
|
||||||
func (s intSlice) Less(i, j int) bool {
|
|
||||||
return s.Slice[i].Value < s.Slice[j].Value
|
|
||||||
}
|
|
||||||
|
|
||||||
type addressStore struct {
|
|
||||||
Value []*models.Address
|
|
||||||
MsgInfo *models.MessageInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type addressSlice struct{ Slice []*addressStore }
|
|
||||||
|
|
||||||
func (s addressSlice) Len() int { return len(s.Slice) }
|
|
||||||
func (s addressSlice) Swap(i, j int) { s.Slice[i], s.Slice[j] = s.Slice[j], s.Slice[i] }
|
|
||||||
func (s addressSlice) Less(i, j int) bool {
|
|
||||||
addressI, addressJ := s.Slice[i].Value, s.Slice[j].Value
|
|
||||||
var firstI, firstJ *models.Address
|
var firstI, firstJ *models.Address
|
||||||
if len(addressI) > 0 {
|
if len(addressI) > 0 {
|
||||||
firstI = addressI[0]
|
firstI = addressI[0]
|
||||||
|
@ -228,6 +88,53 @@ func (s addressSlice) Less(i, j int) bool {
|
||||||
}
|
}
|
||||||
return getName(firstI) < getName(firstJ)
|
return getName(firstI) < getName(firstJ)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortFlags(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
||||||
|
testFlag models.Flag) {
|
||||||
|
var slice []*boolStore
|
||||||
|
for _, msgInfo := range messageInfos {
|
||||||
|
flagPresent := false
|
||||||
|
for _, flag := range msgInfo.Flags {
|
||||||
|
if flag == testFlag {
|
||||||
|
flagPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slice = append(slice, &boolStore{
|
||||||
|
Value: flagPresent,
|
||||||
|
MsgInfo: msgInfo,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sortSlice(criterion, slice, func(i, j int) bool {
|
||||||
|
valI, valJ := slice[i].Value, slice[j].Value
|
||||||
|
return valI && !valJ
|
||||||
|
})
|
||||||
|
for i := 0; i < len(messageInfos); i++ {
|
||||||
|
messageInfos[i] = slice[i].MsgInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortStrings(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
||||||
|
getValue func(*models.MessageInfo) string) {
|
||||||
|
var slice []*lexiStore
|
||||||
|
for _, msgInfo := range messageInfos {
|
||||||
|
slice = append(slice, &lexiStore{
|
||||||
|
Value: getValue(msgInfo),
|
||||||
|
MsgInfo: msgInfo,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sortSlice(criterion, slice, func(i, j int) bool {
|
||||||
|
return slice[i].Value < slice[j].Value
|
||||||
|
})
|
||||||
|
for i := 0; i < len(messageInfos); i++ {
|
||||||
|
messageInfos[i] = slice[i].MsgInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type lexiStore struct {
|
||||||
|
Value string
|
||||||
|
MsgInfo *models.MessageInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type boolStore struct {
|
type boolStore struct {
|
||||||
|
@ -235,19 +142,12 @@ type boolStore struct {
|
||||||
MsgInfo *models.MessageInfo
|
MsgInfo *models.MessageInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type boolSlice struct{ Slice []*boolStore }
|
func sortSlice(criterion *types.SortCriterion, slice interface{}, less func(i, j int) bool) {
|
||||||
|
|
||||||
func (s boolSlice) Len() int { return len(s.Slice) }
|
|
||||||
func (s boolSlice) Swap(i, j int) { s.Slice[i], s.Slice[j] = s.Slice[j], s.Slice[i] }
|
|
||||||
func (s boolSlice) Less(i, j int) bool {
|
|
||||||
valI, valJ := s.Slice[i].Value, s.Slice[j].Value
|
|
||||||
return valI && !valJ
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortSlice(criterion *types.SortCriterion, interfce sort.Interface) {
|
|
||||||
if criterion.Reverse {
|
if criterion.Reverse {
|
||||||
sort.Stable(sort.Reverse(interfce))
|
sort.SliceStable(slice, func(i, j int) bool {
|
||||||
|
return less(j, i)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
sort.Stable(interfce)
|
sort.SliceStable(slice, less)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue