2021-05-15 18:13:51 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gtimer
import (
"container/heap"
"math"
"sync"
2021-11-15 20:49:02 +08:00
"github.com/gogf/gf/v2/container/gtype"
2021-05-15 18:13:51 +08:00
)
// priorityQueue is an abstract data type similar to a regular queue or stack data structure in which
// each element additionally has a "priority" associated with it. In a priority queue, an element with
// high priority is served before an element with low priority.
// priorityQueue is based on heap structure.
type priorityQueue struct {
2021-08-06 12:08:49 +08:00
mu sync . Mutex
heap * priorityQueueHeap // the underlying queue items manager using heap.
nextPriority * gtype . Int64 // nextPriority stores the next priority value of the heap, which is used to check if necessary to call the Pop of heap by Timer.
2021-05-15 18:13:51 +08:00
}
// priorityQueueHeap is a heap manager, of which the underlying `array` is a array implementing a heap structure.
type priorityQueueHeap struct {
array [ ] priorityQueueItem
}
// priorityQueueItem stores the queue item which has a `priority` attribute to sort itself in heap.
type priorityQueueItem struct {
value interface { }
priority int64
}
// newPriorityQueue creates and returns a priority queue.
func newPriorityQueue ( ) * priorityQueue {
queue := & priorityQueue {
2021-08-06 12:08:49 +08:00
heap : & priorityQueueHeap { array : make ( [ ] priorityQueueItem , 0 ) } ,
nextPriority : gtype . NewInt64 ( math . MaxInt64 ) ,
2021-05-15 18:13:51 +08:00
}
heap . Init ( queue . heap )
return queue
}
2021-08-06 12:08:49 +08:00
// NextPriority retrieves and returns the minimum and the most priority value of the queue.
func ( q * priorityQueue ) NextPriority ( ) int64 {
return q . nextPriority . Val ( )
2021-05-15 18:13:51 +08:00
}
// Push pushes a value to the queue.
// The `priority` specifies the priority of the value.
// The lesser the `priority` value the higher priority of the `value`.
func ( q * priorityQueue ) Push ( value interface { } , priority int64 ) {
q . mu . Lock ( )
2021-08-06 12:08:49 +08:00
defer q . mu . Unlock ( )
2021-05-15 18:27:46 +08:00
heap . Push ( q . heap , priorityQueueItem {
value : value ,
priority : priority ,
} )
2021-05-15 18:13:51 +08:00
// Update the minimum priority using atomic operation.
2021-08-06 12:08:49 +08:00
nextPriority := q . nextPriority . Val ( )
if priority >= nextPriority {
return
2021-05-15 18:13:51 +08:00
}
2021-08-06 12:08:49 +08:00
q . nextPriority . Set ( priority )
2021-05-15 18:13:51 +08:00
}
// Pop retrieves, removes and returns the most high priority value from the queue.
func ( q * priorityQueue ) Pop ( ) interface { } {
q . mu . Lock ( )
2021-08-06 12:08:49 +08:00
defer q . mu . Unlock ( )
2021-05-15 18:27:46 +08:00
if v := heap . Pop ( q . heap ) ; v != nil {
2021-08-06 12:08:49 +08:00
var nextPriority int64 = math . MaxInt64
if len ( q . heap . array ) > 0 {
nextPriority = q . heap . array [ 0 ] . priority
2021-05-15 18:27:46 +08:00
}
2021-08-06 12:08:49 +08:00
q . nextPriority . Set ( nextPriority )
return v . ( priorityQueueItem ) . value
2021-05-15 18:13:51 +08:00
}
return nil
}