github.com/golang/dep@v0.5.4/gps/typed_radix.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gps
     6  
     7  import (
     8  	"strings"
     9  	"sync"
    10  
    11  	"github.com/armon/go-radix"
    12  )
    13  
    14  // Typed implementations of radix trees. These are just simple wrappers that let
    15  // us avoid having to type assert anywhere else, cleaning up other code a bit.
    16  //
    17  // Some of the more annoying things to implement (like walks) aren't
    18  // implemented. They can be added if/when we actually need them.
    19  //
    20  // Oh generics, where art thou...
    21  
    22  type deducerTrie struct {
    23  	sync.RWMutex
    24  	t *radix.Tree
    25  }
    26  
    27  func newDeducerTrie() *deducerTrie {
    28  	return &deducerTrie{
    29  		t: radix.New(),
    30  	}
    31  }
    32  
    33  // Suppress unused warning.
    34  var _ = (*deducerTrie)(nil).Delete
    35  
    36  // Delete is used to delete a key, returning the previous value and if it was deleted
    37  func (t *deducerTrie) Delete(s string) (pathDeducer, bool) {
    38  	t.Lock()
    39  	defer t.Unlock()
    40  	if d, had := t.t.Delete(s); had {
    41  		return d.(pathDeducer), had
    42  	}
    43  	return nil, false
    44  }
    45  
    46  // Insert is used to add a newentry or update an existing entry. Returns if updated.
    47  func (t *deducerTrie) Insert(s string, d pathDeducer) (pathDeducer, bool) {
    48  	t.Lock()
    49  	defer t.Unlock()
    50  	if d2, had := t.t.Insert(s, d); had {
    51  		return d2.(pathDeducer), had
    52  	}
    53  	return nil, false
    54  }
    55  
    56  // LongestPrefix is like Get, but instead of an exact match, it will return the
    57  // longest prefix match.
    58  func (t *deducerTrie) LongestPrefix(s string) (string, pathDeducer, bool) {
    59  	t.RLock()
    60  	defer t.RUnlock()
    61  	if p, d, has := t.t.LongestPrefix(s); has {
    62  		return p, d.(pathDeducer), has
    63  	}
    64  	return "", nil, false
    65  }
    66  
    67  // isPathPrefixOrEqual is an additional helper check to ensure that the literal
    68  // string prefix returned from a radix tree prefix match is also a path tree
    69  // match.
    70  //
    71  // The radix tree gets it mostly right, but we have to guard against
    72  // possibilities like this:
    73  //
    74  // github.com/sdboyer/foo
    75  // github.com/sdboyer/foobar/baz
    76  //
    77  // The latter would incorrectly be conflated with the former. As we know we're
    78  // operating on strings that describe import paths, guard against this case by
    79  // verifying that either the input is the same length as the match (in which
    80  // case we know they're equal), or that the next character is a "/". (Import
    81  // paths are defined to always use "/", not the OS-specific path separator.)
    82  func isPathPrefixOrEqual(pre, path string) bool {
    83  	prflen, pathlen := len(pre), len(path)
    84  	if pathlen == prflen+1 {
    85  		// this can never be the case
    86  		return false
    87  	}
    88  
    89  	// we assume something else (a trie) has done equality check up to the point
    90  	// of the prefix, so we just check len
    91  	return prflen == pathlen || strings.Index(path[prflen:], "/") == 0
    92  }