github.com/torfuzx/docker@v1.8.1/pkg/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 // Sort sorts a list of ports using the provided predicate 30 // This function should compare `i` and `j`, returning true if `i` is 31 // considered to be less than `j` 32 func Sort(ports []Port, predicate func(i, j Port) bool) { 33 s := &portSorter{ports, predicate} 34 sort.Sort(s) 35 } 36 37 type portMapEntry struct { 38 port Port 39 binding PortBinding 40 } 41 42 type portMapSorter []portMapEntry 43 44 func (s portMapSorter) Len() int { return len(s) } 45 func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 46 47 // sort the port so that the order is: 48 // 1. port with larger specified bindings 49 // 2. larger port 50 // 3. port with tcp protocol 51 func (s portMapSorter) Less(i, j int) bool { 52 pi, pj := s[i].port, s[j].port 53 hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort) 54 return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp") 55 } 56 57 // SortPortMap sorts the list of ports and their respected mapping. The ports 58 // will explicit HostPort will be placed first. 59 func SortPortMap(ports []Port, bindings PortMap) { 60 s := portMapSorter{} 61 for _, p := range ports { 62 if binding, ok := bindings[p]; ok { 63 for _, b := range binding { 64 s = append(s, portMapEntry{port: p, binding: b}) 65 } 66 bindings[p] = []PortBinding{} 67 } else { 68 s = append(s, portMapEntry{port: p}) 69 } 70 } 71 72 sort.Sort(s) 73 var ( 74 i int 75 pm = make(map[Port]struct{}) 76 ) 77 // reorder ports 78 for _, entry := range s { 79 if _, ok := pm[entry.port]; !ok { 80 ports[i] = entry.port 81 pm[entry.port] = struct{}{} 82 i++ 83 } 84 // reorder bindings for this port 85 if _, ok := bindings[entry.port]; ok { 86 bindings[entry.port] = append(bindings[entry.port], entry.binding) 87 } 88 } 89 } 90 91 func toInt(s string) int64 { 92 i, err := strconv.ParseInt(s, 10, 64) 93 if err != nil { 94 i = 0 95 } 96 return i 97 }