github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/util/automaton/sortedIntSet.go (about) 1 package automaton 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 "strconv" 8 ) 9 10 // util/automaton/SortedIntSet.java 11 12 // If we hold more than this many states, we swtich from O(N*2) 13 // linear ops to O(N log(N)) TreeMap 14 const TREE_MAP_CUTOVER = 30 15 16 /* 17 Just holds a set of []int states, plus a corresponding []int count 18 per state. Used by determinize(). 19 20 I have to disable hashCode and use string key to mimic Lucene's 21 custom hashing function here. 22 */ 23 type SortedIntSet struct { 24 values []int 25 counts []int 26 // hashCode int 27 dict map[int]int // keys need sort 28 useTreeMap bool 29 state int 30 } 31 32 func newSortedIntSet(capacity int) *SortedIntSet { 33 return &SortedIntSet{ 34 values: make([]int, 0, capacity), 35 counts: make([]int, 0, capacity), 36 } 37 } 38 39 // Adds this state ot the set 40 func (sis *SortedIntSet) incr(num int) { 41 if sis.useTreeMap { 42 val, ok := sis.dict[num] 43 if !ok { 44 sis.dict[num] = 1 45 } else { 46 sis.dict[num] = 1 + val 47 } 48 return 49 } 50 51 for i, v := range sis.values { 52 if v == num { 53 sis.counts[i]++ 54 return 55 } else if num < v { 56 // insert here 57 sis.values = append(sis.values[:i], append([]int{num}, sis.values[i:]...)...) 58 sis.counts = append(sis.counts[:i], append([]int{1}, sis.counts[i:]...)...) 59 return 60 } 61 } 62 63 // append 64 sis.values = append(sis.values, num) 65 sis.counts = append(sis.counts, 1) 66 67 if len(sis.values) == TREE_MAP_CUTOVER { 68 sis.useTreeMap = true 69 for i, v := range sis.values { 70 sis.dict[v] = sis.counts[i] 71 } 72 } 73 } 74 75 // Removes the state from the set, if count decrs to 0 76 func (sis *SortedIntSet) decr(num int) { 77 if sis.useTreeMap { 78 count, ok := sis.dict[num] 79 assert(ok) 80 if count == 1 { 81 delete(sis.dict, num) 82 // Fall back to simple arrays once we touch zero again 83 if len(sis.dict) == 0 { 84 sis.useTreeMap = false 85 sis.values = sis.values[:0] // reuse slice 86 sis.counts = sis.counts[:0] // reuse slice 87 } 88 } else { 89 sis.dict[num] = count - 1 90 } 91 return 92 } 93 94 for i, v := range sis.values { 95 if v == num { 96 sis.counts[i]-- 97 if sis.counts[i] == 0 { 98 limit := len(sis.values) - 1 99 if i < limit { 100 sis.values = append(sis.values[:i], sis.values[i+1:]...) 101 sis.counts = append(sis.counts[:i], sis.counts[i+1:]...) 102 } else { 103 sis.values = sis.values[:i] 104 sis.counts = sis.counts[:i] 105 } 106 } 107 return 108 } 109 } 110 111 panic("should not be here!") 112 } 113 114 func (sis *SortedIntSet) computeHash() *FrozenIntSet { 115 // do nothing related to hash 116 if sis.useTreeMap { 117 if size := len(sis.dict); size > len(sis.values) { 118 sis.values = make([]int, 0, size) 119 sis.counts = make([]int, 0, size) 120 } 121 for state, _ := range sis.dict { 122 sis.values = append(sis.values, state) 123 } 124 sort.Ints(sis.values) // keys in map are not sorted 125 } else { 126 // do nothing 127 } 128 return sis.freeze(sis.state) 129 } 130 131 func (sis *SortedIntSet) freeze(state int) *FrozenIntSet { 132 c := make([]int, len(sis.values)) 133 copy(c, sis.values) 134 return newFrozenIntSet(c, state) 135 } 136 137 func (sis *SortedIntSet) String() string { 138 var b bytes.Buffer 139 b.WriteRune('[') 140 for i, v := range sis.values { 141 if i > 0 { 142 b.WriteRune(' ') 143 } 144 fmt.Fprintf(&b, "%v:%v", v, sis.counts[i]) 145 } 146 b.WriteRune(']') 147 return b.String() 148 } 149 150 type FrozenIntSet struct { 151 values []int 152 state int 153 } 154 155 func newFrozenIntSet(values []int, state int) *FrozenIntSet { 156 return &FrozenIntSet{values, state} 157 } 158 159 func newFrozenIntSetOf(num, state int) *FrozenIntSet { 160 return &FrozenIntSet{ 161 values: []int{num}, 162 state: state, 163 } 164 } 165 166 func (fis *FrozenIntSet) String() string { 167 var b bytes.Buffer 168 b.WriteRune('[') 169 for i, v := range fis.values { 170 if i > 0 { 171 b.WriteRune(' ') 172 } 173 b.WriteString(strconv.Itoa(v)) 174 } 175 b.WriteRune(']') 176 return b.String() 177 }