github.com/whatap/golib@v0.0.22/util/hmap/StringIntLinkedMap.go (about)

     1  package hmap
     2  
     3  import (
     4  	"bytes"
     5  	"sort"
     6  	"sync"
     7  
     8  	"github.com/whatap/golib/util/hash"
     9  )
    10  
    11  type StringIntLinkedMap struct {
    12  	table      []*StringIntLinkedEntry
    13  	header     *StringIntLinkedEntry
    14  	count      int
    15  	threshold  int
    16  	loadFactor float32
    17  	lock       sync.Mutex
    18  	max        int
    19  	NONE       int32
    20  }
    21  
    22  func NewStringIntLinkedMap() *StringIntLinkedMap {
    23  
    24  	initCapacity := DEFAULT_CAPACITY
    25  	loadFactor := DEFAULT_LOAD_FACTOR
    26  
    27  	this := new(StringIntLinkedMap)
    28  	this.loadFactor = float32(loadFactor)
    29  	this.table = make([]*StringIntLinkedEntry, initCapacity)
    30  	this.header = &StringIntLinkedEntry{}
    31  	this.header.link_next = this.header
    32  	this.header.link_prev = this.header
    33  	this.threshold = int(float64(initCapacity) * loadFactor)
    34  
    35  	this.NONE = 0
    36  
    37  	return this
    38  }
    39  
    40  func (this *StringIntLinkedMap) SetNullValue(none int32) *StringIntLinkedMap {
    41  	this.NONE = none
    42  	return this
    43  }
    44  
    45  func (this *StringIntLinkedMap) Size() int {
    46  	return this.count
    47  }
    48  
    49  func (this *StringIntLinkedMap) KeyArray() []string {
    50  	this.lock.Lock()
    51  	defer this.lock.Unlock()
    52  
    53  	_keys := make([]string, this.Size())
    54  	en := this.Keys()
    55  	for i := 0; i < len(_keys); i++ {
    56  		_keys[i] = en.NextString()
    57  	}
    58  	return _keys
    59  }
    60  
    61  func (this *StringIntLinkedMap) Keys() StringEnumer {
    62  	return &StringIntLinkedEnumer{parent: this, entry: this.header.link_next}
    63  }
    64  func (this *StringIntLinkedMap) Values() Enumeration {
    65  	return &StringIntLinkedEnumer{parent: this, entry: this.header.link_next, isEntry: false}
    66  }
    67  func (this *StringIntLinkedMap) Entries() Enumeration {
    68  	return &StringIntLinkedEnumer{parent: this, entry: this.header.link_next, isEntry: true}
    69  }
    70  
    71  func (this *StringIntLinkedMap) ContainsValue(value int32) bool {
    72  	this.lock.Lock()
    73  	defer this.lock.Unlock()
    74  
    75  	tab := this.table
    76  
    77  	for i := len(tab) - 1; i > 0; i-- {
    78  		for e := tab[i]; e != nil; e = e.hash_next {
    79  			if e.value == value {
    80  				return true
    81  			}
    82  		}
    83  	}
    84  	return false
    85  }
    86  
    87  func (this *StringIntLinkedMap) ContainsKey(key string) bool {
    88  	this.lock.Lock()
    89  	defer this.lock.Unlock()
    90  
    91  	tab := this.table
    92  	index := this.hash(key) % uint(len(tab))
    93  	for e := tab[index]; e != nil; e = e.hash_next {
    94  		if e.key == key {
    95  			return true
    96  		}
    97  	}
    98  	return false
    99  
   100  }
   101  func (this *StringIntLinkedMap) Get(key string) int32 {
   102  	this.lock.Lock()
   103  	defer this.lock.Unlock()
   104  
   105  	tab := this.table
   106  	index := this.hash(key) % uint(len(tab))
   107  	for e := tab[index]; e != nil; e = e.hash_next {
   108  		if e.key == key {
   109  			return e.value
   110  		}
   111  	}
   112  	return this.NONE
   113  }
   114  
   115  func (this *StringIntLinkedMap) GetFirstKey() string {
   116  	this.lock.Lock()
   117  	defer this.lock.Unlock()
   118  
   119  	return this.header.link_next.key
   120  }
   121  
   122  func (this *StringIntLinkedMap) GetLastKey() string {
   123  	this.lock.Lock()
   124  	defer this.lock.Unlock()
   125  	return this.header.link_prev.key
   126  }
   127  
   128  func (this *StringIntLinkedMap) GetFirstValue() interface{} {
   129  	this.lock.Lock()
   130  	defer this.lock.Unlock()
   131  
   132  	if this.IsEmpty() {
   133  		return this.NONE
   134  	}
   135  
   136  	return this.header.link_next.value
   137  }
   138  
   139  func (this *StringIntLinkedMap) GetLastValue() interface{} {
   140  	this.lock.Lock()
   141  	defer this.lock.Unlock()
   142  
   143  	if this.IsEmpty() {
   144  		return this.NONE
   145  	}
   146  
   147  	return this.header.link_prev.value
   148  }
   149  func (this *StringIntLinkedMap) hash(key string) uint {
   150  	return uint(hash.HashStr(key))
   151  }
   152  
   153  func (this *StringIntLinkedMap) rehash() {
   154  	oldCapacity := len(this.table)
   155  	oldMap := this.table
   156  	newCapacity := oldCapacity*2 + 1
   157  	newMap := make([]*StringIntLinkedEntry, newCapacity)
   158  	this.threshold = int(float32(newCapacity) * this.loadFactor)
   159  	this.table = newMap
   160  	for i := oldCapacity; i > 0; i-- {
   161  		for old := oldMap[i-1]; old != nil; {
   162  			e := old
   163  			old = old.hash_next
   164  			index := uint(e.keyHash % uint(newCapacity))
   165  			e.hash_next = newMap[index]
   166  			newMap[index] = e
   167  		}
   168  	}
   169  }
   170  
   171  func (this *StringIntLinkedMap) SetMax(max int) *StringIntLinkedMap {
   172  	this.max = max
   173  	return this
   174  }
   175  func (this *StringIntLinkedMap) Put(key string, value int32) int32 {
   176  	this.lock.Lock()
   177  	defer this.lock.Unlock()
   178  	return this.put(key, value, PUT_LAST)
   179  }
   180  func (this *StringIntLinkedMap) PutLast(key string, value int32) int32 {
   181  	this.lock.Lock()
   182  	defer this.lock.Unlock()
   183  	return this.put(key, value, PUT_FORCE_LAST)
   184  }
   185  func (this *StringIntLinkedMap) PutFirst(key string, value int32) int32 {
   186  	this.lock.Lock()
   187  	defer this.lock.Unlock()
   188  	return this.put(key, value, PUT_FORCE_FIRST)
   189  }
   190  func (this *StringIntLinkedMap) put(key string, value int32, m PUT_MODE) int32 {
   191  	if key == "" {
   192  		return this.NONE
   193  	}
   194  
   195  	tab := this.table
   196  	keyHash := this.hash(key)
   197  	index := keyHash % uint(len(tab))
   198  	for e := tab[index]; e != nil; e = e.hash_next {
   199  		if e.key == key {
   200  			old := e.value
   201  			e.value = value
   202  			switch m {
   203  			case PUT_FORCE_FIRST:
   204  				if this.header.link_next != e {
   205  					this.unchain(e)
   206  					this.chain(this.header, this.header.link_next, e)
   207  				}
   208  			case PUT_FORCE_LAST:
   209  				if this.header.link_prev != e {
   210  					this.unchain(e)
   211  					this.chain(this.header.link_prev, this.header, e)
   212  				}
   213  			}
   214  			return old
   215  		}
   216  	}
   217  	if this.max > 0 {
   218  		switch m {
   219  		case PUT_FORCE_FIRST, PUT_FIRST:
   220  			for this.count >= this.max {
   221  				k := this.header.link_prev.key
   222  				this.remove(k)
   223  			}
   224  		case PUT_FORCE_LAST, PUT_LAST:
   225  			for this.count >= this.max {
   226  				// removeFirst();
   227  				k := this.header.link_next.key
   228  				this.remove(k)
   229  			}
   230  			break
   231  		}
   232  	}
   233  	if this.count >= this.threshold {
   234  		this.rehash()
   235  		tab = this.table
   236  		index = keyHash % uint(len(tab))
   237  	}
   238  	e := &StringIntLinkedEntry{key: key, keyHash: keyHash, value: value, hash_next: tab[index]}
   239  	tab[index] = e
   240  	switch m {
   241  	case PUT_FORCE_FIRST, PUT_FIRST:
   242  		this.chain(this.header, this.header.link_next, e)
   243  	case PUT_FORCE_LAST, PUT_LAST:
   244  		this.chain(this.header.link_prev, this.header, e)
   245  	}
   246  	this.count++
   247  	return this.NONE
   248  }
   249  
   250  func (this *StringIntLinkedMap) Add(key string, value int32) int32 {
   251  	return this._add(key, value, PUT_LAST)
   252  }
   253  
   254  func (this *StringIntLinkedMap) AddLast(key string, value int32) int32 {
   255  	return this._add(key, value, PUT_FORCE_LAST)
   256  }
   257  
   258  func (this *StringIntLinkedMap) AddFirst(key string, value int32) int32 {
   259  	return this._add(key, value, PUT_FORCE_FIRST)
   260  }
   261  func (this *StringIntLinkedMap) _add(key string, value int32, m PUT_MODE) int32 {
   262  	this.lock.Lock()
   263  	defer this.lock.Unlock()
   264  
   265  	if key == "" {
   266  		return this.NONE
   267  	}
   268  
   269  	tab := this.table
   270  	keyHash := this.hash(key)
   271  	index := keyHash % uint(len(tab))
   272  	for e := tab[index]; e != nil; e = e.hash_next {
   273  		if e.key == key {
   274  			old := e.value
   275  			e.value = value
   276  			switch m {
   277  			case PUT_FORCE_FIRST:
   278  				if this.header.link_next != e {
   279  					this.unchain(e)
   280  					this.chain(this.header, this.header.link_next, e)
   281  				}
   282  			case PUT_FORCE_LAST:
   283  				if this.header.link_prev != e {
   284  					this.unchain(e)
   285  					this.chain(this.header.link_prev, this.header, e)
   286  				}
   287  			}
   288  			return old
   289  		}
   290  	}
   291  	if this.max > 0 {
   292  		switch m {
   293  		case PUT_FORCE_FIRST, PUT_FIRST:
   294  			for this.count >= this.max {
   295  				k := this.header.link_prev.key
   296  				this.remove(k)
   297  			}
   298  		case PUT_FORCE_LAST, PUT_LAST:
   299  			for this.count >= this.max {
   300  				// removeFirst();
   301  				k := this.header.link_next.key
   302  				this.remove(k)
   303  			}
   304  			break
   305  		}
   306  	}
   307  	if this.count >= this.threshold {
   308  		this.rehash()
   309  		tab = this.table
   310  		index = keyHash % uint(len(tab))
   311  	}
   312  	e := &StringIntLinkedEntry{key: key, keyHash: keyHash, value: value, hash_next: tab[index]}
   313  	tab[index] = e
   314  	switch m {
   315  	case PUT_FORCE_FIRST, PUT_FIRST:
   316  		this.chain(this.header, this.header.link_next, e)
   317  	case PUT_FORCE_LAST, PUT_LAST:
   318  		this.chain(this.header.link_prev, this.header, e)
   319  	}
   320  	this.count++
   321  
   322  	return this.NONE
   323  }
   324  
   325  func (this *StringIntLinkedMap) Remove(key string) interface{} {
   326  	this.lock.Lock()
   327  	defer this.lock.Unlock()
   328  
   329  	return this.remove(key)
   330  }
   331  func (this *StringIntLinkedMap) RemoveFirst() interface{} {
   332  	if this.IsEmpty() {
   333  		return this.NONE
   334  	}
   335  	this.lock.Lock()
   336  	defer this.lock.Unlock()
   337  	return this.remove(this.header.link_next.key)
   338  }
   339  
   340  func (this *StringIntLinkedMap) RemoveLast() interface{} {
   341  	if this.IsEmpty() {
   342  		return this.NONE
   343  	}
   344  	this.lock.Lock()
   345  	defer this.lock.Unlock()
   346  	return this.remove(this.header.link_prev.key)
   347  }
   348  
   349  func (this *StringIntLinkedMap) remove(key string) interface{} {
   350  
   351  	tab := this.table
   352  	index := this.hash(key) % uint(len(tab))
   353  	e := tab[index]
   354  	var prev *StringIntLinkedEntry = nil
   355  	for e != nil {
   356  		if e.key == key {
   357  			if prev != nil {
   358  				prev.hash_next = e.hash_next
   359  			} else {
   360  				tab[index] = e.hash_next
   361  			}
   362  			this.count--
   363  			oldValue := e.value
   364  			e.value = this.NONE
   365  			//
   366  			this.unchain(e)
   367  			return oldValue
   368  		}
   369  		prev = e
   370  		e = e.hash_next
   371  	}
   372  	return this.NONE
   373  }
   374  
   375  func (this *StringIntLinkedMap) IsEmpty() bool {
   376  	return this.count == 0
   377  }
   378  func (this *StringIntLinkedMap) IsFull() bool {
   379  	return this.max > 0 && this.max <= this.count
   380  }
   381  
   382  func (this *StringIntLinkedMap) Clear() {
   383  	this.lock.Lock()
   384  	defer this.lock.Unlock()
   385  	this.clear()
   386  }
   387  func (this *StringIntLinkedMap) clear() {
   388  	tab := this.table
   389  	for index := len(tab) - 1; index >= 0; index-- {
   390  		tab[index] = nil
   391  	}
   392  	this.header.link_next = this.header
   393  	this.header.link_prev = this.header
   394  	this.count = 0
   395  }
   396  
   397  func (this *StringIntLinkedMap) chain(link_prev *StringIntLinkedEntry, link_next *StringIntLinkedEntry, e *StringIntLinkedEntry) {
   398  	e.link_prev = link_prev
   399  	e.link_next = link_next
   400  	link_prev.link_next = e
   401  	link_next.link_prev = e
   402  }
   403  
   404  func (this *StringIntLinkedMap) unchain(e *StringIntLinkedEntry) {
   405  	e.link_prev.link_next = e.link_next
   406  	e.link_next.link_prev = e.link_prev
   407  	e.link_prev = nil
   408  	e.link_next = nil
   409  }
   410  
   411  type StringIntSortable struct {
   412  	compare func(a, b string) bool
   413  	data    []*StringIntLinkedEntry
   414  }
   415  
   416  func (this StringIntSortable) Len() int {
   417  	return len(this.data)
   418  }
   419  func (this StringIntSortable) Less(i, j int) bool {
   420  	return this.compare(this.data[i].GetKey(), this.data[j].GetKey())
   421  }
   422  
   423  func (this StringIntSortable) Swap(i, j int) {
   424  	this.data[i], this.data[j] = this.data[j], this.data[i]
   425  }
   426  
   427  func (this *StringIntLinkedMap) Sort(c func(k1, k2 string) bool) {
   428  	this.lock.Lock()
   429  	defer this.lock.Unlock()
   430  
   431  	sz := this.Size()
   432  	list := make([]*StringIntLinkedEntry, sz)
   433  	en := this.Entries()
   434  	for i := 0; i < sz; i++ {
   435  		list[i] = en.NextElement().(*StringIntLinkedEntry)
   436  	}
   437  	sort.Sort(StringIntSortable{compare: c, data: list})
   438  
   439  	this.clear()
   440  	for i := 0; i < sz; i++ {
   441  		this.put(list[i].GetKey(), list[i].GetValue(), PUT_LAST)
   442  	}
   443  }
   444  
   445  func (this *StringIntLinkedMap) ToString() string {
   446  	this.lock.Lock()
   447  	defer this.lock.Unlock()
   448  
   449  	var buffer bytes.Buffer
   450  	x := this.Entries()
   451  	buffer.WriteString("{")
   452  	for i := 0; x.HasMoreElements(); i++ {
   453  		if i > 0 {
   454  			buffer.WriteString(", ")
   455  		}
   456  		e := x.NextElement().(*StringIntLinkedEntry)
   457  		buffer.WriteString(e.ToString())
   458  	}
   459  	buffer.WriteString("}")
   460  	return buffer.String()
   461  }
   462  
   463  type StringIntLinkedEnumer struct {
   464  	parent  *StringIntLinkedMap
   465  	entry   *StringIntLinkedEntry
   466  	isEntry bool
   467  	Type    int
   468  }
   469  
   470  func NewStringIntLinkedEnumer(parent *StringIntLinkedMap, entry *StringIntLinkedEntry, Type int) *StringIntLinkedEnumer {
   471  	p := new(StringIntLinkedEnumer)
   472  	p.parent = parent
   473  	p.entry = entry
   474  	p.Type = Type
   475  
   476  	return p
   477  }
   478  func (this *StringIntLinkedEnumer) HasMoreElements() bool {
   479  	return this.entry != nil && this.parent.header != this.entry
   480  }
   481  func (this *StringIntLinkedEnumer) NextElement() interface{} {
   482  	if this.HasMoreElements() {
   483  		e := this.entry
   484  		this.entry = e.link_next
   485  
   486  		switch this.Type {
   487  		case ELEMENT_TYPE_KEYS:
   488  			return e.key
   489  		case ELEMENT_TYPE_VALUES:
   490  			return e.value
   491  		default:
   492  			return e
   493  		}
   494  	}
   495  	return nil
   496  }
   497  
   498  func (this *StringIntLinkedEnumer) NextInt() int32 {
   499  	if this.HasMoreElements() {
   500  		e := this.entry
   501  		this.entry = e.link_next
   502  		return e.value
   503  	}
   504  	return 0
   505  }
   506  
   507  func (this *StringIntLinkedEnumer) NextString() string {
   508  	if this.HasMoreElements() {
   509  		e := this.entry
   510  		this.entry = e.link_next
   511  		return e.key
   512  	}
   513  	return ""
   514  }