gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/miningpool/splitsetheap.go (about) 1 package pool 2 3 // mapElements are stored in a mapHeap. The index refers to the location of the 4 // splitSet in the underlying slice used to represent the heap. 5 type mapElement struct { 6 set *splitSet 7 id splitSetID 8 index int 9 } 10 11 // mapHeap is a heap of splitSets (compared by averageFee). The minHeap bool 12 // specifies whether it is a min-heap or max-heap. 13 type mapHeap struct { 14 selectID map[splitSetID]*mapElement 15 data []*mapElement 16 size uint64 17 minHeap bool 18 } 19 20 // up maintains the heap condition by checking if the element at index j is less 21 // than its parent (as defined by less()). If so it swaps them, so that the 22 // element at index j goes 'up' the heap. It continues until the heap condition 23 // is satisfied again. 24 func (mh *mapHeap) up(j int) { 25 for { 26 // i is the parent of element at index j. 27 i := (j - 1) / 2 28 29 if i == j || !mh.less(j, i) { 30 // Heap condition maintained. 31 break 32 } 33 34 // Swap i and j, then continue. 35 mh.swap(i, j) 36 j = i 37 } 38 } 39 40 // down maintains the heap condition by checking that the children of the 41 // element at index i are less than the element at i (as defined by less()). If 42 // so, it swaps them, and continues down the heap until the heap condition is 43 // satisfied. 44 func (mh *mapHeap) down(i0, n int) bool { 45 i := i0 46 for { 47 // j1 is the left child of the element at index i 48 j1 := 2*i + 1 49 50 // Check that j1 is in the bounds of the heap (j1 < 0 after int overflow). 51 if j1 >= n || j1 < 0 { 52 break 53 } 54 55 //j is the left child of i. 56 j := j1 57 58 // If the right child (j2) of the element at index i (the sibling of j), 59 // is within the bounds of the heap and satisfies 60 if j2 := j1 + 1; j2 < n && !mh.less(j1, j2) { 61 j = j2 // = 2*i + 2 // right child 62 } 63 64 // If the heap condition is true here, the method can exit. 65 if !mh.less(j, i) { 66 break 67 } 68 69 // Swap with the child and continue down the heap. 70 mh.swap(i, j) 71 i = j 72 } 73 return i > i0 74 } 75 76 // Len returns the number of items stored in the heap. 77 func (mh mapHeap) len() int { 78 return len(mh.data) 79 } 80 81 // less returns true if the mapElement at index i is less than the element at 82 // index j if the mapHeap is a min-heap. If the mapHeap is a max-heap, it 83 // returns true if the element at index i is greater. 84 func (mh mapHeap) less(i, j int) bool { 85 if mh.minHeap { 86 return mh.data[i].set.averageFee.Cmp(mh.data[j].set.averageFee) == -1 87 } 88 return mh.data[i].set.averageFee.Cmp(mh.data[j].set.averageFee) == 1 89 } 90 91 // swap swaps the elements at indices i and j. It also mutates the mapElements 92 // in the map of a mapHeap to reflect the change of indices. 93 func (mh mapHeap) swap(i, j int) { 94 // Swap in slice. 95 mh.data[i], mh.data[j] = mh.data[j], mh.data[i] 96 97 // Change values in slice to correct indices. Note that the same mapeElement 98 // pointer is in the map also, so we only have to mutate it in one place. 99 mh.data[i].index = i 100 mh.data[j].index = j 101 } 102 103 // push puts an element onto the heap and maintains the heap condition. 104 func (mh *mapHeap) push(elem *mapElement) { 105 // Get the number of items stored in the heap. 106 n := len(mh.data) 107 108 // Add elem to the bottom of the heap, and set the index to reflect that. 109 elem.index = n 110 mh.data = append(mh.data, elem) 111 112 // Place the mapElement into the map with the correct splitSetID. 113 mh.selectID[elem.id] = elem 114 115 // Increment the mapHeap size by the size of the mapElement. 116 mh.size += elem.set.size 117 118 // Fix the heap condition by sifting up. 119 mh.up(n) 120 } 121 122 // pop removes the top element from the heap (as defined by Less()) Pop will 123 // panic if called on an empty heap. Use Peek before Pop to be safe. 124 func (mh *mapHeap) pop() *mapElement { 125 n := mh.len() - 1 126 127 // Move the element to be popped to the end, then fix the heap condition. 128 mh.swap(0, n) 129 mh.down(0, n) 130 131 // Get the last element. 132 elem := mh.data[n] 133 134 // Shrink the data slice, and delete the mapElement from the map. 135 mh.data = mh.data[0:n] 136 delete(mh.selectID, elem.id) 137 138 // Decrement the size of the mapHeap. 139 mh.size -= elem.set.size 140 141 return elem 142 } 143 144 // removeSetByID removes an element from the MapHeap using only the splitSetID. 145 func (mh *mapHeap) removeSetByID(s splitSetID) *mapElement { 146 // Get index into data at which the element is stored. 147 i := mh.selectID[s].index 148 149 //Remove it from the heap using the Go library. 150 return mh.remove(i) 151 } 152 153 // Peek returns the element at the top of the heap without removing it. 154 func (mh *mapHeap) peek() (*mapElement, bool) { 155 if len(mh.data) == 0 { 156 return nil, false 157 } 158 return mh.data[0], true 159 } 160 161 // A heap must be initialized before any of the heap operations can be used. 162 // Init is idempotent with respect to the heap conditions and may be called 163 // whenever the heap conditions may have been invalidated. Its complexity is 164 // O(n) where n = h.Len(). 165 func (mh *mapHeap) init() { 166 // Sifts down through the heap to achieve the heap condition. 167 n := mh.len() 168 for i := n/2 - 1; i >= 0; i-- { 169 mh.down(i, n) 170 } 171 } 172 173 // remove removes the element at index i from the heap. The complexity is 174 // O(log(n)) where n = h.Len(). 175 func (mh *mapHeap) remove(i int) *mapElement { 176 n := mh.len() - 1 177 178 // If the element to be removed is not at the top of the heap, move it. Then 179 // fix the heap condition. 180 if n != i { 181 mh.swap(i, n) 182 mh.down(i, n) 183 mh.up(i) 184 } 185 186 // Get the last element. 187 elem := mh.data[n] 188 189 // Shrink the data slice, and delete the mapElement from the map. 190 mh.data = mh.data[0:n] 191 delete(mh.selectID, elem.id) 192 193 // Decrement the size of the mapHeap. 194 mh.size -= elem.set.size 195 return elem 196 } 197 198 // fix re-establishes the heap ordering after the element at index i has changed 199 // its value. Changing the value of the element at index i and then calling Fix 200 // is equivalent to, but less expensive than, calling Remove(h, i) followed by a 201 // Push of the new value. The complexity is O(log(n)) where n = h.len(). 202 func (mh *mapHeap) fix(i int) { 203 // Check if the heap condition can be satisfied by sifting down. 204 // If not, sift up too. 205 if !mh.down(i, mh.len()) { 206 mh.up(i) 207 } 208 }