github.com/gogf/gf@v1.16.9/os/gtimer/gtimer_queue.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gtimer
     8  
     9  import (
    10  	"container/heap"
    11  	"github.com/gogf/gf/container/gtype"
    12  	"math"
    13  	"sync"
    14  )
    15  
    16  // priorityQueue is an abstract data type similar to a regular queue or stack data structure in which
    17  // each element additionally has a "priority" associated with it. In a priority queue, an element with
    18  // high priority is served before an element with low priority.
    19  // priorityQueue is based on heap structure.
    20  type priorityQueue struct {
    21  	mu           sync.Mutex
    22  	heap         *priorityQueueHeap // the underlying queue items manager using heap.
    23  	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.
    24  }
    25  
    26  // priorityQueueHeap is a heap manager, of which the underlying `array` is a array implementing a heap structure.
    27  type priorityQueueHeap struct {
    28  	array []priorityQueueItem
    29  }
    30  
    31  // priorityQueueItem stores the queue item which has a `priority` attribute to sort itself in heap.
    32  type priorityQueueItem struct {
    33  	value    interface{}
    34  	priority int64
    35  }
    36  
    37  // newPriorityQueue creates and returns a priority queue.
    38  func newPriorityQueue() *priorityQueue {
    39  	queue := &priorityQueue{
    40  		heap:         &priorityQueueHeap{array: make([]priorityQueueItem, 0)},
    41  		nextPriority: gtype.NewInt64(math.MaxInt64),
    42  	}
    43  	heap.Init(queue.heap)
    44  	return queue
    45  }
    46  
    47  // NextPriority retrieves and returns the minimum and the most priority value of the queue.
    48  func (q *priorityQueue) NextPriority() int64 {
    49  	return q.nextPriority.Val()
    50  }
    51  
    52  // Push pushes a value to the queue.
    53  // The `priority` specifies the priority of the value.
    54  // The lesser the `priority` value the higher priority of the `value`.
    55  func (q *priorityQueue) Push(value interface{}, priority int64) {
    56  	q.mu.Lock()
    57  	defer q.mu.Unlock()
    58  	heap.Push(q.heap, priorityQueueItem{
    59  		value:    value,
    60  		priority: priority,
    61  	})
    62  	// Update the minimum priority using atomic operation.
    63  	nextPriority := q.nextPriority.Val()
    64  	if priority >= nextPriority {
    65  		return
    66  	}
    67  	q.nextPriority.Set(priority)
    68  }
    69  
    70  // Pop retrieves, removes and returns the most high priority value from the queue.
    71  func (q *priorityQueue) Pop() interface{} {
    72  	q.mu.Lock()
    73  	defer q.mu.Unlock()
    74  	if v := heap.Pop(q.heap); v != nil {
    75  		var nextPriority int64 = math.MaxInt64
    76  		if len(q.heap.array) > 0 {
    77  			nextPriority = q.heap.array[0].priority
    78  		}
    79  		q.nextPriority.Set(nextPriority)
    80  		return v.(priorityQueueItem).value
    81  	}
    82  	return nil
    83  }