common/prque: make Prque wrap-around priority handling optional (#22495)

This commit is contained in:
Daniel Liu 2024-12-17 11:37:21 +08:00
parent e52587df53
commit e2eb22dcac
4 changed files with 27 additions and 16 deletions

View file

@ -56,7 +56,7 @@ type (
// NewLazyQueue creates a new lazy queue // NewLazyQueue creates a new lazy queue
func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPriority MaxPriorityCallback, clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue { func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPriority MaxPriorityCallback, clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue {
q := &LazyQueue{ q := &LazyQueue{
popQueue: newSstack(nil), popQueue: newSstack(nil, false),
setIndex: setIndex, setIndex: setIndex,
priority: priority, priority: priority,
maxPriority: maxPriority, maxPriority: maxPriority,
@ -72,8 +72,8 @@ func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPrior
// Reset clears the contents of the queue // Reset clears the contents of the queue
func (q *LazyQueue) Reset() { func (q *LazyQueue) Reset() {
q.queue[0] = newSstack(q.setIndex0) q.queue[0] = newSstack(q.setIndex0, false)
q.queue[1] = newSstack(q.setIndex1) q.queue[1] = newSstack(q.setIndex1, false)
} }
// Refresh performs queue re-evaluation if necessary // Refresh performs queue re-evaluation if necessary

View file

@ -28,7 +28,12 @@ type Prque struct {
// New creates a new priority queue. // New creates a new priority queue.
func New(setIndex SetIndexCallback) *Prque { func New(setIndex SetIndexCallback) *Prque {
return &Prque{newSstack(setIndex)} return &Prque{newSstack(setIndex, false)}
}
// NewWrapAround creates a new priority queue with wrap-around priority handling.
func NewWrapAround(setIndex SetIndexCallback) *Prque {
return &Prque{newSstack(setIndex, true)}
} }
// Pushes a value with a given priority into the queue, expanding if necessary. // Pushes a value with a given priority into the queue, expanding if necessary.
@ -36,13 +41,13 @@ func (p *Prque) Push(data interface{}, priority int64) {
heap.Push(p.cont, &item{data, priority}) heap.Push(p.cont, &item{data, priority})
} }
// Peek returns the value with the greates priority but does not pop it off. // Peek returns the value with the greatest priority but does not pop it off.
func (p *Prque) Peek() (interface{}, int64) { func (p *Prque) Peek() (interface{}, int64) {
item := p.cont.blocks[0][0] item := p.cont.blocks[0][0]
return item.value, item.priority return item.value, item.priority
} }
// Pops the value with the greates priority off the stack and returns it. // Pops the value with the greatest priority off the stack and returns it.
// Currently no shrinking is done. // Currently no shrinking is done.
func (p *Prque) Pop() (interface{}, int64) { func (p *Prque) Pop() (interface{}, int64) {
item := heap.Pop(p.cont).(*item) item := heap.Pop(p.cont).(*item)

View file

@ -31,22 +31,24 @@ type SetIndexCallback func(data interface{}, index int)
// the stack (heap) functionality and the Len, Less and Swap methods for the // the stack (heap) functionality and the Len, Less and Swap methods for the
// sortability requirements of the heaps. // sortability requirements of the heaps.
type sstack struct { type sstack struct {
setIndex SetIndexCallback setIndex SetIndexCallback
size int size int
capacity int capacity int
offset int offset int
wrapAround bool
blocks [][]*item blocks [][]*item
active []*item active []*item
} }
// Creates a new, empty stack. // Creates a new, empty stack.
func newSstack(setIndex SetIndexCallback) *sstack { func newSstack(setIndex SetIndexCallback, wrapAround bool) *sstack {
result := new(sstack) result := new(sstack)
result.setIndex = setIndex result.setIndex = setIndex
result.active = make([]*item, blockSize) result.active = make([]*item, blockSize)
result.blocks = [][]*item{result.active} result.blocks = [][]*item{result.active}
result.capacity = blockSize result.capacity = blockSize
result.wrapAround = wrapAround
return result return result
} }
@ -94,7 +96,11 @@ func (s *sstack) Len() int {
// Compares the priority of two elements of the stack (higher is first). // Compares the priority of two elements of the stack (higher is first).
// Required by sort.Interface. // Required by sort.Interface.
func (s *sstack) Less(i, j int) bool { func (s *sstack) Less(i, j int) bool {
return (s.blocks[i/blockSize][i%blockSize].priority - s.blocks[j/blockSize][j%blockSize].priority) > 0 a, b := s.blocks[i/blockSize][i%blockSize].priority, s.blocks[j/blockSize][j%blockSize].priority
if s.wrapAround {
return a-b > 0
}
return a > b
} }
// Swaps two elements in the stack. Required by sort.Interface. // Swaps two elements in the stack. Required by sort.Interface.
@ -110,5 +116,5 @@ func (s *sstack) Swap(i, j int) {
// Resets the stack, effectively clearing its contents. // Resets the stack, effectively clearing its contents.
func (s *sstack) Reset() { func (s *sstack) Reset() {
*s = *newSstack(s.setIndex) *s = *newSstack(s.setIndex, false)
} }

View file

@ -21,7 +21,7 @@ func TestSstack(t *testing.T) {
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
data[i] = &item{rand.Int(), rand.Int63()} data[i] = &item{rand.Int(), rand.Int63()}
} }
stack := newSstack(nil) stack := newSstack(nil, false)
for rep := 0; rep < 2; rep++ { for rep := 0; rep < 2; rep++ {
// Push all the data into the stack, pop out every second // Push all the data into the stack, pop out every second
secs := []*item{} secs := []*item{}
@ -55,7 +55,7 @@ func TestSstackSort(t *testing.T) {
data[i] = &item{rand.Int(), int64(i)} data[i] = &item{rand.Int(), int64(i)}
} }
// Push all the data into the stack // Push all the data into the stack
stack := newSstack(nil) stack := newSstack(nil, false)
for _, val := range data { for _, val := range data {
stack.Push(val) stack.Push(val)
} }
@ -76,7 +76,7 @@ func TestSstackReset(t *testing.T) {
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
data[i] = &item{rand.Int(), rand.Int63()} data[i] = &item{rand.Int(), rand.Int63()}
} }
stack := newSstack(nil) stack := newSstack(nil, false)
for rep := 0; rep < 2; rep++ { for rep := 0; rep < 2; rep++ {
// Push all the data into the stack, pop out every second // Push all the data into the stack, pop out every second
secs := []*item{} secs := []*item{}