sigs.k8s.io/kueue@v0.6.2/pkg/util/heap/heap.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // heap.Interface implementation inspired by
    18  // https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/internal/heap/heap.go
    19  package heap
    20  
    21  import (
    22  	"container/heap"
    23  )
    24  
    25  // lessFunc is a function that receives two items and returns true if the first
    26  // item should be placed before the second one when the list is sorted.
    27  type lessFunc func(a, b interface{}) bool
    28  
    29  // KeyFunc is a function type to get the key from an object.
    30  type keyFunc func(obj interface{}) string
    31  
    32  type heapItem struct {
    33  	obj   interface{}
    34  	index int
    35  }
    36  
    37  type itemKeyValue struct {
    38  	key string
    39  	obj interface{}
    40  }
    41  
    42  // data is an internal struct that implements the standard heap interface
    43  // and keeps the data stored in the heap.
    44  type data struct {
    45  	// items is a map from key of the objects to the objects and their index
    46  	items map[string]*heapItem
    47  	// keys keeps the keys of the objects ordered according to the heap invariant.
    48  	keys     []string
    49  	keyFunc  keyFunc
    50  	lessFunc lessFunc
    51  }
    52  
    53  var _ = heap.Interface(&data{})
    54  
    55  // Less compares two objects and returns true if the first one should go
    56  // in front of the second one in the heap.
    57  func (h *data) Less(i, j int) bool {
    58  	if i > h.Len() || j > h.Len() {
    59  		return false
    60  	}
    61  	a, ok := h.items[h.keys[i]]
    62  	if !ok {
    63  		return false
    64  	}
    65  	b, ok := h.items[h.keys[j]]
    66  	if !ok {
    67  		return false
    68  	}
    69  	return h.lessFunc(a.obj, b.obj)
    70  }
    71  
    72  // Len returns the number of items in the Heap.
    73  func (h *data) Len() int {
    74  	return len(h.keys)
    75  }
    76  
    77  // Swap implements swapping of two elements in the heap. This is a part of standard
    78  // heap interface and should never be called directly.
    79  func (h *data) Swap(i, j int) {
    80  	h.keys[i], h.keys[j] = h.keys[j], h.keys[i]
    81  	h.items[h.keys[i]].index = i
    82  	h.items[h.keys[j]].index = j
    83  }
    84  
    85  // Push is supposed to be called by heap.Push only.
    86  func (h *data) Push(kv interface{}) {
    87  	keyValue := kv.(*itemKeyValue)
    88  	h.items[keyValue.key] = &heapItem{
    89  		obj:   keyValue.obj,
    90  		index: len(h.keys),
    91  	}
    92  	h.keys = append(h.keys, keyValue.key)
    93  }
    94  
    95  // Pop is supposed to be called by heap.Pop only.
    96  func (h *data) Pop() interface{} {
    97  	key := h.keys[len(h.keys)-1]
    98  	h.keys = h.keys[:len(h.keys)-1]
    99  	item, ok := h.items[key]
   100  	if !ok {
   101  		// This is an error
   102  		return nil
   103  	}
   104  	delete(h.items, key)
   105  	return item.obj
   106  }
   107  
   108  // Heap is a producer/consumer queue that implements a heap data structure.
   109  // It can be used to implement priority queues and similar data structures.
   110  type Heap struct {
   111  	data data
   112  }
   113  
   114  // PushOrUpdate inserts an item to the queue.
   115  // The item will be updated if it already exists.
   116  func (h *Heap) PushOrUpdate(obj interface{}) {
   117  	key := h.data.keyFunc(obj)
   118  	if _, exists := h.data.items[key]; exists {
   119  		h.data.items[key].obj = obj
   120  		heap.Fix(&h.data, h.data.items[key].index)
   121  	} else {
   122  		heap.Push(&h.data, &itemKeyValue{key, obj})
   123  	}
   124  }
   125  
   126  // PushIfNotPresent inserts an item to the queue. If an item with
   127  // the key is present in the map, no changes is made to the item.
   128  func (h *Heap) PushIfNotPresent(obj interface{}) (added bool) {
   129  	key := h.data.keyFunc(obj)
   130  	if _, exists := h.data.items[key]; exists {
   131  		return false
   132  	}
   133  
   134  	heap.Push(&h.data, &itemKeyValue{key, obj})
   135  	return true
   136  }
   137  
   138  // Delete removes an item.
   139  func (h *Heap) Delete(key string) {
   140  	item, exists := h.data.items[key]
   141  	if !exists {
   142  		return
   143  	}
   144  	heap.Remove(&h.data, item.index)
   145  }
   146  
   147  // Pop returns the head of the heap and removes it.
   148  func (h *Heap) Pop() interface{} {
   149  	return heap.Pop(&h.data)
   150  }
   151  
   152  // Get returns the requested item, exists, error.
   153  func (h *Heap) Get(obj interface{}) (item interface{}) {
   154  	key := h.data.keyFunc(obj)
   155  	return h.GetByKey(key)
   156  }
   157  
   158  // GetByKey returns the requested item, or sets exists=false.
   159  func (h *Heap) GetByKey(key string) interface{} {
   160  	item, exists := h.data.items[key]
   161  	if !exists {
   162  		return nil
   163  	}
   164  	return item.obj
   165  }
   166  
   167  // Len returns the number of items in the heap.
   168  func (h *Heap) Len() int {
   169  	return h.data.Len()
   170  }
   171  
   172  // List returns a list of all the items.
   173  func (h *Heap) List() []interface{} {
   174  	list := make([]interface{}, 0, h.Len())
   175  	for _, item := range h.data.items {
   176  		list = append(list, item.obj)
   177  	}
   178  	return list
   179  }
   180  
   181  // New returns a Heap which can be used to queue up items to process.
   182  func New(keyFn keyFunc, lessFn lessFunc) Heap {
   183  	return Heap{
   184  		data: data{
   185  			items:    map[string]*heapItem{},
   186  			keyFunc:  keyFn,
   187  			lessFunc: lessFn,
   188  		},
   189  	}
   190  }