From b6715449737261c64d3408418754185da8624204 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 24 Oct 2017 11:13:31 -0700 Subject: [PATCH] Move first/last unique elements utility functions to android package Move firstUniqueElements to android.FirstUniqueStrings, lastUniqueElements to android.LastUniqueStrings, and lastUniquePaths to android.LastUniquePaths. Test: m checkbuild Change-Id: Ieac840405126c7f8f98afb4a4ef35c01a18fe7fb --- Android.bp | 1 + android/paths.go | 22 +++++++- android/util.go | 35 +++++++++++++ android/util_test.go | 120 +++++++++++++++++++++++++++++++++++++++++++ cc/cc.go | 72 ++++---------------------- cc/cc_test.go | 100 ------------------------------------ 6 files changed, 186 insertions(+), 164 deletions(-) create mode 100644 android/util_test.go diff --git a/Android.bp b/Android.bp index 1f6ebe2ad..3badfcd04 100644 --- a/Android.bp +++ b/Android.bp @@ -67,6 +67,7 @@ bootstrap_go_package { "android/expand_test.go", "android/paths_test.go", "android/prebuilt_test.go", + "android/util_test.go", "android/variable_test.go", ], } diff --git a/android/paths.go b/android/paths.go index 744354739..d6a1c6684 100644 --- a/android/paths.go +++ b/android/paths.go @@ -286,8 +286,8 @@ func (p Paths) Strings() []string { return ret } -// FirstUniqueElements returns all unique elements of a slice, keeping the first copy of each -// modifies the slice contents in place, and returns a subslice of the original slice +// 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 { k := 0 outer: @@ -303,6 +303,24 @@ outer: 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 { + totalSkip := 0 + for i := len(list) - 1; i >= totalSkip; i-- { + skip := 0 + for j := i - 1; j >= totalSkip; j-- { + if list[i] == list[j] { + skip++ + } else { + list[j+skip] = list[j] + } + } + totalSkip += skip + } + return list[totalSkip:] +} + func indexPathList(s Path, list []Path) int { for i, l := range list { if l == s { diff --git a/android/util.go b/android/util.go index 80c7870a0..4d30a7400 100644 --- a/android/util.go +++ b/android/util.go @@ -77,6 +77,41 @@ func prefixInList(s string, list []string) bool { return false } +// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of +// each. It modifies the slice contents in place, and returns a subslice of the original slice. +func FirstUniqueStrings(list []string) []string { + k := 0 +outer: + for i := 0; i < len(list); i++ { + for j := 0; j < k; j++ { + if list[i] == list[j] { + continue outer + } + } + list[k] = list[i] + k++ + } + return list[:k] +} + +// LastUniqueStrings returns all unique elements of a slice of strings, keeping the last copy of +// each. It modifies the slice contents in place, and returns a subslice of the original slice. +func LastUniqueStrings(list []string) []string { + totalSkip := 0 + for i := len(list) - 1; i >= totalSkip; i-- { + skip := 0 + for j := i - 1; j >= totalSkip; j-- { + if list[i] == list[j] { + skip++ + } else { + list[j+skip] = list[j] + } + } + totalSkip += skip + } + return list[totalSkip:] +} + // checkCalledFromInit panics if a Go package's init function is not on the // call stack. func checkCalledFromInit() { diff --git a/android/util_test.go b/android/util_test.go new file mode 100644 index 000000000..32f92b46c --- /dev/null +++ b/android/util_test.go @@ -0,0 +1,120 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "reflect" + "testing" +) + +var firstUniqueStringsTestCases = []struct { + in []string + out []string +}{ + { + in: []string{"a"}, + out: []string{"a"}, + }, + { + in: []string{"a", "b"}, + out: []string{"a", "b"}, + }, + { + in: []string{"a", "a"}, + out: []string{"a"}, + }, + { + in: []string{"a", "b", "a"}, + out: []string{"a", "b"}, + }, + { + in: []string{"b", "a", "a"}, + out: []string{"b", "a"}, + }, + { + in: []string{"a", "a", "b"}, + out: []string{"a", "b"}, + }, + { + in: []string{"a", "b", "a", "b"}, + out: []string{"a", "b"}, + }, + { + in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"}, + out: []string{"liblog", "libdl", "libc++", "libc", "libm"}, + }, +} + +func TestFirstUniqueStrings(t *testing.T) { + for _, testCase := range firstUniqueStringsTestCases { + out := FirstUniqueStrings(testCase.in) + if !reflect.DeepEqual(out, testCase.out) { + t.Errorf("incorrect output:") + t.Errorf(" input: %#v", testCase.in) + t.Errorf(" expected: %#v", testCase.out) + t.Errorf(" got: %#v", out) + } + } +} + +var lastUniqueStringsTestCases = []struct { + in []string + out []string +}{ + { + in: []string{"a"}, + out: []string{"a"}, + }, + { + in: []string{"a", "b"}, + out: []string{"a", "b"}, + }, + { + in: []string{"a", "a"}, + out: []string{"a"}, + }, + { + in: []string{"a", "b", "a"}, + out: []string{"b", "a"}, + }, + { + in: []string{"b", "a", "a"}, + out: []string{"b", "a"}, + }, + { + in: []string{"a", "a", "b"}, + out: []string{"a", "b"}, + }, + { + in: []string{"a", "b", "a", "b"}, + out: []string{"a", "b"}, + }, + { + in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"}, + out: []string{"liblog", "libc++", "libdl", "libc", "libm"}, + }, +} + +func TestLastUniqueStrings(t *testing.T) { + for _, testCase := range lastUniqueStringsTestCases { + out := LastUniqueStrings(testCase.in) + if !reflect.DeepEqual(out, testCase.out) { + t.Errorf("incorrect output:") + t.Errorf(" input: %#v", testCase.in) + t.Errorf(" expected: %#v", testCase.out) + t.Errorf(" got: %#v", out) + } + } +} diff --git a/cc/cc.go b/cc/cc.go index 716369612..36b97e119 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -561,7 +561,7 @@ func orderDeps(directDeps []android.Path, transitiveDeps map[android.Path][]andr orderedAllDeps = append(orderedAllDeps, transitiveDeps[dep]...) } - orderedAllDeps = lastUniquePaths(orderedAllDeps) + orderedAllDeps = android.LastUniquePaths(orderedAllDeps) // We don't want to add any new dependencies into directDeps (to allow the caller to // intentionally exclude or replace any unwanted transitive dependencies), so we limit the @@ -763,12 +763,12 @@ func (c *Module) deps(ctx DepsContext) Deps { deps = feature.deps(ctx, deps) } - deps.WholeStaticLibs = lastUniqueElements(deps.WholeStaticLibs) - deps.StaticLibs = lastUniqueElements(deps.StaticLibs) - deps.LateStaticLibs = lastUniqueElements(deps.LateStaticLibs) - deps.SharedLibs = lastUniqueElements(deps.SharedLibs) - deps.LateSharedLibs = lastUniqueElements(deps.LateSharedLibs) - deps.HeaderLibs = lastUniqueElements(deps.HeaderLibs) + deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs) + deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs) + deps.LateStaticLibs = android.LastUniqueStrings(deps.LateStaticLibs) + deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs) + deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs) + deps.HeaderLibs = android.LastUniqueStrings(deps.HeaderLibs) for _, lib := range deps.ReexportSharedLibHeaders { if !inList(lib, deps.SharedLibs) { @@ -1249,13 +1249,13 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps)...) // Dedup exported flags from dependencies - depPaths.Flags = firstUniqueElements(depPaths.Flags) + depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags) depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders) - depPaths.ReexportedFlags = firstUniqueElements(depPaths.ReexportedFlags) + depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags) depPaths.ReexportedFlagsDeps = android.FirstUniquePaths(depPaths.ReexportedFlagsDeps) if c.sabi != nil { - c.sabi.Properties.ReexportedIncludeFlags = firstUniqueElements(c.sabi.Properties.ReexportedIncludeFlags) + c.sabi.Properties.ReexportedIncludeFlags = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludeFlags) } return depPaths @@ -1438,58 +1438,6 @@ func vendorMutator(mctx android.BottomUpMutatorContext) { } } -// firstUniqueElements returns all unique elements of a slice, keeping the first copy of each -// modifies the slice contents in place, and returns a subslice of the original slice -func firstUniqueElements(list []string) []string { - k := 0 -outer: - for i := 0; i < len(list); i++ { - for j := 0; j < k; j++ { - if list[i] == list[j] { - continue outer - } - } - list[k] = list[i] - k++ - } - return list[:k] -} - -// lastUniqueElements returns all unique elements of a slice, keeping the last copy of each. -// It modifies the slice contents in place, and returns a subslice of the original slice -func lastUniqueElements(list []string) []string { - totalSkip := 0 - for i := len(list) - 1; i >= totalSkip; i-- { - skip := 0 - for j := i - 1; j >= totalSkip; j-- { - if list[i] == list[j] { - skip++ - } else { - list[j+skip] = list[j] - } - } - totalSkip += skip - } - return list[totalSkip:] -} - -// lastUniquePaths is the same as lastUniqueElements but uses Path structs -func lastUniquePaths(list []android.Path) []android.Path { - totalSkip := 0 - for i := len(list) - 1; i >= totalSkip; i-- { - skip := 0 - for j := i - 1; j >= totalSkip; j-- { - if list[i] == list[j] { - skip++ - } else { - list[j+skip] = list[j] - } - } - totalSkip += skip - } - return list[totalSkip:] -} - func getCurrentNdkPrebuiltVersion(ctx DepsContext) string { if ctx.AConfig().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt { return strconv.Itoa(config.NdkMaxPrebuiltVersionInt) diff --git a/cc/cc_test.go b/cc/cc_test.go index dc04a4e14..35274f0c1 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -156,106 +156,6 @@ func TestVendorSrc(t *testing.T) { } } -var firstUniqueElementsTestCases = []struct { - in []string - out []string -}{ - { - in: []string{"a"}, - out: []string{"a"}, - }, - { - in: []string{"a", "b"}, - out: []string{"a", "b"}, - }, - { - in: []string{"a", "a"}, - out: []string{"a"}, - }, - { - in: []string{"a", "b", "a"}, - out: []string{"a", "b"}, - }, - { - in: []string{"b", "a", "a"}, - out: []string{"b", "a"}, - }, - { - in: []string{"a", "a", "b"}, - out: []string{"a", "b"}, - }, - { - in: []string{"a", "b", "a", "b"}, - out: []string{"a", "b"}, - }, - { - in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"}, - out: []string{"liblog", "libdl", "libc++", "libc", "libm"}, - }, -} - -func TestFirstUniqueElements(t *testing.T) { - for _, testCase := range firstUniqueElementsTestCases { - out := firstUniqueElements(testCase.in) - if !reflect.DeepEqual(out, testCase.out) { - t.Errorf("incorrect output:") - t.Errorf(" input: %#v", testCase.in) - t.Errorf(" expected: %#v", testCase.out) - t.Errorf(" got: %#v", out) - } - } -} - -var lastUniqueElementsTestCases = []struct { - in []string - out []string -}{ - { - in: []string{"a"}, - out: []string{"a"}, - }, - { - in: []string{"a", "b"}, - out: []string{"a", "b"}, - }, - { - in: []string{"a", "a"}, - out: []string{"a"}, - }, - { - in: []string{"a", "b", "a"}, - out: []string{"b", "a"}, - }, - { - in: []string{"b", "a", "a"}, - out: []string{"b", "a"}, - }, - { - in: []string{"a", "a", "b"}, - out: []string{"a", "b"}, - }, - { - in: []string{"a", "b", "a", "b"}, - out: []string{"a", "b"}, - }, - { - in: []string{"liblog", "libdl", "libc++", "libdl", "libc", "libm"}, - out: []string{"liblog", "libc++", "libdl", "libc", "libm"}, - }, -} - -func TestLastUniqueElements(t *testing.T) { - for _, testCase := range lastUniqueElementsTestCases { - out := lastUniqueElements(testCase.in) - if !reflect.DeepEqual(out, testCase.out) { - t.Errorf("incorrect output:") - t.Errorf(" input: %#v", testCase.in) - t.Errorf(" expected: %#v", testCase.out) - t.Errorf(" got: %#v", out) - } - } -} - var ( str11 = "01234567891" str10 = str11[:10]