github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/omap/osmap/osmap.go (about) 1 package osmap 2 3 // OSMap is a ordered string keyed map. 4 // It is eight to ten times slower than golang builtin map. 5 // Confirming my rule of thumb for hash-based vs. btree-based structures. 6 7 type OSMap struct { 8 root *node 9 less func(string, string) bool 10 length int 11 } 12 13 type node struct { 14 key, value string 15 red bool 16 left, right *node 17 } 18 19 // New returns an empty Map 20 func New() *OSMap { 21 f := func(a, b string) bool { 22 return a < b 23 } 24 return &OSMap{less: f} 25 } 26 27 // Insert inserts a new key-value into the Map returning true; 28 // or replaces an existing key-value pair's value returning false. 29 // inserted := myMap.Insert(key, value). 30 func (m *OSMap) Insert(key, value string) (inserted bool) { 31 m.root, inserted = m.insert(m.root, key, value, 0) 32 m.root.red = false 33 if inserted { 34 m.length++ 35 } 36 return inserted 37 } 38 39 // For compatibility 40 func (m *OSMap) Set(key, value string) (inserted bool) { return m.Insert(key, value) } 41 42 // Find returns the value and true if the key is in the Map 43 // or nil and false otherwise. 44 // value, found := myMap.Find(key). 45 func (m *OSMap) Find(key string) (value string, found bool) { 46 root := m.root 47 for root != nil { 48 if m.less(key, root.key) { 49 root = root.left 50 } else if m.less(root.key, key) { 51 root = root.right 52 } else { 53 return root.value, true 54 } 55 } 56 return "", false // string null value 57 } 58 59 // For compatibility 60 func (m *OSMap) Get(key string) (value string, found bool) { return m.Find(key) } 61 62 // Delete deletes the key-value returning true, 63 // or does nothing returning false 64 // deleted := myMap.Delete(key). 65 func (m *OSMap) Delete(key string) (deleted bool) { 66 if m.root != nil { 67 if m.root, deleted = m.remove(m.root, key); m.root != nil { 68 m.root.red = false 69 } 70 } 71 if deleted { 72 m.length-- 73 } 74 return deleted 75 } 76 77 // Do calls the given function on every key-value in the Map in order. 78 func (m *OSMap) Do(function func(string, string)) { 79 do(m.root, function) 80 } 81 82 // Len returns the number of key-value pairs in the map. 83 func (m *OSMap) Len() int { 84 return m.length 85 } 86 87 // ======================================================== 88 func INNER_CORE_FOR_EXTRACTION() { 89 // insert(args) 90 // do(args) 91 // remove(args) 92 93 } 94 95 func (m *OSMap) insert(root *node, key, value string, lvl int) (*node, bool) { 96 inserted := false 97 if root == nil { // If the key was in the tree it would belong here 98 if m.length%1000 == 0 && m.length > 10 { 99 // fmt.Printf("l%v-%v - ", lvl, m.length) 100 } 101 return &node{key: key, value: value, red: true}, true 102 } 103 if isRed(root.left) && isRed(root.right) { 104 colorFlip(root) 105 } 106 if m.less(key, root.key) { 107 root.left, inserted = m.insert(root.left, key, value, lvl+1) 108 } else if m.less(root.key, key) { 109 root.right, inserted = m.insert(root.right, key, value, lvl+1) 110 } else { // The key is already in the tree so just replace its value 111 root.value = value 112 } 113 if isRed(root.right) && !isRed(root.left) { 114 root = rotateLeft(root) 115 } 116 if isRed(root.left) && isRed(root.left.left) { 117 root = rotateRight(root) 118 } 119 return root, inserted 120 } 121 122 func isRed(root *node) bool { 123 return root != nil && root.red 124 } 125 126 func colorFlip(root *node) { 127 root.red = !root.red 128 if root.left != nil { 129 root.left.red = !root.left.red 130 } 131 if root.right != nil { 132 root.right.red = !root.right.red 133 } 134 } 135 136 func rotateLeft(root *node) *node { 137 x := root.right 138 root.right = x.left 139 x.left = root 140 x.red = root.red 141 root.red = true 142 return x 143 } 144 145 func rotateRight(root *node) *node { 146 x := root.left 147 root.left = x.right 148 x.right = root 149 x.red = root.red 150 root.red = true 151 return x 152 } 153 154 func do(root *node, function func(string, string)) { 155 if root != nil { 156 do(root.left, function) 157 function(root.key, root.value) 158 do(root.right, function) 159 } 160 } 161 162 // We do not provide an exported First() method because this is an 163 // implementation detail. 164 func first(root *node) *node { 165 for root.left != nil { 166 root = root.left 167 } 168 return root 169 } 170 171 func (m *OSMap) remove(root *node, key string) (*node, bool) { 172 deleted := false 173 if m.less(key, root.key) { 174 if root.left != nil { 175 if !isRed(root.left) && !isRed(root.left.left) { 176 root = moveRedLeft(root) 177 } 178 root.left, deleted = m.remove(root.left, key) 179 } 180 } else { 181 if isRed(root.left) { 182 root = rotateRight(root) 183 } 184 if !m.less(key, root.key) && !m.less(root.key, key) && 185 root.right == nil { 186 return nil, true 187 } 188 if root.right != nil { 189 if !isRed(root.right) && !isRed(root.right.left) { 190 root = moveRedRight(root) 191 } 192 if !m.less(key, root.key) && !m.less(root.key, key) { 193 smallest := first(root.right) 194 root.key = smallest.key 195 root.value = smallest.value 196 root.right = deleteMinimum(root.right) 197 deleted = true 198 } else { 199 root.right, deleted = m.remove(root.right, key) 200 } 201 } 202 } 203 return fixUp(root), deleted 204 } 205 206 func moveRedLeft(root *node) *node { 207 colorFlip(root) 208 if root.right != nil && isRed(root.right.left) { 209 root.right = rotateRight(root.right) 210 root = rotateLeft(root) 211 colorFlip(root) 212 } 213 return root 214 } 215 216 func moveRedRight(root *node) *node { 217 colorFlip(root) 218 if root.left != nil && isRed(root.left.left) { 219 root = rotateRight(root) 220 colorFlip(root) 221 } 222 return root 223 } 224 225 func deleteMinimum(root *node) *node { 226 if root.left == nil { 227 return nil 228 } 229 if !isRed(root.left) && !isRed(root.left.left) { 230 root = moveRedLeft(root) 231 } 232 root.left = deleteMinimum(root.left) 233 return fixUp(root) 234 } 235 236 func fixUp(root *node) *node { 237 if isRed(root.right) { 238 root = rotateLeft(root) 239 } 240 if isRed(root.left) && isRed(root.left.left) { 241 root = rotateRight(root) 242 } 243 if isRed(root.left) && isRed(root.right) { 244 colorFlip(root) 245 } 246 return root 247 }