From e8b7b3bcc16329ab9fe402d6629db775f197b73b Mon Sep 17 00:00:00 2001 From: Jeffas Date: Sat, 29 Feb 2020 01:27:31 +0000 Subject: [PATCH] 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. --- worker/lib/sort.go | 210 ++++++++++++--------------------------------- 1 file changed, 55 insertions(+), 155 deletions(-) diff --git a/worker/lib/sort.go b/worker/lib/sort.go index 36c0924..ac8ed07 100644 --- a/worker/lib/sort.go +++ b/worker/lib/sort.go @@ -4,7 +4,6 @@ import ( "fmt" "sort" "strings" - "time" "git.sr.ht/~sircmpwn/aerc/models" "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 for i := len(criteria) - 1; i >= 0; i-- { criterion := criteria[i] - var err error switch criterion.Field { case types.SortArrival: - err = sortDate(messageInfos, criterion, - func(msgInfo *models.MessageInfo) time.Time { - return msgInfo.InternalDate - }) + sortSlice(criterion, messageInfos, func(i, j int) bool { + return messageInfos[i].InternalDate.Before(messageInfos[j].InternalDate) + }) case types.SortCc: - err = sortAddresses(messageInfos, criterion, + sortAddresses(messageInfos, criterion, func(msgInfo *models.MessageInfo) []*models.Address { return msgInfo.Envelope.Cc }) case types.SortDate: - err = sortDate(messageInfos, criterion, - func(msgInfo *models.MessageInfo) time.Time { - return msgInfo.Envelope.Date - }) + sortSlice(criterion, messageInfos, func(i, j int) bool { + return messageInfos[i].Envelope.Date.Before(messageInfos[j].Envelope.Date) + }) case types.SortFrom: - err = sortAddresses(messageInfos, criterion, + sortAddresses(messageInfos, criterion, func(msgInfo *models.MessageInfo) []*models.Address { return msgInfo.Envelope.From }) case types.SortRead: - err = sortFlags(messageInfos, criterion, models.SeenFlag) + sortFlags(messageInfos, criterion, models.SeenFlag) case types.SortSize: - err = sortInts(messageInfos, criterion, - func(msgInfo *models.MessageInfo) uint32 { - return msgInfo.Size - }) + sortSlice(criterion, messageInfos, func(i, j int) bool { + return messageInfos[i].Size < messageInfos[j].Size + }) case types.SortSubject: - err = sortStrings(messageInfos, criterion, + sortStrings(messageInfos, criterion, func(msgInfo *models.MessageInfo) string { subject := strings.ToLower(msgInfo.Envelope.Subject) subject = strings.TrimPrefix(subject, "re: ") return strings.TrimPrefix(subject, "fwd: ") }) case types.SortTo: - err = sortAddresses(messageInfos, criterion, + sortAddresses(messageInfos, criterion, func(msgInfo *models.MessageInfo) []*models.Address { return msgInfo.Envelope.To }) } - if err != nil { - return nil, err - } } var uids []uint32 // copy in reverse as msgList displays backwards @@ -69,40 +61,38 @@ func Sort(messageInfos []*models.MessageInfo, 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, - getValue func(*models.MessageInfo) []*models.Address) error { - var slice []*addressStore - for _, msgInfo := range messageInfos { - 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 + getValue func(*models.MessageInfo) []*models.Address) { + sortSlice(criterion, messageInfos, func(i, j int) bool { + addressI, addressJ := getValue(messageInfos[i]), getValue(messageInfos[j]) + var firstI, firstJ *models.Address + if len(addressI) > 0 { + firstI = addressI[0] + } + if len(addressJ) > 0 { + firstJ = addressJ[0] + } + if firstI == nil && firstJ == nil { + return false + } else if firstI == nil && firstJ != nil { + return false + } else if firstI != nil && firstJ == nil { + return true + } else /* firstI != nil && firstJ != nil */ { + getName := func(addr *models.Address) string { + if addr.Name != "" { + return addr.Name + } else { + return fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host) + } + } + return getName(firstI) < getName(firstJ) + } + }) } func sortFlags(messageInfos []*models.MessageInfo, criterion *types.SortCriterion, - testFlag models.Flag) error { + testFlag models.Flag) { var slice []*boolStore for _, msgInfo := range messageInfos { flagPresent := false @@ -116,31 +106,17 @@ func sortFlags(messageInfos []*models.MessageInfo, criterion *types.SortCriterio MsgInfo: msgInfo, }) } - sortSlice(criterion, boolSlice{slice}) + 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 } - 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 { + getValue func(*models.MessageInfo) string) { var slice []*lexiStore for _, msgInfo := range messageInfos { slice = append(slice, &lexiStore{ @@ -148,11 +124,12 @@ func sortStrings(messageInfos []*models.MessageInfo, criterion *types.SortCriter MsgInfo: msgInfo, }) } - sortSlice(criterion, lexiSlice{slice}) + 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 } - return nil } type lexiStore struct { @@ -160,94 +137,17 @@ type lexiStore struct { 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 - if len(addressI) > 0 { - firstI = addressI[0] - } - if len(addressJ) > 0 { - firstJ = addressJ[0] - } - if firstI == nil && firstJ == nil { - return false - } else if firstI == nil && firstJ != nil { - return false - } else if firstI != nil && firstJ == nil { - return true - } else /* firstI != nil && firstJ != nil */ { - getName := func(addr *models.Address) string { - if addr.Name != "" { - return addr.Name - } else { - return fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host) - } - } - return getName(firstI) < getName(firstJ) - } -} - type boolStore struct { Value bool MsgInfo *models.MessageInfo } -type boolSlice struct{ Slice []*boolStore } - -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) { +func sortSlice(criterion *types.SortCriterion, slice interface{}, less func(i, j int) bool) { if criterion.Reverse { - sort.Stable(sort.Reverse(interfce)) + sort.SliceStable(slice, func(i, j int) bool { + return less(j, i) + }) } else { - sort.Stable(interfce) + sort.SliceStable(slice, less) } }