github.com/sevki/docker@v1.7.1/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 bindings[p] = []PortBinding{} 64 } else { 65 s = append(s, portMapEntry{port: p}) 66 } 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 if _, ok := bindings[entry.port]; ok { 83 bindings[entry.port] = append(bindings[entry.port], entry.binding) 84 } 85 } 86 } 87 88 func toInt(s string) int64 { 89 i, err := strconv.ParseInt(s, 10, 64) 90 if err != nil { 91 i = 0 92 } 93 return i 94 }