gitlab.com/beacon-software/gadget@v0.0.0-20181217202115-54565ea1ed5e/collection/specialized/hashpriorityqueue.go (about)

     1  package specialized
     2  
     3  import (
     4  	"gitlab.com/beacon-software/gadget/collection"
     5  )
     6  
     7  // HashPriority exposes both a priority function and Hash function.
     8  type HashPriority interface {
     9  	Priority
    10  	GetHash() interface{}
    11  }
    12  
    13  // HashPriorityQueue prevents duplicate prioritized entries in a queue.
    14  type HashPriorityQueue interface {
    15  	// Size of this queue
    16  	Size() int
    17  	// Push the passed element onto this queue if it does not already exist in
    18  	// the queue.
    19  	Push(element HashPriority)
    20  	// Pop the highest priority element off the queue
    21  	Pop() (HashPriority, bool)
    22  	// Peek at the highest priority element without modifying the queue
    23  	Peek() (HashPriority, bool)
    24  }
    25  
    26  // NewHashPriorityQueue for queueing unique elements by priority.
    27  func NewHashPriorityQueue() HashPriorityQueue {
    28  	return &hashPriorityQueue{
    29  		set:    collection.NewSet(),
    30  		pqueue: NewPriorityQueue(),
    31  	}
    32  }
    33  
    34  type hashPriorityWrapper struct {
    35  	priority int
    36  	element  HashPriority
    37  }
    38  
    39  func (hpw *hashPriorityWrapper) GetPriority() int {
    40  	return hpw.priority
    41  }
    42  
    43  func (hpw *hashPriorityWrapper) GetHash() interface{} {
    44  	return hpw.element.GetHash()
    45  }
    46  
    47  func newHashPriorityWrapper(element HashPriority) *hashPriorityWrapper {
    48  	return &hashPriorityWrapper{
    49  		priority: element.GetPriority(),
    50  		element:  element,
    51  	}
    52  }
    53  
    54  type hashPriorityQueue struct {
    55  	set    collection.Set
    56  	pqueue PriorityQueue
    57  }
    58  
    59  func (hpq *hashPriorityQueue) Size() int {
    60  	return hpq.pqueue.Size()
    61  }
    62  
    63  func (hpq *hashPriorityQueue) Push(element HashPriority) {
    64  	hash := element.GetHash()
    65  	wrappedElement := newHashPriorityWrapper(element)
    66  	if hpq.set.Contains(hash) {
    67  		for elm := hpq.pqueue.(*priorityQueue).list.Head(); elm != nil; elm = elm.Next() {
    68  			d := hpq.convert(elm.Data())
    69  			if d.GetHash() == hash {
    70  				hpq.pqueue.(*priorityQueue).list.Remove(elm)
    71  				wrappedElement.priority = d.GetPriority()
    72  			}
    73  		}
    74  	}
    75  	hpq.pqueue.Push(wrappedElement)
    76  	hpq.set.Add(hash)
    77  }
    78  
    79  func (hpq *hashPriorityQueue) convert(data interface{}) HashPriority {
    80  	p, _ := data.(HashPriority)
    81  	return p
    82  }
    83  
    84  func (hpq *hashPriorityQueue) nextElement(next func() (Priority, bool), remove bool) (HashPriority, bool) {
    85  	p, ok := next()
    86  	var hp *hashPriorityWrapper
    87  	if !ok {
    88  		return nil, false
    89  	}
    90  
    91  	hp, _ = p.(*hashPriorityWrapper)
    92  	if remove {
    93  		hpq.set.Remove(hp.GetHash())
    94  	}
    95  	return hp.element, true
    96  }
    97  
    98  func (hpq *hashPriorityQueue) Pop() (HashPriority, bool) {
    99  	return hpq.nextElement(hpq.pqueue.Pop, true)
   100  }
   101  
   102  func (hpq *hashPriorityQueue) Peek() (HashPriority, bool) {
   103  	return hpq.nextElement(hpq.pqueue.Peek, false)
   104  }