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  }