github.com/whatap/golib@v0.0.22/util/hmap/StringLinkedSet.go (about) 1 package hmap 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 "sync" 8 9 "github.com/whatap/golib/util/stringutil" 10 ) 11 12 // TODO SearchPathMap 에서 사용하기 위해 생성 (현재는 생성만) 13 // 테스트 필요. 14 type StringLinkedSet struct { 15 table []*StringLinkedSetry 16 header *StringLinkedSetry 17 count int 18 threshold int 19 loadFactor float32 20 lock sync.Mutex 21 max int 22 } 23 24 func NewStringLinkedSet() *StringLinkedSet { 25 26 initCapacity := DEFAULT_CAPACITY 27 loadFactor := DEFAULT_LOAD_FACTOR 28 29 this := new(StringLinkedSet) 30 this.loadFactor = float32(loadFactor) 31 this.table = make([]*StringLinkedSetry, initCapacity) 32 this.header = &StringLinkedSetry{} 33 this.header.link_next = this.header 34 this.header.link_prev = this.header 35 this.threshold = int(float64(initCapacity) * loadFactor) 36 return this 37 } 38 39 func (this *StringLinkedSet) Size() int { 40 return this.count 41 } 42 43 func (this *StringLinkedSet) GetArray() []string { 44 this.lock.Lock() 45 defer this.lock.Unlock() 46 47 _keys := make([]string, this.Size()) 48 en := this.Keys() 49 for i := 0; i < len(_keys); i++ { 50 _keys[i] = en.NextString() 51 } 52 return _keys 53 } 54 55 type StringEnumerSetImpl struct { 56 parent *StringLinkedSet 57 entry *StringLinkedSetry 58 rtype int 59 } 60 61 func (this *StringEnumerSetImpl) HasMoreElements() bool { 62 return this.entry != nil && this.parent.header != this.entry 63 } 64 65 func (this *StringEnumerSetImpl) NextString() string { 66 if this.HasMoreElements() { 67 e := this.entry 68 this.entry = e.link_next 69 return e.Get() 70 } 71 return "" 72 } 73 func (this *StringLinkedSet) Keys() StringEnumer { 74 return &StringEnumerSetImpl{parent: this, entry: this.header.link_next} 75 } 76 77 func (this *StringLinkedSet) Contains(key string) bool { 78 this.lock.Lock() 79 defer this.lock.Unlock() 80 if key == "" { 81 return false 82 } 83 84 tab := this.table 85 index := this.hash(key) % uint(len(tab)) 86 for e := tab[index]; e != nil; e = e.hash_next { 87 if e.key == key { 88 return true 89 } 90 } 91 return false 92 93 } 94 95 func (this *StringLinkedSet) GetFirst() string { 96 this.lock.Lock() 97 defer this.lock.Unlock() 98 99 return this.header.link_next.key 100 } 101 102 func (this *StringLinkedSet) GetLast() string { 103 this.lock.Lock() 104 defer this.lock.Unlock() 105 return this.header.link_prev.key 106 } 107 func (this *StringLinkedSet) hash(key string) uint { 108 return uint(stringutil.HashCode(key)) 109 } 110 111 func (this *StringLinkedSet) rehash() { 112 oldCapacity := len(this.table) 113 oldMap := this.table 114 newCapacity := oldCapacity*2 + 1 115 newMap := make([]*StringLinkedSetry, newCapacity) 116 this.threshold = int(float32(newCapacity) * this.loadFactor) 117 this.table = newMap 118 for i := oldCapacity; i > 0; i-- { 119 for old := oldMap[i-1]; old != nil; { 120 e := old 121 old = old.hash_next 122 index := uint(this.hash(e.key) % uint(newCapacity)) 123 e.hash_next = newMap[index] 124 newMap[index] = e 125 } 126 } 127 } 128 129 func (this *StringLinkedSet) SetMax(max int) *StringLinkedSet { 130 this.max = max 131 return this 132 } 133 func (this *StringLinkedSet) Put(key string) interface{} { 134 this.lock.Lock() 135 defer this.lock.Unlock() 136 return this.put(key, PUT_LAST) 137 } 138 func (this *StringLinkedSet) PutLast(key string) interface{} { 139 this.lock.Lock() 140 defer this.lock.Unlock() 141 return this.put(key, PUT_FORCE_LAST) 142 } 143 func (this *StringLinkedSet) PutFirst(key string) interface{} { 144 this.lock.Lock() 145 defer this.lock.Unlock() 146 return this.put(key, PUT_FORCE_FIRST) 147 } 148 func (this *StringLinkedSet) put(key string, m PUT_MODE) interface{} { 149 tab := this.table 150 keyHash := this.hash(key) 151 index := keyHash % uint(len(tab)) 152 for e := tab[index]; e != nil; e = e.hash_next { 153 if e.key == key { 154 switch m { 155 case PUT_FORCE_FIRST: 156 if this.header.link_next != e { 157 this.unchain(e) 158 this.chain(this.header, this.header.link_next, e) 159 } 160 case PUT_FORCE_LAST: 161 if this.header.link_prev != e { 162 this.unchain(e) 163 this.chain(this.header.link_prev, this.header, e) 164 } 165 } 166 return key 167 } 168 } 169 if this.max > 0 { 170 switch m { 171 case PUT_FORCE_FIRST, PUT_FIRST: 172 for this.count >= this.max { 173 k := this.header.link_prev.key 174 this.remove(k) 175 } 176 case PUT_FORCE_LAST, PUT_LAST: 177 for this.count >= this.max { 178 k := this.header.link_next.key 179 this.remove(k) 180 } 181 break 182 } 183 } 184 if this.count >= this.threshold { 185 this.rehash() 186 tab = this.table 187 index = keyHash % uint(len(tab)) 188 } 189 e := &StringLinkedSetry{key: key, hash_next: tab[index]} 190 tab[index] = e 191 switch m { 192 case PUT_FORCE_FIRST, PUT_FIRST: 193 this.chain(this.header, this.header.link_next, e) 194 case PUT_FORCE_LAST, PUT_LAST: 195 this.chain(this.header.link_prev, this.header, e) 196 } 197 this.count++ 198 return nil 199 } 200 201 func (this *StringLinkedSet) Unipoint(key string) string { 202 old := this.put(key, PUT_LAST) 203 if old == nil { 204 return key 205 } else { 206 return old.(string) 207 } 208 } 209 210 func (this *StringLinkedSet) Remove(key string) interface{} { 211 this.lock.Lock() 212 defer this.lock.Unlock() 213 214 return this.remove(key) 215 } 216 func (this *StringLinkedSet) RemoveFirst() interface{} { 217 if this.IsEmpty() { 218 return 0 219 } 220 this.lock.Lock() 221 defer this.lock.Unlock() 222 return this.remove(this.header.link_next.key) 223 } 224 225 func (this *StringLinkedSet) RemoveLast() interface{} { 226 if this.IsEmpty() { 227 return 0 228 } 229 this.lock.Lock() 230 defer this.lock.Unlock() 231 return this.remove(this.header.link_prev.key) 232 } 233 234 func (this *StringLinkedSet) remove(key string) interface{} { 235 236 tab := this.table 237 index := this.hash(key) % uint(len(tab)) 238 e := tab[index] 239 var prev *StringLinkedSetry = nil 240 for e != nil { 241 if e.key == key { 242 if prev != nil { 243 prev.hash_next = e.hash_next 244 } else { 245 tab[index] = e.hash_next 246 } 247 this.count-- 248 // 249 this.unchain(e) 250 return key 251 } 252 prev = e 253 e = e.hash_next 254 } 255 return nil 256 } 257 258 func (this *StringLinkedSet) IsEmpty() bool { 259 return this.count == 0 260 } 261 func (this *StringLinkedSet) IsFull() bool { 262 return this.max > 0 && this.max <= this.count 263 } 264 265 func (this *StringLinkedSet) Clear() { 266 this.lock.Lock() 267 defer this.lock.Unlock() 268 this.clear() 269 } 270 func (this *StringLinkedSet) clear() { 271 tab := this.table 272 for index := len(tab) - 1; index >= 0; index-- { 273 tab[index] = nil 274 } 275 this.header.link_next = this.header 276 this.header.link_prev = this.header 277 this.count = 0 278 } 279 280 func (this *StringLinkedSet) chain(link_prev *StringLinkedSetry, link_next *StringLinkedSetry, e *StringLinkedSetry) { 281 e.link_prev = link_prev 282 e.link_next = link_next 283 link_prev.link_next = e 284 link_next.link_prev = e 285 } 286 287 func (this *StringLinkedSet) unchain(e *StringLinkedSetry) { 288 e.link_prev.link_next = e.link_next 289 e.link_next.link_prev = e.link_prev 290 e.link_prev = nil 291 e.link_next = nil 292 } 293 294 func (this *StringLinkedSet) ToString() string { 295 this.lock.Lock() 296 defer this.lock.Unlock() 297 298 var buffer bytes.Buffer 299 x := this.Keys() 300 buffer.WriteString("{") 301 for i := 0; x.HasMoreElements(); i++ { 302 if i > 0 { 303 buffer.WriteString(", ") 304 } 305 e := x.NextString() 306 buffer.WriteString(e) 307 } 308 buffer.WriteString("}") 309 return buffer.String() 310 } 311 312 type StringLinkedSortable struct { 313 compare func(a, b string) bool 314 data []string 315 } 316 317 func (this StringLinkedSortable) Swap(i, j int) { 318 this.data[i], this.data[j] = this.data[j], this.data[i] 319 } 320 func (this StringLinkedSortable) Len() int { 321 return len(this.data) 322 } 323 func (this StringLinkedSortable) Less(i, j int) bool { 324 return this.compare(this.data[i], this.data[j]) 325 } 326 327 func (this *StringLinkedSet) Sort(c func(k1, k2 string) bool) { 328 this.lock.Lock() 329 defer this.lock.Unlock() 330 331 sz := this.Size() 332 list := make([]string, sz) 333 en := this.Keys() 334 for i := 0; i < sz; i++ { 335 list[i] = en.NextString() 336 } 337 sort.Sort(StringLinkedSortable{compare: c, data: list}) 338 339 this.clear() 340 for i := 0; i < sz; i++ { 341 this.put(list[i], PUT_LAST) 342 } 343 } 344 345 func StringLinkedSetMain() { 346 s := NewStringLinkedSet() 347 s.Put("aa") 348 s.Put("bb") 349 s.Put("00") 350 // s.Sort(c func(k1, k2 string) bool) 351 fmt.Println(s) 352 // s.Sort(false) 353 fmt.Println(s) 354 }