github.com/pbberlin/tools@v0.0.0-20160910141205-7aa5421c2169/omap/osmaps/osmaps.go (about) 1 package osmaps 2 3 import ( 4 "fmt" 5 "sort" 6 "strconv" 7 8 "github.com/pbberlin/tools/util" 9 ) 10 11 const ( 12 zeroVal = "" 13 cFanout = 12 // key-values per node 14 cPrealloc = 1500 // kv-slices pre-allocated on map-creation 15 16 noSuccessor = -1 // constant indicating no successor 17 ) 18 19 var ( 20 cntr = 0 21 ndStat = make([]map[*node]int, 20) // node statistics 22 ) 23 24 func init() { 25 for i := 0; i < len(ndStat); i++ { 26 ndStat[i] = make(map[*node]int, 0) 27 } 28 } 29 30 // key-value type 31 type kvt struct { 32 key, val string 33 succ int 34 } 35 36 type OSMap struct { 37 root *node 38 less func(string, string) bool 39 length int 40 41 reservoir [][]kvt 42 allocCntr int 43 } 44 45 type node struct { 46 min, max string // key 47 minIdx int // index to smallest key 48 kv []kvt 49 50 red bool 51 left, right *node 52 } 53 54 // New returns an empty Map 55 func New() *OSMap { 56 f := func(a, b string) bool { 57 return a < b 58 } 59 m := &OSMap{less: f} 60 61 x := make([][]kvt, cPrealloc) 62 for i := 0; i < len(x); i++ { 63 x[i] = make([]kvt, 0, cFanout) 64 } 65 m.reservoir = x 66 return m 67 } 68 69 // Insert inserts a new key-value into the Map returning true; 70 // or replaces an existing key-value pair's value returning false. 71 // inserted := myMap.Insert(key, value). 72 func (m *OSMap) Insert(key, value string) (inserted bool) { 73 m.root, inserted = m.insert(m.root, key, value, 0) 74 m.root.red = false 75 if inserted { 76 m.length++ 77 } 78 return inserted 79 } 80 81 // For compatibility 82 func (m *OSMap) Set(key, value string) (inserted bool) { return m.Insert(key, value) } 83 84 // Find returns the value and true if the key is in the Map 85 // or nil and false otherwise. 86 // value, found := myMap.Find(key). 87 func (m *OSMap) Find(key string) (value string, found bool) { 88 nd := m.root 89 for nd != nil { 90 if m.less(key, nd.min) && nd.left != nil { 91 nd = nd.left 92 } else if m.less(nd.max, key) && nd.right != nil { 93 nd = nd.right 94 } else { 95 _, value, found = findInner(nd, key) 96 return 97 } 98 } 99 return zeroVal, false // string null value 100 } 101 102 // For compatibility 103 func (m *OSMap) Get(key string) (value string, found bool) { return m.Find(key) } 104 105 // Delete deletes the key-value returning true, 106 // or does nothing returning false 107 // deleted := myMap.Delete(key). 108 func (m *OSMap) Delete(key string) (deleted bool) { 109 if m.root != nil { 110 if m.root, deleted = m.remove(m.root, key); m.root != nil { 111 m.root.red = false 112 } 113 } 114 if deleted { 115 m.length-- 116 } 117 return deleted 118 } 119 120 // Do calls the given function 121 // on every key-value in the Map in order. 122 func (m *OSMap) Do(fct1 func(string, string)) { 123 do(m.root, fct1) 124 } 125 126 // Len returns the number of key-value pairs in the map. 127 func (m *OSMap) Len() int { 128 return m.length 129 } 130 131 // ======================================================== 132 func INNER_CORE_FOR_EXTRACTION() { 133 // insert(args) 134 // do(args) 135 // remove(args) 136 137 } 138 139 func findInner(nd *node, key string) (idx int, val string, found bool) { 140 141 for i := 0; i < len(nd.kv); i++ { 142 if nd.kv[i].key == key { 143 return i, nd.kv[i].val, true 144 } 145 } 146 return noSuccessor, zeroVal, false 147 148 } 149 150 func (m *OSMap) insert(nd *node, key, value string, lvl int) (*node, bool) { 151 inserted := false 152 153 if nd == nil { 154 // If the key was in the tree it would belong here 155 newNd := node{} 156 newNd.red = true 157 newNd.min = key 158 newNd.max = key 159 newNd.kv = make([]kvt, 0, cFanout) 160 newNd.kv = append(newNd.kv, kvt{key, value, noSuccessor}) 161 return &newNd, true 162 } 163 164 if isRed(nd.left) && isRed(nd.right) { 165 colorFlip(nd) 166 } 167 168 if m.less(key, nd.min) && nd.left != nil { 169 // printStatus("branch left", key, lvl) 170 nd.left, inserted = m.insert(nd.left, key, value, lvl+1) 171 } else if m.less(nd.max, key) && nd.right != nil { 172 // printStatus("branch rght", key, lvl) 173 nd.right, inserted = m.insert(nd.right, key, value, lvl+1) 174 } else { 175 // printStatus("remain", key, lvl) 176 idx, _, contains := findInner(nd, key) 177 if contains { 178 nd.kv[idx].val = value // update 179 } else { 180 inserted = insertLinkedList(nd, m.less, key, value) 181 } 182 183 } 184 185 if len(nd.kv) > cFanout-1 { 186 // -1 | split one step *before* reaching capacity 187 x := nd.right 188 nd.right = m.split(nd, lvl) 189 nd.right.right = x 190 } 191 192 // 193 194 if isRed(nd.right) && !isRed(nd.left) { 195 nd = rotateLeft(nd) 196 } 197 if isRed(nd.left) && isRed(nd.left.left) { 198 nd = rotateRight(nd) 199 } 200 return nd, inserted 201 } 202 203 func (m *OSMap) split(nd *node, lvl int) *node { 204 205 sortedK := make([]string, len(nd.kv)) 206 for i := 0; i < len(nd.kv); i++ { 207 sortedK[i] = nd.kv[i].key 208 } 209 sort.Strings(sortedK) 210 211 halfIdx := len(nd.kv) / 2 212 splitkey := sortedK[halfIdx] 213 214 ndStat[lvl][nd]++ 215 216 if lvl == 4 || lvl == 6 { 217 kd := make([]string, 3) 218 kd[0], kd[1], kd[2] = sortedK[0], splitkey, sortedK[len(sortedK)-1] 219 for i := 0; i < len(kd); i++ { 220 kd[i] = kd[i][:util.Min(len(kd[i]), 3)] 221 } 222 // fmt.Printf("splitting l%2v ac%3v %4q < %4q < %4q \n", lvl, m.allocCntr, kd[0], kd[1], kd[2]) 223 } 224 225 // kv1 := make([]kvt, 0, cFanout) 226 // kv2 := make([]kvt, 0, cFanout) 227 228 kv1 := m.reservoir[m.allocCntr] 229 m.allocCntr++ 230 kv2 := m.reservoir[m.allocCntr] 231 m.allocCntr++ 232 233 for i := 0; i < len(nd.kv); i++ { 234 if m.less(nd.kv[i].key, splitkey) { 235 kv1 = append(kv1, nd.kv[i]) 236 } else { 237 kv2 = append(kv2, nd.kv[i]) 238 } 239 } 240 241 nd.min = sortedK[0] 242 nd.max = sortedK[halfIdx-1] 243 nd.kv = kv1 244 245 newNd := node{} 246 newNd.red = true 247 newNd.min = splitkey 248 newNd.max = sortedK[len(sortedK)-1] 249 newNd.kv = kv2 250 251 return &newNd 252 253 } 254 255 func isRed(nd *node) bool { 256 return nd != nil && nd.red 257 } 258 259 func colorFlip(nd *node) { 260 nd.red = !nd.red 261 if nd.left != nil { 262 nd.left.red = !nd.left.red 263 } 264 if nd.right != nil { 265 nd.right.red = !nd.right.red 266 } 267 } 268 269 func rotateLeft(root *node) *node { 270 x := root.right 271 root.right = x.left 272 x.left = root 273 x.red = root.red 274 root.red = true 275 return x 276 } 277 278 func rotateRight(root *node) *node { 279 x := root.left 280 root.left = x.right 281 x.right = root 282 x.red = root.red 283 root.red = true 284 return x 285 } 286 287 func do(nd *node, fct1 func(string, string)) { 288 if nd != nil { 289 290 do(nd.left, fct1) 291 292 for i := 0; i < len(nd.kv); i++ { 293 fct1(nd.kv[i].key, nd.kv[i].val) 294 } 295 296 do(nd.right, fct1) 297 298 } 299 } 300 301 // We do not provide an exported First() method because this is an 302 // implementation detail. 303 func first(root *node) *node { 304 for root.left != nil { 305 root = root.left 306 } 307 return root 308 } 309 310 func (m *OSMap) remove(root *node, key string) (*node, bool) { 311 deleted := false 312 313 /* 314 if m.less(key, root.key) { 315 if root.left != nil { 316 if !isRed(root.left) && !isRed(root.left.left) { 317 root = moveRedLeft(root) 318 } 319 root.left, deleted = m.remove(root.left, key) 320 } 321 } else { 322 if isRed(root.left) { 323 root = rotateRight(root) 324 } 325 if !m.less(key, root.key) && !m.less(root.key, key) && 326 root.right == nil { 327 return nil, true 328 } 329 if root.right != nil { 330 if !isRed(root.right) && !isRed(root.right.left) { 331 root = moveRedRight(root) 332 } 333 if !m.less(key, root.key) && !m.less(root.key, key) { 334 smallest := first(root.right) 335 root.key = smallest.key 336 root.value = smallest.value 337 root.right = deleteMinimum(root.right) 338 deleted = true 339 } else { 340 root.right, deleted = m.remove(root.right, key) 341 } 342 } 343 } 344 */ 345 return fixUp(root), deleted 346 } 347 348 func moveRedLeft(root *node) *node { 349 colorFlip(root) 350 if root.right != nil && isRed(root.right.left) { 351 root.right = rotateRight(root.right) 352 root = rotateLeft(root) 353 colorFlip(root) 354 } 355 return root 356 } 357 358 func moveRedRight(root *node) *node { 359 colorFlip(root) 360 if root.left != nil && isRed(root.left.left) { 361 root = rotateRight(root) 362 colorFlip(root) 363 } 364 return root 365 } 366 367 func deleteMinimum(root *node) *node { 368 if root.left == nil { 369 return nil 370 } 371 if !isRed(root.left) && !isRed(root.left.left) { 372 root = moveRedLeft(root) 373 } 374 root.left = deleteMinimum(root.left) 375 return fixUp(root) 376 } 377 378 func fixUp(root *node) *node { 379 if isRed(root.right) { 380 root = rotateLeft(root) 381 } 382 if isRed(root.left) && isRed(root.left.left) { 383 root = rotateRight(root) 384 } 385 if isRed(root.left) && isRed(root.right) { 386 colorFlip(root) 387 } 388 return root 389 } 390 391 func printStatus(msg, key string, lvl int) { 392 393 if cntr%1000 < 20 { 394 kd := key 395 if len(key) > 3 { 396 kd = key[:3] 397 } 398 fmt.Printf("%-12v %5v l%2v\n", msg, kd, lvl) 399 } 400 cntr++ 401 } 402 403 // is there a better way to convert a pointer to a hash 404 func pointerHash(p *string) (int64, int) { 405 406 sp := fmt.Sprintf("%p", p) // string pointer 407 408 pi, err := strconv.ParseInt(sp, 0, 64) // pointer integer 409 if err != nil { 410 fmt.Printf("Error converting pointer to int64: %v - pointer was %v\n", err, sp) 411 return 0, 0 412 } 413 414 mod := int(pi % (1000)) 415 416 cntr++ 417 if cntr%5000 == 0 { 418 fmt.Printf("%v %v | ", pi, mod) 419 } 420 421 return pi, mod 422 423 }