github.com/wtsi-ssg/wrstat/v4@v4.5.1/ch/prefix.go (about) 1 /******************************************************************************* 2 * Copyright (c) 2023 Genome Research Ltd. 3 * 4 * Authors: Michael Woolnough <mw31@sanger.ac.uk> 5 * Sendu Bala <sb10@sanger.ac.uk> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 ******************************************************************************/ 26 27 package ch 28 29 import ( 30 "path/filepath" 31 "strings" 32 ) 33 34 // pathPrefixTree stores information about file paths that let you find the longest 35 // directory containing a new path. 36 type pathPrefixTree struct { 37 children map[string]*pathPrefixTree 38 leaf string 39 } 40 41 func newPathPrefixTree() *pathPrefixTree { 42 return &pathPrefixTree{ 43 children: make(map[string]*pathPrefixTree), 44 } 45 } 46 47 // addDirectory adds a new directory to the tree. 48 func (p *pathPrefixTree) addDirectory(directory string) { 49 for dir, rest := splitPath(directory[1:]); dir != ""; dir, rest = splitPath(rest) { 50 p = p.child(dir) 51 } 52 53 p.leaf = directory 54 } 55 56 func splitPath(path string) (string, string) { 57 pos := strings.IndexByte(path, filepath.Separator) 58 59 if pos == -1 { 60 return path, "" 61 } 62 63 return path[:pos], path[pos+1:] 64 } 65 66 func (p *pathPrefixTree) child(directory string) *pathPrefixTree { 67 tree, exists := p.children[directory] 68 if !exists { 69 tree = newPathPrefixTree() 70 p.children[directory] = tree 71 } 72 73 return tree 74 } 75 76 // longestPrefix finds the longest directory in the tree that is a prefix of 77 // the given path. 78 func (p *pathPrefixTree) longestPrefix(path string) (string, bool) { 79 for dir, rest := splitPath(path[1:]); dir != ""; dir, rest = splitPath(rest) { 80 tree, found := p.children[dir] 81 if !found { 82 if p.leaf != "" { 83 return p.leaf, true 84 } 85 86 break 87 } 88 89 p = tree 90 } 91 92 return "", false 93 }