github.com/go-ego/cedar@v0.10.2/cedar.go (about) 1 package cedar 2 3 const ( 4 // ValueLimit limit value 5 ValueLimit = int(^uint(0) >> 1) 6 ) 7 8 type node struct { 9 Value int 10 Check int 11 } 12 13 func (n *node) base() int { 14 return -(n.Value + 1) 15 } 16 17 type ninfo struct { 18 Sibling, Child byte 19 } 20 21 type block struct { 22 Prev, Next, Num, Reject, Trial, Ehead int 23 } 24 25 func (b *block) init() { 26 b.Num = 256 27 b.Reject = 257 28 } 29 30 // Cedar cedar struct 31 type Cedar struct { 32 Array []node 33 Ninfos []ninfo 34 Blocks []block 35 Reject [257]int 36 37 BheadF, BheadC, BheadO int 38 39 Capacity int 40 Size int 41 Ordered bool 42 MaxTrial int 43 } 44 45 // New new Cedar 46 func New() *Cedar { 47 da := Cedar{ 48 Array: make([]node, 256), 49 Ninfos: make([]ninfo, 256), 50 Blocks: make([]block, 1), 51 Capacity: 256, 52 Size: 256, 53 Ordered: true, 54 MaxTrial: 1, 55 } 56 57 da.Array[0] = node{-2, 0} 58 for i := 1; i < 256; i++ { 59 da.Array[i] = node{-(i - 1), -(i + 1)} 60 } 61 da.Array[1].Value = -255 62 da.Array[255].Check = -1 63 64 da.Blocks[0].Ehead = 1 65 da.Blocks[0].init() 66 67 for i := 0; i <= 256; i++ { 68 da.Reject[i] = i + 1 69 } 70 71 return &da 72 } 73 74 // Get value by key, insert the key if not exist 75 func (da *Cedar) get(key []byte, from, pos int) *int { 76 to := da.getV(key, from, pos) 77 return &da.Array[to].Value 78 } 79 80 // GetV value by key, insert the key if not exist 81 func (da *Cedar) getV(key []byte, from, pos int) int { 82 for ; pos < len(key); pos++ { 83 if value := da.Array[from].Value; value >= 0 && value != ValueLimit { 84 to := da.follow(from, 0) 85 da.Array[to].Value = value 86 } 87 from = da.follow(from, key[pos]) 88 } 89 90 to := from 91 if da.Array[from].Value < 0 { 92 to = da.follow(from, 0) 93 } 94 95 return to 96 } 97 98 func (da *Cedar) follow(from int, label byte) int { 99 base := da.Array[from].base() 100 to := base ^ int(label) 101 102 if base < 0 || da.Array[to].Check < 0 { 103 hasChild := false 104 if base >= 0 { 105 hasChild = (da.Array[base^int(da.Ninfos[from].Child)].Check == from) 106 } 107 to = da.popEnode(base, from, label) 108 da.pushSibling(from, to^int(label), label, hasChild) 109 110 return to 111 } 112 113 if da.Array[to].Check != from { 114 to = da.resolve(from, base, label) 115 return to 116 } 117 118 if da.Array[to].Check == from { 119 return to 120 } 121 122 panic("Cedar: internal error, should not be here") 123 // return to 124 } 125 126 func (da *Cedar) popBlock(bi int, headIn *int, last bool) { 127 if last { 128 *headIn = 0 129 return 130 } 131 132 b := &da.Blocks[bi] 133 da.Blocks[b.Prev].Next = b.Next 134 da.Blocks[b.Next].Prev = b.Prev 135 if bi == *headIn { 136 *headIn = b.Next 137 } 138 } 139 140 func (da *Cedar) pushBlock(bi int, headOut *int, empty bool) { 141 b := &da.Blocks[bi] 142 if empty { 143 *headOut, b.Prev, b.Next = bi, bi, bi 144 } else { 145 tailOut := &da.Blocks[*headOut].Prev 146 b.Prev = *tailOut 147 b.Next = *headOut 148 *headOut, *tailOut, da.Blocks[*tailOut].Next = bi, bi, bi 149 } 150 } 151 152 func (da *Cedar) addBlock() int { 153 if da.Size == da.Capacity { 154 da.Capacity *= 2 155 156 oldArray := da.Array 157 da.Array = make([]node, da.Capacity) 158 copy(da.Array, oldArray) 159 160 oldNinfo := da.Ninfos 161 da.Ninfos = make([]ninfo, da.Capacity) 162 copy(da.Ninfos, oldNinfo) 163 164 oldBlock := da.Blocks 165 da.Blocks = make([]block, da.Capacity>>8) 166 copy(da.Blocks, oldBlock) 167 } 168 169 da.Blocks[da.Size>>8].init() 170 da.Blocks[da.Size>>8].Ehead = da.Size 171 172 da.Array[da.Size] = node{-(da.Size + 255), -(da.Size + 1)} 173 for i := da.Size + 1; i < da.Size+255; i++ { 174 da.Array[i] = node{-(i - 1), -(i + 1)} 175 } 176 da.Array[da.Size+255] = node{-(da.Size + 254), -da.Size} 177 178 da.pushBlock(da.Size>>8, &da.BheadO, da.BheadO == 0) 179 da.Size += 256 180 return da.Size>>8 - 1 181 } 182 183 func (da *Cedar) transferBlock(bi int, headIn, headOut *int) { 184 da.popBlock(bi, headIn, bi == da.Blocks[bi].Next) 185 da.pushBlock(bi, headOut, *headOut == 0 && da.Blocks[bi].Num != 0) 186 } 187 188 func (da *Cedar) popEnode(base, from int, label byte) int { 189 e := base ^ int(label) 190 if base < 0 { 191 e = da.findPlace() 192 } 193 194 bi := e >> 8 195 n := &da.Array[e] 196 b := &da.Blocks[bi] 197 b.Num-- 198 199 if b.Num == 0 { 200 if bi != 0 { 201 da.transferBlock(bi, &da.BheadC, &da.BheadF) 202 } 203 } else { 204 da.Array[-n.Value].Check = n.Check 205 da.Array[-n.Check].Value = n.Value 206 207 if e == b.Ehead { 208 b.Ehead = -n.Check 209 } 210 211 if bi != 0 && b.Num == 1 && b.Trial != da.MaxTrial { 212 da.transferBlock(bi, &da.BheadO, &da.BheadC) 213 } 214 } 215 216 n.Value = ValueLimit 217 n.Check = from 218 if base < 0 { 219 da.Array[from].Value = -(e ^ int(label)) - 1 220 } 221 222 return e 223 } 224 225 func (da *Cedar) pushEnode(e int) { 226 bi := e >> 8 227 b := &da.Blocks[bi] 228 b.Num++ 229 230 if b.Num == 1 { 231 b.Ehead = e 232 da.Array[e] = node{-e, -e} 233 if bi != 0 { 234 da.transferBlock(bi, &da.BheadF, &da.BheadC) 235 } 236 } else { 237 prev := b.Ehead 238 next := -da.Array[prev].Check 239 da.Array[e] = node{-prev, -next} 240 da.Array[prev].Check = -e 241 da.Array[next].Value = -e 242 243 if b.Num == 2 || b.Trial == da.MaxTrial { 244 if bi != 0 { 245 da.transferBlock(bi, &da.BheadC, &da.BheadO) 246 } 247 } 248 249 b.Trial = 0 250 } 251 252 if b.Reject < da.Reject[b.Num] { 253 b.Reject = da.Reject[b.Num] 254 } 255 da.Ninfos[e] = ninfo{} 256 } 257 258 // hasChild: wherether the `from` node has children 259 func (da *Cedar) pushSibling(from, base int, label byte, hasChild bool) { 260 c := &da.Ninfos[from].Child 261 keepOrder := *c == 0 262 if da.Ordered { 263 keepOrder = label > *c 264 } 265 266 if hasChild && keepOrder { 267 c = &da.Ninfos[base^int(*c)].Sibling 268 for da.Ordered && *c != 0 && *c < label { 269 c = &da.Ninfos[base^int(*c)].Sibling 270 } 271 } 272 273 da.Ninfos[base^int(label)].Sibling = *c 274 *c = label 275 } 276 277 func (da *Cedar) popSibling(from, base int, label byte) { 278 c := &da.Ninfos[from].Child 279 for *c != label { 280 c = &da.Ninfos[base^int(*c)].Sibling 281 } 282 *c = da.Ninfos[base^int(*c)].Sibling 283 } 284 285 func (da *Cedar) consult(baseN, baseP int, cN, cP byte) bool { 286 cN = da.Ninfos[baseN^int(cN)].Sibling 287 cP = da.Ninfos[baseP^int(cP)].Sibling 288 289 for cN != 0 && cP != 0 { 290 cN = da.Ninfos[baseN^int(cN)].Sibling 291 cP = da.Ninfos[baseP^int(cP)].Sibling 292 } 293 return cP != 0 294 } 295 296 func (da *Cedar) setChild(base int, c, label byte, flag bool) []byte { 297 child := make([]byte, 0, 257) 298 if c == 0 { 299 child = append(child, c) 300 c = da.Ninfos[base^int(c)].Sibling 301 } 302 303 if da.Ordered { 304 for c != 0 && c <= label { 305 child = append(child, c) 306 c = da.Ninfos[base^int(c)].Sibling 307 } 308 } 309 310 if flag { 311 child = append(child, label) 312 } 313 314 for c != 0 { 315 child = append(child, c) 316 c = da.Ninfos[base^int(c)].Sibling 317 } 318 319 return child 320 } 321 322 func (da *Cedar) findPlace() int { 323 if da.BheadC != 0 { 324 return da.Blocks[da.BheadC].Ehead 325 } 326 327 if da.BheadO != 0 { 328 return da.Blocks[da.BheadO].Ehead 329 } 330 331 return da.addBlock() << 8 332 } 333 334 func (da *Cedar) findPlaces(child []byte) int { 335 bi := da.BheadO 336 if bi != 0 { 337 e := da.listBi(bi, child) 338 if e > 0 { 339 return e 340 } 341 } 342 343 return da.addBlock() << 8 344 } 345 346 func (da *Cedar) listBi(bi int, child []byte) int { 347 nc := len(child) 348 bz := da.Blocks[da.BheadO].Prev 349 350 for { 351 b := &da.Blocks[bi] 352 if b.Num >= nc && nc < b.Reject { 353 e := da.listEhead(b, child) 354 if e > 0 { 355 return e 356 } 357 } 358 359 b.Reject = nc 360 if b.Reject < da.Reject[b.Num] { 361 da.Reject[b.Num] = b.Reject 362 } 363 364 biN := b.Next 365 b.Trial++ 366 if b.Trial == da.MaxTrial { 367 da.transferBlock(bi, &da.BheadO, &da.BheadC) 368 } 369 370 if bi == bz { 371 break 372 } 373 bi = biN 374 } 375 376 return 0 377 } 378 379 func (da *Cedar) listEhead(b *block, child []byte) int { 380 for e := b.Ehead; ; { 381 base := e ^ int(child[0]) 382 for i := 0; da.Array[base^int(child[i])].Check < 0; i++ { 383 if i == len(child)-1 { 384 b.Ehead = e 385 // if e == 0 { 386 // } 387 return e 388 } 389 } 390 391 e = -da.Array[e].Check 392 if e == b.Ehead { 393 break 394 } 395 } 396 397 return 0 398 } 399 400 func (da *Cedar) resolve(fromN, baseN int, labelN byte) int { 401 toPn := baseN ^ int(labelN) 402 fromP := da.Array[toPn].Check 403 baseP := da.Array[fromP].base() 404 flag := da.consult(baseN, baseP, da.Ninfos[fromN].Child, da.Ninfos[fromP].Child) 405 406 var children []byte 407 if flag { 408 children = da.setChild(baseN, da.Ninfos[fromN].Child, labelN, true) 409 } else { 410 children = da.setChild(baseP, da.Ninfos[fromP].Child, 255, false) 411 } 412 413 var base int 414 if len(children) == 1 { 415 base = da.findPlace() 416 } else { 417 base = da.findPlaces(children) 418 } 419 base ^= int(children[0]) 420 421 var ( 422 from int 423 nbase int 424 ) 425 426 if flag { 427 from = fromN 428 nbase = baseN 429 } else { 430 from = fromP 431 nbase = baseP 432 } 433 434 if flag && children[0] == labelN { 435 da.Ninfos[from].Child = labelN 436 } 437 438 da.Array[from].Value = -base - 1 439 base, labelN, toPn = da.list(base, from, nbase, fromN, toPn, 440 labelN, children, flag) 441 442 if flag { 443 return base ^ int(labelN) 444 } 445 446 return toPn 447 } 448 449 func (da *Cedar) list(base, from, nbase, fromN, toPn int, 450 labelN byte, children []byte, flag bool) (int, byte, int) { 451 for i := 0; i < len(children); i++ { 452 to := da.popEnode(base, from, children[i]) 453 newTo := nbase ^ int(children[i]) 454 455 if i == len(children)-1 { 456 da.Ninfos[to].Sibling = 0 457 } else { 458 da.Ninfos[to].Sibling = children[i+1] 459 } 460 461 if flag && newTo == toPn { // new node has no child 462 continue 463 } 464 465 n := &da.Array[to] 466 ns := &da.Array[newTo] 467 n.Value = ns.Value 468 469 if n.Value < 0 && children[i] != 0 { 470 // this node has children, fix their check 471 c := da.Ninfos[newTo].Child 472 da.Ninfos[to].Child = c 473 da.Array[n.base()^int(c)].Check = to 474 475 c = da.Ninfos[n.base()^int(c)].Sibling 476 for c != 0 { 477 da.Array[n.base()^int(c)].Check = to 478 c = da.Ninfos[n.base()^int(c)].Sibling 479 } 480 } 481 482 if !flag && newTo == fromN { // parent node moved 483 fromN = to 484 } 485 486 if !flag && newTo == toPn { 487 da.pushSibling(fromN, toPn^int(labelN), labelN, true) 488 da.Ninfos[newTo].Child = 0 489 ns.Value = ValueLimit 490 ns.Check = fromN 491 } else { 492 da.pushEnode(newTo) 493 } 494 } 495 496 return base, labelN, toPn 497 }