123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- package cedar
- const (
- // ValueLimit limit value
- ValueLimit = int(^uint(0) >> 1)
- )
- type node struct {
- Value int
- Check int
- }
- func (n *node) base() int {
- return -(n.Value + 1)
- }
- type ninfo struct {
- Sibling, Child byte
- }
- type block struct {
- Prev, Next, Num, Reject, Trial, Ehead int
- }
- func (b *block) init() {
- b.Num = 256
- b.Reject = 257
- }
- // Cedar cedar struct
- type Cedar struct {
- *cedar
- }
- type cedar struct {
- Array []node
- Ninfos []ninfo
- Blocks []block
- Reject [257]int
- BheadF int
- BheadC int
- BheadO int
- Capacity int
- Size int
- Ordered bool
- MaxTrial int
- }
- // New new cedar
- func New() *Cedar {
- da := cedar{
- Array: make([]node, 256),
- Ninfos: make([]ninfo, 256),
- Blocks: make([]block, 1),
- Capacity: 256,
- Size: 256,
- Ordered: true,
- MaxTrial: 1,
- }
- da.Array[0] = node{-2, 0}
- for i := 1; i < 256; i++ {
- da.Array[i] = node{-(i - 1), -(i + 1)}
- }
- da.Array[1].Value = -255
- da.Array[255].Check = -1
- da.Blocks[0].Ehead = 1
- da.Blocks[0].init()
- for i := 0; i <= 256; i++ {
- da.Reject[i] = i + 1
- }
- return &Cedar{&da}
- }
- // Get value by key, insert the key if not exist
- func (da *cedar) get(key []byte, from, pos int) *int {
- for ; pos < len(key); pos++ {
- if value := da.Array[from].Value; value >= 0 && value != ValueLimit {
- to := da.follow(from, 0)
- da.Array[to].Value = value
- }
- from = da.follow(from, key[pos])
- }
- to := from
- if da.Array[from].Value < 0 {
- to = da.follow(from, 0)
- }
- return &da.Array[to].Value
- }
- func (da *cedar) follow(from int, label byte) int {
- base := da.Array[from].base()
- to := base ^ int(label)
- if base < 0 || da.Array[to].Check < 0 {
- hasChild := false
- if base >= 0 {
- hasChild = (da.Array[base^int(da.Ninfos[from].Child)].Check == from)
- }
- to = da.popEnode(base, label, from)
- da.pushSibling(from, to^int(label), label, hasChild)
- return to
- }
- if da.Array[to].Check != from {
- to = da.resolve(from, base, label)
- return to
- }
- if da.Array[to].Check == from {
- return to
- }
- panic("cedar: internal error, should not be here")
- // return to
- }
- func (da *cedar) popBlock(bi int, headIn *int, last bool) {
- if last {
- *headIn = 0
- return
- }
- b := &da.Blocks[bi]
- da.Blocks[b.Prev].Next = b.Next
- da.Blocks[b.Next].Prev = b.Prev
- if bi == *headIn {
- *headIn = b.Next
- }
- }
- func (da *cedar) pushBlock(bi int, headOut *int, empty bool) {
- b := &da.Blocks[bi]
- if empty {
- *headOut, b.Prev, b.Next = bi, bi, bi
- } else {
- tailOut := &da.Blocks[*headOut].Prev
- b.Prev = *tailOut
- b.Next = *headOut
- *headOut, *tailOut, da.Blocks[*tailOut].Next = bi, bi, bi
- }
- }
- func (da *cedar) addBlock() int {
- if da.Size == da.Capacity {
- da.Capacity *= 2
- oldArray := da.Array
- da.Array = make([]node, da.Capacity)
- copy(da.Array, oldArray)
- oldNinfo := da.Ninfos
- da.Ninfos = make([]ninfo, da.Capacity)
- copy(da.Ninfos, oldNinfo)
- oldBlock := da.Blocks
- da.Blocks = make([]block, da.Capacity>>8)
- copy(da.Blocks, oldBlock)
- }
- da.Blocks[da.Size>>8].init()
- da.Blocks[da.Size>>8].Ehead = da.Size
- da.Array[da.Size] = node{-(da.Size + 255), -(da.Size + 1)}
- for i := da.Size + 1; i < da.Size+255; i++ {
- da.Array[i] = node{-(i - 1), -(i + 1)}
- }
- da.Array[da.Size+255] = node{-(da.Size + 254), -da.Size}
- da.pushBlock(da.Size>>8, &da.BheadO, da.BheadO == 0)
- da.Size += 256
- return da.Size>>8 - 1
- }
- func (da *cedar) transferBlock(bi int, headIn, headOut *int) {
- da.popBlock(bi, headIn, bi == da.Blocks[bi].Next)
- da.pushBlock(bi, headOut, *headOut == 0 && da.Blocks[bi].Num != 0)
- }
- func (da *cedar) popEnode(base int, label byte, from int) int {
- e := base ^ int(label)
- if base < 0 {
- e = da.findPlace()
- }
- bi := e >> 8
- n := &da.Array[e]
- b := &da.Blocks[bi]
- b.Num--
- if b.Num == 0 {
- if bi != 0 {
- da.transferBlock(bi, &da.BheadC, &da.BheadF)
- }
- } else {
- da.Array[-n.Value].Check = n.Check
- da.Array[-n.Check].Value = n.Value
- if e == b.Ehead {
- b.Ehead = -n.Check
- }
- if bi != 0 && b.Num == 1 && b.Trial != da.MaxTrial {
- da.transferBlock(bi, &da.BheadO, &da.BheadC)
- }
- }
- n.Value = ValueLimit
- n.Check = from
- if base < 0 {
- da.Array[from].Value = -(e ^ int(label)) - 1
- }
- return e
- }
- func (da *cedar) pushEnode(e int) {
- bi := e >> 8
- b := &da.Blocks[bi]
- b.Num++
- if b.Num == 1 {
- b.Ehead = e
- da.Array[e] = node{-e, -e}
- if bi != 0 {
- da.transferBlock(bi, &da.BheadF, &da.BheadC)
- }
- } else {
- prev := b.Ehead
- next := -da.Array[prev].Check
- da.Array[e] = node{-prev, -next}
- da.Array[prev].Check = -e
- da.Array[next].Value = -e
- if b.Num == 2 || b.Trial == da.MaxTrial {
- if bi != 0 {
- da.transferBlock(bi, &da.BheadC, &da.BheadO)
- }
- }
- b.Trial = 0
- }
- if b.Reject < da.Reject[b.Num] {
- b.Reject = da.Reject[b.Num]
- }
- da.Ninfos[e] = ninfo{}
- }
- // hasChild: wherether the `from` node has children
- func (da *cedar) pushSibling(from, base int, label byte, hasChild bool) {
- c := &da.Ninfos[from].Child
- keepOrder := *c == 0
- if da.Ordered {
- keepOrder = label > *c
- }
- if hasChild && keepOrder {
- c = &da.Ninfos[base^int(*c)].Sibling
- for da.Ordered && *c != 0 && *c < label {
- c = &da.Ninfos[base^int(*c)].Sibling
- }
- }
- da.Ninfos[base^int(label)].Sibling = *c
- *c = label
- }
- func (da *cedar) popSibling(from, base int, label byte) {
- c := &da.Ninfos[from].Child
- for *c != label {
- c = &da.Ninfos[base^int(*c)].Sibling
- }
- *c = da.Ninfos[base^int(*c)].Sibling
- }
- func (da *cedar) consult(baseN, baseP int, cN, cP byte) bool {
- cN = da.Ninfos[baseN^int(cN)].Sibling
- cP = da.Ninfos[baseP^int(cP)].Sibling
- for cN != 0 && cP != 0 {
- cN = da.Ninfos[baseN^int(cN)].Sibling
- cP = da.Ninfos[baseP^int(cP)].Sibling
- }
- return cP != 0
- }
- func (da *cedar) setChild(base int, c byte, label byte, flag bool) []byte {
- child := make([]byte, 0, 257)
- if c == 0 {
- child = append(child, c)
- c = da.Ninfos[base^int(c)].Sibling
- }
- if da.Ordered {
- for c != 0 && c <= label {
- child = append(child, c)
- c = da.Ninfos[base^int(c)].Sibling
- }
- }
- if flag {
- child = append(child, label)
- }
- for c != 0 {
- child = append(child, c)
- c = da.Ninfos[base^int(c)].Sibling
- }
- return child
- }
- func (da *cedar) findPlace() int {
- if da.BheadC != 0 {
- return da.Blocks[da.BheadC].Ehead
- }
- if da.BheadO != 0 {
- return da.Blocks[da.BheadO].Ehead
- }
- return da.addBlock() << 8
- }
- func (da *cedar) findPlaces(child []byte) int {
- bi := da.BheadO
- if bi != 0 {
- e := da.listBi(bi, child)
- if e > 0 {
- return e
- }
- }
- return da.addBlock() << 8
- }
- func (da *cedar) listBi(bi int, child []byte) int {
- nc := len(child)
- bz := da.Blocks[da.BheadO].Prev
- for {
- b := &da.Blocks[bi]
- if b.Num >= nc && nc < b.Reject {
- e := da.listEhead(b, child)
- if e > 0 {
- return e
- }
- }
- b.Reject = nc
- if b.Reject < da.Reject[b.Num] {
- da.Reject[b.Num] = b.Reject
- }
- biN := b.Next
- b.Trial++
- if b.Trial == da.MaxTrial {
- da.transferBlock(bi, &da.BheadO, &da.BheadC)
- }
- if bi == bz {
- break
- }
- bi = biN
- }
- return 0
- }
- func (da *cedar) listEhead(b *block, child []byte) int {
- for e := b.Ehead; ; {
- base := e ^ int(child[0])
- for i := 0; da.Array[base^int(child[i])].Check < 0; i++ {
- if i == len(child)-1 {
- b.Ehead = e
- // if e == 0 {
- // }
- return e
- }
- }
- e = -da.Array[e].Check
- if e == b.Ehead {
- break
- }
- }
- return 0
- }
- func (da *cedar) resolve(fromN, baseN int, labelN byte) int {
- toPn := baseN ^ int(labelN)
- fromP := da.Array[toPn].Check
- baseP := da.Array[fromP].base()
- flag := da.consult(baseN, baseP, da.Ninfos[fromN].Child, da.Ninfos[fromP].Child)
- var children []byte
- if flag {
- children = da.setChild(baseN, da.Ninfos[fromN].Child, labelN, true)
- } else {
- children = da.setChild(baseP, da.Ninfos[fromP].Child, 255, false)
- }
- var base int
- if len(children) == 1 {
- base = da.findPlace()
- } else {
- base = da.findPlaces(children)
- }
- base ^= int(children[0])
- var (
- from int
- nbase int
- )
- if flag {
- from = fromN
- nbase = baseN
- } else {
- from = fromP
- nbase = baseP
- }
- if flag && children[0] == labelN {
- da.Ninfos[from].Child = labelN
- }
- da.Array[from].Value = -base - 1
- base, labelN, toPn = da.list(base, from, nbase, fromN, toPn,
- labelN, children, flag)
- if flag {
- return base ^ int(labelN)
- }
- return toPn
- }
- func (da *cedar) list(base, from, nbase, fromN, toPn int,
- labelN byte, children []byte, flag bool) (int, byte, int) {
- for i := 0; i < len(children); i++ {
- to := da.popEnode(base, children[i], from)
- newTo := nbase ^ int(children[i])
- if i == len(children)-1 {
- da.Ninfos[to].Sibling = 0
- } else {
- da.Ninfos[to].Sibling = children[i+1]
- }
- if flag && newTo == toPn { // new node has no child
- continue
- }
- n := &da.Array[to]
- ns := &da.Array[newTo]
- n.Value = ns.Value
- if n.Value < 0 && children[i] != 0 {
- // this node has children, fix their check
- c := da.Ninfos[newTo].Child
- da.Ninfos[to].Child = c
- da.Array[n.base()^int(c)].Check = to
- c = da.Ninfos[n.base()^int(c)].Sibling
- for c != 0 {
- da.Array[n.base()^int(c)].Check = to
- c = da.Ninfos[n.base()^int(c)].Sibling
- }
- }
- if !flag && newTo == fromN { // parent node moved
- fromN = to
- }
- if !flag && newTo == toPn {
- da.pushSibling(fromN, toPn^int(labelN), labelN, true)
- da.Ninfos[newTo].Child = 0
- ns.Value = ValueLimit
- ns.Check = fromN
- } else {
- da.pushEnode(newTo)
- }
- }
- return base, labelN, toPn
- }
|