sort.go 2.1 KB

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