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  }