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 }