github.com/jogo/docker@v1.7.0-rc1/nat/sort.go (about)

     1  package nat
     2  
     3  import (
     4  	"sort"
     5  	"strconv"
     6  	"strings"
     7  )
     8  
     9  type portSorter struct {
    10  	ports []Port
    11  	by    func(i, j Port) bool
    12  }
    13  
    14  func (s *portSorter) Len() int {
    15  	return len(s.ports)
    16  }
    17  
    18  func (s *portSorter) Swap(i, j int) {
    19  	s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
    20  }
    21  
    22  func (s *portSorter) Less(i, j int) bool {
    23  	ip := s.ports[i]
    24  	jp := s.ports[j]
    25  
    26  	return s.by(ip, jp)
    27  }
    28  
    29  func Sort(ports []Port, predicate func(i, j Port) bool) {
    30  	s := &portSorter{ports, predicate}
    31  	sort.Sort(s)
    32  }
    33  
    34  type portMapEntry struct {
    35  	port    Port
    36  	binding PortBinding
    37  }
    38  
    39  type portMapSorter []portMapEntry
    40  
    41  func (s portMapSorter) Len() int      { return len(s) }
    42  func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    43  
    44  // sort the port so that the order is:
    45  // 1. port with larger specified bindings
    46  // 2. larger port
    47  // 3. port with tcp protocol
    48  func (s portMapSorter) Less(i, j int) bool {
    49  	pi, pj := s[i].port, s[j].port
    50  	hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort)
    51  	return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp")
    52  }
    53  
    54  // SortPortMap sorts the list of ports and their respected mapping. The ports
    55  // will explicit HostPort will be placed first.
    56  func SortPortMap(ports []Port, bindings PortMap) {
    57  	s := portMapSorter{}
    58  	for _, p := range ports {
    59  		if binding, ok := bindings[p]; ok {
    60  			for _, b := range binding {
    61  				s = append(s, portMapEntry{port: p, binding: b})
    62  			}
    63  		} else {
    64  			s = append(s, portMapEntry{port: p})
    65  		}
    66  		bindings[p] = []PortBinding{}
    67  	}
    68  
    69  	sort.Sort(s)
    70  	var (
    71  		i  int
    72  		pm = make(map[Port]struct{})
    73  	)
    74  	// reorder ports
    75  	for _, entry := range s {
    76  		if _, ok := pm[entry.port]; !ok {
    77  			ports[i] = entry.port
    78  			pm[entry.port] = struct{}{}
    79  			i++
    80  		}
    81  		// reorder bindings for this port
    82  		bindings[entry.port] = append(bindings[entry.port], entry.binding)
    83  	}
    84  }
    85  
    86  func toInt(s string) int64 {
    87  	i, err := strconv.ParseInt(s, 10, 64)
    88  	if err != nil {
    89  		i = 0
    90  	}
    91  	return i
    92  }