mirror of https://github.com/poanetwork/quorum.git
171 lines
3.0 KiB
Go
171 lines
3.0 KiB
Go
|
package lane
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// PQType represents a priority queue ordering kind (see MAXPQ and MINPQ)
|
||
|
type PQType int
|
||
|
|
||
|
const (
|
||
|
MAXPQ PQType = iota
|
||
|
MINPQ
|
||
|
)
|
||
|
|
||
|
type item struct {
|
||
|
value interface{}
|
||
|
priority int
|
||
|
}
|
||
|
|
||
|
// PQueue is a heap priority queue data structure implementation.
|
||
|
// It can be whether max or min ordered and it is synchronized
|
||
|
// and is safe for concurrent operations.
|
||
|
type PQueue struct {
|
||
|
sync.RWMutex
|
||
|
items []*item
|
||
|
elemsCount int
|
||
|
comparator func(int, int) bool
|
||
|
}
|
||
|
|
||
|
func newItem(value interface{}, priority int) *item {
|
||
|
return &item{
|
||
|
value: value,
|
||
|
priority: priority,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (i *item) String() string {
|
||
|
return fmt.Sprintf("<item value:%s priority:%d>", i.value, i.priority)
|
||
|
}
|
||
|
|
||
|
// NewPQueue creates a new priority queue with the provided pqtype
|
||
|
// ordering type
|
||
|
func NewPQueue(pqType PQType) *PQueue {
|
||
|
var cmp func(int, int) bool
|
||
|
|
||
|
if pqType == MAXPQ {
|
||
|
cmp = max
|
||
|
} else {
|
||
|
cmp = min
|
||
|
}
|
||
|
|
||
|
items := make([]*item, 1)
|
||
|
items[0] = nil // Heap queue first element should always be nil
|
||
|
|
||
|
return &PQueue{
|
||
|
items: items,
|
||
|
elemsCount: 0,
|
||
|
comparator: cmp,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Push the value item into the priority queue with provided priority.
|
||
|
func (pq *PQueue) Push(value interface{}, priority int) {
|
||
|
item := newItem(value, priority)
|
||
|
|
||
|
pq.Lock()
|
||
|
pq.items = append(pq.items, item)
|
||
|
pq.elemsCount += 1
|
||
|
pq.swim(pq.size())
|
||
|
pq.Unlock()
|
||
|
}
|
||
|
|
||
|
// Pop and returns the highest/lowest priority item (depending on whether
|
||
|
// you're using a MINPQ or MAXPQ) from the priority queue
|
||
|
func (pq *PQueue) Pop() (interface{}, int) {
|
||
|
pq.Lock()
|
||
|
defer pq.Unlock()
|
||
|
|
||
|
if pq.size() < 1 {
|
||
|
return nil, 0
|
||
|
}
|
||
|
|
||
|
var max *item = pq.items[1]
|
||
|
|
||
|
pq.exch(1, pq.size())
|
||
|
pq.items = pq.items[0:pq.size()]
|
||
|
pq.elemsCount -= 1
|
||
|
pq.sink(1)
|
||
|
|
||
|
return max.value, max.priority
|
||
|
}
|
||
|
|
||
|
// Head returns the highest/lowest priority item (depending on whether
|
||
|
// you're using a MINPQ or MAXPQ) from the priority queue
|
||
|
func (pq *PQueue) Head() (interface{}, int) {
|
||
|
pq.RLock()
|
||
|
defer pq.RUnlock()
|
||
|
|
||
|
if pq.size() < 1 {
|
||
|
return nil, 0
|
||
|
}
|
||
|
|
||
|
headValue := pq.items[1].value
|
||
|
headPriority := pq.items[1].priority
|
||
|
|
||
|
return headValue, headPriority
|
||
|
}
|
||
|
|
||
|
// Size returns the elements present in the priority queue count
|
||
|
func (pq *PQueue) Size() int {
|
||
|
pq.RLock()
|
||
|
defer pq.RUnlock()
|
||
|
return pq.size()
|
||
|
}
|
||
|
|
||
|
// Check queue is empty
|
||
|
func (pq *PQueue) Empty() bool {
|
||
|
pq.RLock()
|
||
|
defer pq.RUnlock()
|
||
|
return pq.size() == 0
|
||
|
}
|
||
|
|
||
|
func (pq *PQueue) size() int {
|
||
|
return pq.elemsCount
|
||
|
}
|
||
|
|
||
|
func max(i, j int) bool {
|
||
|
return i < j
|
||
|
}
|
||
|
|
||
|
func min(i, j int) bool {
|
||
|
return i > j
|
||
|
}
|
||
|
|
||
|
func (pq *PQueue) less(i, j int) bool {
|
||
|
return pq.comparator(pq.items[i].priority, pq.items[j].priority)
|
||
|
}
|
||
|
|
||
|
func (pq *PQueue) exch(i, j int) {
|
||
|
var tmpItem *item = pq.items[i]
|
||
|
|
||
|
pq.items[i] = pq.items[j]
|
||
|
pq.items[j] = tmpItem
|
||
|
}
|
||
|
|
||
|
func (pq *PQueue) swim(k int) {
|
||
|
for k > 1 && pq.less(k/2, k) {
|
||
|
pq.exch(k/2, k)
|
||
|
k = k / 2
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func (pq *PQueue) sink(k int) {
|
||
|
for 2*k <= pq.size() {
|
||
|
var j int = 2 * k
|
||
|
|
||
|
if j < pq.size() && pq.less(j, j+1) {
|
||
|
j++
|
||
|
}
|
||
|
|
||
|
if !pq.less(k, j) {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
pq.exch(k, j)
|
||
|
k = j
|
||
|
}
|
||
|
}
|