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  }