1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2021 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "sort" 19*1fa6dee9SAndroid Build Coastguard Worker) 20*1fa6dee9SAndroid Build Coastguard Worker 21*1fa6dee9SAndroid Build Coastguard Workerfunc abs(a int) int { 22*1fa6dee9SAndroid Build Coastguard Worker if a < 0 { 23*1fa6dee9SAndroid Build Coastguard Worker return -a 24*1fa6dee9SAndroid Build Coastguard Worker } 25*1fa6dee9SAndroid Build Coastguard Worker return a 26*1fa6dee9SAndroid Build Coastguard Worker} 27*1fa6dee9SAndroid Build Coastguard Worker 28*1fa6dee9SAndroid Build Coastguard Worker// This implementation is written to be recursive, because 29*1fa6dee9SAndroid Build Coastguard Worker// we know Soong names are short, so we shouldn't hit the stack 30*1fa6dee9SAndroid Build Coastguard Worker// depth. Also, the buffer is indexed this way so that new 31*1fa6dee9SAndroid Build Coastguard Worker// allocations aren't needed. 32*1fa6dee9SAndroid Build Coastguard Workerfunc levenshtein(a, b string, ai, bi, max int, buf [][]int) int { 33*1fa6dee9SAndroid Build Coastguard Worker if max == 0 { 34*1fa6dee9SAndroid Build Coastguard Worker return 0 35*1fa6dee9SAndroid Build Coastguard Worker } 36*1fa6dee9SAndroid Build Coastguard Worker if ai >= len(a) { 37*1fa6dee9SAndroid Build Coastguard Worker return len(b) - bi 38*1fa6dee9SAndroid Build Coastguard Worker } 39*1fa6dee9SAndroid Build Coastguard Worker if bi >= len(b) { 40*1fa6dee9SAndroid Build Coastguard Worker return len(a) - ai 41*1fa6dee9SAndroid Build Coastguard Worker } 42*1fa6dee9SAndroid Build Coastguard Worker if buf[bi][ai] != 0 { 43*1fa6dee9SAndroid Build Coastguard Worker return buf[bi][ai] 44*1fa6dee9SAndroid Build Coastguard Worker } 45*1fa6dee9SAndroid Build Coastguard Worker if abs(len(a)-len(b)) >= max { 46*1fa6dee9SAndroid Build Coastguard Worker return max 47*1fa6dee9SAndroid Build Coastguard Worker } 48*1fa6dee9SAndroid Build Coastguard Worker var res = max 49*1fa6dee9SAndroid Build Coastguard Worker if a[ai] == b[bi] { 50*1fa6dee9SAndroid Build Coastguard Worker res = levenshtein(a, b, ai+1, bi+1, max, buf) 51*1fa6dee9SAndroid Build Coastguard Worker } else { 52*1fa6dee9SAndroid Build Coastguard Worker if c := levenshtein(a, b, ai+1, bi+1, max-1, buf); c < res { 53*1fa6dee9SAndroid Build Coastguard Worker res = c // replace 54*1fa6dee9SAndroid Build Coastguard Worker } 55*1fa6dee9SAndroid Build Coastguard Worker if c := levenshtein(a, b, ai+1, bi, max-1, buf); c < res { 56*1fa6dee9SAndroid Build Coastguard Worker res = c // delete from a 57*1fa6dee9SAndroid Build Coastguard Worker } 58*1fa6dee9SAndroid Build Coastguard Worker if c := levenshtein(a, b, ai, bi+1, max-1, buf); c < res { 59*1fa6dee9SAndroid Build Coastguard Worker res = c // delete from b 60*1fa6dee9SAndroid Build Coastguard Worker } 61*1fa6dee9SAndroid Build Coastguard Worker res += 1 62*1fa6dee9SAndroid Build Coastguard Worker } 63*1fa6dee9SAndroid Build Coastguard Worker buf[bi][ai] = res 64*1fa6dee9SAndroid Build Coastguard Worker return res 65*1fa6dee9SAndroid Build Coastguard Worker} 66*1fa6dee9SAndroid Build Coastguard Worker 67*1fa6dee9SAndroid Build Coastguard Workerfunc stringIn(arr []string, str string) bool { 68*1fa6dee9SAndroid Build Coastguard Worker for _, a := range arr { 69*1fa6dee9SAndroid Build Coastguard Worker if a == str { 70*1fa6dee9SAndroid Build Coastguard Worker return true 71*1fa6dee9SAndroid Build Coastguard Worker } 72*1fa6dee9SAndroid Build Coastguard Worker } 73*1fa6dee9SAndroid Build Coastguard Worker return false 74*1fa6dee9SAndroid Build Coastguard Worker} 75*1fa6dee9SAndroid Build Coastguard Worker 76*1fa6dee9SAndroid Build Coastguard Workerfunc namesLike(name string, unlike string, moduleGroups []*moduleGroup) []string { 77*1fa6dee9SAndroid Build Coastguard Worker const kAllowedDifferences = 10 78*1fa6dee9SAndroid Build Coastguard Worker buf := make([][]int, len(name)+kAllowedDifferences) 79*1fa6dee9SAndroid Build Coastguard Worker for i := range buf { 80*1fa6dee9SAndroid Build Coastguard Worker buf[i] = make([]int, len(name)) 81*1fa6dee9SAndroid Build Coastguard Worker } 82*1fa6dee9SAndroid Build Coastguard Worker 83*1fa6dee9SAndroid Build Coastguard Worker var best []string 84*1fa6dee9SAndroid Build Coastguard Worker bestVal := kAllowedDifferences + 1 85*1fa6dee9SAndroid Build Coastguard Worker 86*1fa6dee9SAndroid Build Coastguard Worker for _, group := range moduleGroups { 87*1fa6dee9SAndroid Build Coastguard Worker other := group.name 88*1fa6dee9SAndroid Build Coastguard Worker 89*1fa6dee9SAndroid Build Coastguard Worker if other == unlike { 90*1fa6dee9SAndroid Build Coastguard Worker continue 91*1fa6dee9SAndroid Build Coastguard Worker } 92*1fa6dee9SAndroid Build Coastguard Worker 93*1fa6dee9SAndroid Build Coastguard Worker l := levenshtein(name, other, 0, 0, kAllowedDifferences, buf) 94*1fa6dee9SAndroid Build Coastguard Worker // fmt.Printf("levenshtein %q %q %d\n", name, other, l) 95*1fa6dee9SAndroid Build Coastguard Worker 96*1fa6dee9SAndroid Build Coastguard Worker // slightly better to use a min-heap 97*1fa6dee9SAndroid Build Coastguard Worker if l == 0 { 98*1fa6dee9SAndroid Build Coastguard Worker // these are the same, so it must be in a different namespace 99*1fa6dee9SAndroid Build Coastguard Worker // ignore... 100*1fa6dee9SAndroid Build Coastguard Worker } else if l < bestVal { 101*1fa6dee9SAndroid Build Coastguard Worker bestVal = l 102*1fa6dee9SAndroid Build Coastguard Worker best = []string{other} 103*1fa6dee9SAndroid Build Coastguard Worker } else if l == bestVal && !stringIn(best, other) { 104*1fa6dee9SAndroid Build Coastguard Worker best = append(best, other) 105*1fa6dee9SAndroid Build Coastguard Worker } 106*1fa6dee9SAndroid Build Coastguard Worker 107*1fa6dee9SAndroid Build Coastguard Worker // zero buffer once used 108*1fa6dee9SAndroid Build Coastguard Worker for _, v := range buf { 109*1fa6dee9SAndroid Build Coastguard Worker for j := range v { 110*1fa6dee9SAndroid Build Coastguard Worker v[j] = 0 111*1fa6dee9SAndroid Build Coastguard Worker } 112*1fa6dee9SAndroid Build Coastguard Worker } 113*1fa6dee9SAndroid Build Coastguard Worker } 114*1fa6dee9SAndroid Build Coastguard Worker 115*1fa6dee9SAndroid Build Coastguard Worker sort.Strings(best) 116*1fa6dee9SAndroid Build Coastguard Worker return best 117*1fa6dee9SAndroid Build Coastguard Worker} 118