list.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package value
  14. // List represents a list object.
  15. type List interface {
  16. // Length returns how many items can be found in the map.
  17. Length() int
  18. // At returns the item at the given position in the map. It will
  19. // panic if the index is out of range.
  20. At(int) Value
  21. // AtUsing uses the provided allocator and returns the item at the given
  22. // position in the map. It will panic if the index is out of range.
  23. // The returned Value should be given back to the Allocator when no longer needed
  24. // by calling Allocator.Free(Value).
  25. AtUsing(Allocator, int) Value
  26. // Range returns a ListRange for iterating over the items in the list.
  27. Range() ListRange
  28. // RangeUsing uses the provided allocator and returns a ListRange for
  29. // iterating over the items in the list.
  30. // The returned Range should be given back to the Allocator when no longer needed
  31. // by calling Allocator.Free(Value).
  32. RangeUsing(Allocator) ListRange
  33. // Equals compares the two lists, and return true if they are the same, false otherwise.
  34. // Implementations can use ListEquals as a general implementation for this methods.
  35. Equals(List) bool
  36. // EqualsUsing uses the provided allocator and compares the two lists, and return true if
  37. // they are the same, false otherwise. Implementations can use ListEqualsUsing as a general
  38. // implementation for this methods.
  39. EqualsUsing(Allocator, List) bool
  40. }
  41. // ListRange represents a single iteration across the items of a list.
  42. type ListRange interface {
  43. // Next increments to the next item in the range, if there is one, and returns true, or returns false if there are no more items.
  44. Next() bool
  45. // Item returns the index and value of the current item in the range. or panics if there is no current item.
  46. // For efficiency, Item may reuse the values returned by previous Item calls. Callers should be careful avoid holding
  47. // pointers to the value returned by Item() that escape the iteration loop since they become invalid once either
  48. // Item() or Allocator.Free() is called.
  49. Item() (index int, value Value)
  50. }
  51. var EmptyRange = &emptyRange{}
  52. type emptyRange struct{}
  53. func (_ *emptyRange) Next() bool {
  54. return false
  55. }
  56. func (_ *emptyRange) Item() (index int, value Value) {
  57. panic("Item called on empty ListRange")
  58. }
  59. // ListEquals compares two lists lexically.
  60. // WARN: This is a naive implementation, calling lhs.Equals(rhs) is typically the most efficient.
  61. func ListEquals(lhs, rhs List) bool {
  62. return ListEqualsUsing(HeapAllocator, lhs, rhs)
  63. }
  64. // ListEqualsUsing uses the provided allocator and compares two lists lexically.
  65. // WARN: This is a naive implementation, calling lhs.EqualsUsing(allocator, rhs) is typically the most efficient.
  66. func ListEqualsUsing(a Allocator, lhs, rhs List) bool {
  67. if lhs.Length() != rhs.Length() {
  68. return false
  69. }
  70. lhsRange := lhs.RangeUsing(a)
  71. defer a.Free(lhsRange)
  72. rhsRange := rhs.RangeUsing(a)
  73. defer a.Free(rhsRange)
  74. for lhsRange.Next() && rhsRange.Next() {
  75. _, lv := lhsRange.Item()
  76. _, rv := rhsRange.Item()
  77. if !EqualsUsing(a, lv, rv) {
  78. return false
  79. }
  80. }
  81. return true
  82. }
  83. // ListLess compares two lists lexically.
  84. func ListLess(lhs, rhs List) bool {
  85. return ListCompare(lhs, rhs) == -1
  86. }
  87. // ListCompare compares two lists lexically. The result will be 0 if l==rhs, -1
  88. // if l < rhs, and +1 if l > rhs.
  89. func ListCompare(lhs, rhs List) int {
  90. return ListCompareUsing(HeapAllocator, lhs, rhs)
  91. }
  92. // ListCompareUsing uses the provided allocator and compares two lists lexically. The result will be 0 if l==rhs, -1
  93. // if l < rhs, and +1 if l > rhs.
  94. func ListCompareUsing(a Allocator, lhs, rhs List) int {
  95. lhsRange := lhs.RangeUsing(a)
  96. defer a.Free(lhsRange)
  97. rhsRange := rhs.RangeUsing(a)
  98. defer a.Free(rhsRange)
  99. for {
  100. lhsOk := lhsRange.Next()
  101. rhsOk := rhsRange.Next()
  102. if !lhsOk && !rhsOk {
  103. // Lists are the same length and all items are equal.
  104. return 0
  105. }
  106. if !lhsOk {
  107. // LHS is shorter.
  108. return -1
  109. }
  110. if !rhsOk {
  111. // RHS is shorter.
  112. return 1
  113. }
  114. _, lv := lhsRange.Item()
  115. _, rv := rhsRange.Item()
  116. if c := CompareUsing(a, lv, rv); c != 0 {
  117. return c
  118. }
  119. // The items are equal; continue.
  120. }
  121. }