github.com/metacubex/mihomo@v1.18.5/component/trie/domain_set.go (about)

     1  package trie
     2  
     3  // Package succinct provides several succinct data types.
     4  // Modify from https://github.com/openacid/succinct/blob/d4684c35d123f7528b14e03c24327231723db704/sskv.go
     5  
     6  import (
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/metacubex/mihomo/common/utils"
    11  	"github.com/openacid/low/bitmap"
    12  )
    13  
    14  const (
    15  	complexWildcardByte = byte('+')
    16  	wildcardByte        = byte('*')
    17  	domainStepByte      = byte('.')
    18  )
    19  
    20  type DomainSet struct {
    21  	leaves, labelBitmap []uint64
    22  	labels              []byte
    23  	ranks, selects      []int32
    24  }
    25  
    26  type qElt struct{ s, e, col int }
    27  
    28  // NewDomainSet creates a new *DomainSet struct, from a DomainTrie.
    29  func (t *DomainTrie[T]) NewDomainSet() *DomainSet {
    30  	reserveDomains := make([]string, 0)
    31  	t.Foreach(func(domain string, data T) {
    32  		reserveDomains = append(reserveDomains, utils.Reverse(domain))
    33  	})
    34  	// ensure that the same prefix is continuous
    35  	// and according to the ascending sequence of length
    36  	sort.Strings(reserveDomains)
    37  	keys := reserveDomains
    38  	if len(keys) == 0 {
    39  		return nil
    40  	}
    41  	ss := &DomainSet{}
    42  	lIdx := 0
    43  
    44  	queue := []qElt{{0, len(keys), 0}}
    45  	for i := 0; i < len(queue); i++ {
    46  		elt := queue[i]
    47  		if elt.col == len(keys[elt.s]) {
    48  			elt.s++
    49  			// a leaf node
    50  			setBit(&ss.leaves, i, 1)
    51  		}
    52  
    53  		for j := elt.s; j < elt.e; {
    54  
    55  			frm := j
    56  
    57  			for ; j < elt.e && keys[j][elt.col] == keys[frm][elt.col]; j++ {
    58  			}
    59  			queue = append(queue, qElt{frm, j, elt.col + 1})
    60  			ss.labels = append(ss.labels, keys[frm][elt.col])
    61  			setBit(&ss.labelBitmap, lIdx, 0)
    62  			lIdx++
    63  		}
    64  		setBit(&ss.labelBitmap, lIdx, 1)
    65  		lIdx++
    66  	}
    67  
    68  	ss.init()
    69  	return ss
    70  }
    71  
    72  // Has query for a key and return whether it presents in the DomainSet.
    73  func (ss *DomainSet) Has(key string) bool {
    74  	if ss == nil {
    75  		return false
    76  	}
    77  	key = utils.Reverse(key)
    78  	key = strings.ToLower(key)
    79  	// no more labels in this node
    80  	// skip character matching
    81  	// go to next level
    82  	nodeId, bmIdx := 0, 0
    83  	type wildcardCursor struct {
    84  		bmIdx, index int
    85  	}
    86  	stack := make([]wildcardCursor, 0)
    87  	for i := 0; i < len(key); i++ {
    88  	RESTART:
    89  		c := key[i]
    90  		for ; ; bmIdx++ {
    91  			if getBit(ss.labelBitmap, bmIdx) != 0 {
    92  				if len(stack) > 0 {
    93  					cursor := stack[len(stack)-1]
    94  					stack = stack[0 : len(stack)-1]
    95  					// back wildcard and find next node
    96  					nextNodeId := countZeros(ss.labelBitmap, ss.ranks, cursor.bmIdx+1)
    97  					nextBmIdx := selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nextNodeId-1) + 1
    98  					j := cursor.index
    99  					for ; j < len(key) && key[j] != domainStepByte; j++ {
   100  					}
   101  					if j == len(key) {
   102  						if getBit(ss.leaves, nextNodeId) != 0 {
   103  							return true
   104  						} else {
   105  							goto RESTART
   106  						}
   107  					}
   108  					for ; nextBmIdx-nextNodeId < len(ss.labels); nextBmIdx++ {
   109  						if ss.labels[nextBmIdx-nextNodeId] == domainStepByte {
   110  							bmIdx = nextBmIdx
   111  							nodeId = nextNodeId
   112  							i = j
   113  							goto RESTART
   114  						}
   115  					}
   116  				}
   117  				return false
   118  			}
   119  			// handle wildcard for domain
   120  			if ss.labels[bmIdx-nodeId] == complexWildcardByte {
   121  				return true
   122  			} else if ss.labels[bmIdx-nodeId] == wildcardByte {
   123  				cursor := wildcardCursor{}
   124  				cursor.bmIdx = bmIdx
   125  				cursor.index = i
   126  				stack = append(stack, cursor)
   127  			} else if ss.labels[bmIdx-nodeId] == c {
   128  				break
   129  			}
   130  		}
   131  		nodeId = countZeros(ss.labelBitmap, ss.ranks, bmIdx+1)
   132  		bmIdx = selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nodeId-1) + 1
   133  	}
   134  
   135  	return getBit(ss.leaves, nodeId) != 0
   136  
   137  }
   138  
   139  func setBit(bm *[]uint64, i int, v int) {
   140  	for i>>6 >= len(*bm) {
   141  		*bm = append(*bm, 0)
   142  	}
   143  	(*bm)[i>>6] |= uint64(v) << uint(i&63)
   144  }
   145  
   146  func getBit(bm []uint64, i int) uint64 {
   147  	return bm[i>>6] & (1 << uint(i&63))
   148  }
   149  
   150  // init builds pre-calculated cache to speed up rank() and select()
   151  func (ss *DomainSet) init() {
   152  	ss.selects, ss.ranks = bitmap.IndexSelect32R64(ss.labelBitmap)
   153  }
   154  
   155  // countZeros counts the number of "0" in a bitmap before the i-th bit(excluding
   156  // the i-th bit) on behalf of rank index.
   157  // E.g.:
   158  //
   159  //	countZeros("010010", 4) == 3
   160  //	//          012345
   161  func countZeros(bm []uint64, ranks []int32, i int) int {
   162  	a, _ := bitmap.Rank64(bm, ranks, int32(i))
   163  	return i - int(a)
   164  }
   165  
   166  // selectIthOne returns the index of the i-th "1" in a bitmap, on behalf of rank
   167  // and select indexes.
   168  // E.g.:
   169  //
   170  //	selectIthOne("010010", 1) == 4
   171  //	//            012345
   172  func selectIthOne(bm []uint64, ranks, selects []int32, i int) int {
   173  	a, _ := bitmap.Select32R64(bm, selects, ranks, int32(i))
   174  	return int(a)
   175  }