github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/pkg/sortedmap/sortedmap.go (about) 1 // Copyright 2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sortedmap 6 7 import ( 8 "errors" 9 "sort" 10 "sync" 11 ) 12 13 var ErrNoSuchKey = errors.New("no such key exists") 14 15 // SearchInt64s implements sort.SearchInts for int64. 16 func SearchInt64s(a []int64, x int64) int { 17 return sort.Search(len(a), func(i int) bool { return a[i] >= x }) 18 } 19 20 // sortedSlice is a sorted slice of unique int64s. 21 type sortedSlice []int64 22 23 // Insert inserts value v int64o the appropriate location in the slice. 24 func (s *sortedSlice) Insert(v int64) { 25 // Search returns the index to insert v if it exists, 26 // so check that it doesn't exist before adding it. 27 i := SearchInt64s(*s, v) 28 if i < len(*s) && (*s)[i] == v { 29 return 30 } 31 32 // Grow the slice by one element. 33 *s = append(*s, 0) 34 // Move the upper part of the slice out of the way and open a hole. 35 copy((*s)[i+1:], (*s)[i:]) 36 // Store the new value. 37 (*s)[i] = v 38 } 39 40 // Delete deletes the value v from the slice. 41 func (s *sortedSlice) Delete(v int64) { 42 // Search returns the index to insert v if it doesn't exist, 43 // so check that it exists before deleting it. 44 i := SearchInt64s(*s, v) 45 if i >= len(*s) || (*s)[i] != v { 46 return 47 } 48 49 *s = append((*s)[:i], (*s)[i+1:]...) 50 } 51 52 // Search returns the index of v in the slice, if exists is true. 53 // Otherwise, it is the location v would be inserted. All indices less 54 // than i contain values less than v. 55 func (s *sortedSlice) Search(v int64) (i int, exists bool) { 56 i = SearchInt64s(*s, v) 57 // Does v exist, or is this just the location to insert it. 58 if i < len(*s) && (*s)[i] == v { 59 exists = true 60 } 61 62 return 63 } 64 65 // Map is a sorted map[int64]int64. 66 type Map struct { 67 // m is the underlying map store 68 m map[int64]int64 69 70 // k is the sorted list of keys 71 k sortedSlice 72 73 // mu locks the Map. 74 mu sync.RWMutex 75 } 76 77 // Insert inserts a key, value pair. 78 func (m *Map) Insert(k, v int64) { 79 m.mu.Lock() 80 defer m.mu.Unlock() 81 82 // Delete any duplicate entry. 83 m.deleteImpl(k) 84 85 m.m[k] = v 86 m.k.Insert(k) 87 } 88 89 // Delete key from map, must be called with mu held. 90 func (m *Map) deleteImpl(k int64) { 91 delete(m.m, k) 92 m.k.Delete(k) 93 } 94 95 // Delete deletes the value stored at k from the map. 96 func (m *Map) Delete(k int64) { 97 m.mu.Lock() 98 defer m.mu.Unlock() 99 100 m.deleteImpl(k) 101 } 102 103 // Get gets the value at a specific key. 104 func (m *Map) Get(k int64) (v int64, ok bool) { 105 m.mu.RLock() 106 defer m.mu.RUnlock() 107 108 v, ok = m.m[k] 109 return 110 } 111 112 // NearestLessEqual returns the nearest key, value pair that exists in 113 // the map with a key <= want. 114 func (m *Map) NearestLessEqual(want int64) (key, value int64, err error) { 115 m.mu.RLock() 116 defer m.mu.RUnlock() 117 118 i, exists := m.k.Search(want) 119 // Key already exists in the map. 120 if exists { 121 return want, m.m[want], nil 122 } 123 124 // i - 1 contains the nearest key less than the desired key. 125 if i < 1 { 126 return 0, 0, ErrNoSuchKey 127 } 128 129 key = m.k[i-1] 130 value = m.m[key] 131 132 return key, value, nil 133 } 134 135 // NearestGreater returns the nearest key, value pair that exists in 136 // the map with a key > want. 137 func (m *Map) NearestGreater(want int64) (key, value int64, err error) { 138 m.mu.RLock() 139 defer m.mu.RUnlock() 140 141 // By searching for want + 1, we the lowest possible index for 142 // want + 1, which must either not exist or contain something 143 // larger than want. 144 i, _ := m.k.Search(want + 1) 145 146 // i is off the end of the slice, there is nothing > want. 147 if i >= len(m.k) { 148 return 0, 0, ErrNoSuchKey 149 } 150 151 key = m.k[i] 152 value = m.m[key] 153 154 return key, value, nil 155 } 156 157 func NewMap() Map { 158 return Map{ 159 m: make(map[int64]int64), 160 k: make(sortedSlice, 0), 161 } 162 }