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