Optimize FirstUniqueStrings and FirstUniquePaths

FirstUniquePaths is called on some long lists where the O(n^2)
behavior is problematic.  Use a map-based implementation for
longer lists.

Test: TestFirstUniqueStrings
Change-Id: I7181aba869e5ccc0f99c2fa7b8f03839f06e4307
This commit is contained in:
Colin Cross
2020-02-28 15:34:17 -08:00
parent c6e538406c
commit 27027c765e
4 changed files with 157 additions and 5 deletions

View File

@@ -470,6 +470,14 @@ func (p Paths) Strings() []string {
// FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each. It
// modifies the Paths slice contents in place, and returns a subslice of the original slice.
func FirstUniquePaths(list Paths) Paths {
// 128 was chosen based on BenchmarkFirstUniquePaths results.
if len(list) > 128 {
return firstUniquePathsMap(list)
}
return firstUniquePathsList(list)
}
func firstUniquePathsList(list Paths) Paths {
k := 0
outer:
for i := 0; i < len(list); i++ {
@@ -484,6 +492,20 @@ outer:
return list[:k]
}
func firstUniquePathsMap(list Paths) Paths {
k := 0
seen := make(map[Path]bool, len(list))
for i := 0; i < len(list); i++ {
if seen[list[i]] {
continue
}
seen[list[i]] = true
list[k] = list[i]
k++
}
return list[:k]
}
// LastUniquePaths returns all unique elements of a Paths, keeping the last copy of each. It
// modifies the Paths slice contents in place, and returns a subslice of the original slice.
func LastUniquePaths(list Paths) Paths {