about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJeffas <dev@jeffas.io>2020-02-29 01:27:31 +0000
committerDrew DeVault <sir@cmpwn.com>2020-02-28 20:54:14 -0500
commite8b7b3bcc16329ab9fe402d6629db775f197b73b (patch)
tree79905088ef2c0e50d75536412a8e8fda30f1cf45
parent583b129c9470a060d17c952b46dbe1bffc4c0c49 (diff)
downloadaerc-e8b7b3bcc16329ab9fe402d6629db775f197b73b.tar.gz
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.
-rw-r--r--worker/lib/sort.go210
1 files 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})
-	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})
+	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 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)
 	}
 }