goProject/.svn/pristine/2a/2a53f94905747f4fa5f73ac48126d3788f20ea2b.svn-base
2025-01-06 16:21:36 +08:00

344 lines
6.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rank_util
import (
"sync"
)
// RankUtil
// @description:排行工具类
type RankUtil struct {
// maxCount 排行榜最大数量
maxCount int
// compar 对比函数 返回含义 -1:a<b 0:a=b 1:a>b
compar func(a, b interface{}) int
// dataList 排行数据
dataList []*Model
// dataDict 数据字典
dataDict map[string]*Model
// dataLock 数据锁
dataLock sync.RWMutex
}
// NewRankUtil
// @description: 构造排行对象
// parameter:
// @mc:最大容量
// @comp:元素比对方法
// return:
func NewRankUtil(mc int, comp func(a, b interface{}) int) *RankUtil {
result := &RankUtil{
maxCount: mc,
compar: comp,
dataList: make([]*Model, 0, mc),
dataDict: make(map[string]*Model, mc),
}
return result
}
// GetMaxCount
// @description: 获取排行榜最大数量
// parameter:
// @receiver r:
// return:
// @int:
func (r *RankUtil) GetMaxCount() int {
return r.maxCount
}
// GetCount
// @description: 获取排行榜当前数量
// parameter:
// @receiver r:
// return:
// @int:
func (r *RankUtil) GetCount() int {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
return len(r.dataList)
}
// IsFull
// @description: 判断排行榜是否已经满了
// parameter:
// @receiver r:
// return:
// @bool:
func (r *RankUtil) IsFull() bool {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
return len(r.dataList) == r.maxCount
}
// GetAll
// @description: 获取排行榜内容
// parameter:
// @receiver r:
// return:
// @[]*Model:
func (r *RankUtil) GetAll() []*Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
result := make([]*Model, 0, len(r.dataList))
for _, item := range r.dataList {
if item == nil || item.obj == nil {
break
}
result = append(result, item)
}
return result
}
// GetRankListBySkip
// @description: 获取排行榜内容
// parameter:
// @receiver r:
// @skip:跳过的数量
// @count:跳过后需要返回的数量
// return:
// @[]*Model:
func (r *RankUtil) GetRankListBySkip(skip, count int) []*Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
result := make([]*Model, 0, count)
cn := len(r.dataList)
if skip >= cn {
return result
}
for i := 0; i < count; i++ {
item := r.dataList[skip+i]
if item == nil || item.obj == nil {
break
}
result = append(result, item)
}
return result
}
// GetItemForK
// @description: 根据key获取对象
// parameter:
// @receiver r:
// @k:key
// return:
// @*Model:
func (r *RankUtil) GetItemForK(k string) *Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
item, _ := r.dataDict[k]
return item
}
// GetItemForRank
// @description: 根据排名获取对应对象
// parameter:
// @receiver r:
// @rank:排名
// return:
// @*Model:
func (r *RankUtil) GetItemForRank(rank int) *Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
if len(r.dataList) < rank {
return nil
}
return r.dataList[rank-1]
}
// Refresh
// @description: 刷新排行榜
// parameter:
// @receiver r:
// @k:key
// @o:排行持有的对象,业务层不应该持有该对象。否则业务层更改内容,会导致排行榜内容被改变
// @isup:变动是否升高
// return:
// @changeRank:排行是否变动
// @dm:如果有对象因为排行变动导致掉出排行榜则返回该对象否则返回nil
func (r *RankUtil) Refresh(k string, o interface{}, isup bool) (changeRank bool, dm *Model) {
r.dataLock.Lock()
defer r.dataLock.Unlock()
changeRank = false
curItem, exists := r.dataDict[k]
if isup {
if !exists {
newRank := len(r.dataList) + 1
curItem = &Model{rank: newRank, key: k, obj: o}
// 排行榜未满,必定入榜,则先加入排行榜
if newRank <= r.maxCount {
r.dataList = append(r.dataList, curItem)
r.dataDict[curItem.key] = curItem
changeRank = true
_, dm = r.upRank(curItem)
} else {
changeRank, dm = r.upRank(curItem)
}
} else {
curItem.obj = o
changeRank, dm = r.upRank(curItem)
}
} else {
// 如果在排行榜内,从之前往下比较
if exists {
curItem.obj = o
changeRank = r.downRank(curItem)
} else {
// 如果不在排行榜内,直接结束
}
}
return
}
// Delete
// @description: 删除k指定的对象,很耗性能,不建议高频使用
// parameter:
// @receiver r:
// @k:key
// return:
// @bool:true:代表key存在排行榜中并且删除成功 false:其他情况
func (r *RankUtil) Delete(k string) bool {
r.dataLock.Lock()
defer r.dataLock.Unlock()
m, exists := r.dataDict[k]
if !exists {
return false
}
//从当前位置向后移动,到最后的时候,删除
for {
if m.rank >= len(r.dataList) {
break
}
am := r.dataList[m.rank]
r.exchange(m, am)
m = am
}
//最后一个应该是要删除的对象
r.dataList = append(r.dataList[:m.rank-1:r.maxCount], r.dataList[m.rank:]...)
delete(r.dataDict, k)
return true
}
// upRank
// @description: 排行升高
// parameter:
// @receiver r:
// @curItem:当前对象
// return:
// @changeRank:排行是否变动
// @dm:因排行变动被移除排行的对象
func (r *RankUtil) upRank(curItem *Model) (changeRank bool, dm *Model) {
changeRank = false
for {
// rank=1,排在第一位下标为0故这里需要-2为上一位的下标
beforeIndex := curItem.rank - 2
if beforeIndex < 0 {
break
}
beforeItem := r.dataList[beforeIndex]
if r.compar(curItem.obj, beforeItem.obj) <= 0 {
break
}
// 交换操作
tdm := r.exchange(curItem, beforeItem)
if tdm != nil {
dm = tdm
}
curItem = beforeItem
changeRank = true
}
return
}
// downRank
// @description: 排行降低
// parameter:
// @receiver r:
// @curItem:当前对象
// return:
// @bool:
func (r *RankUtil) downRank(curItem *Model) bool {
changeRank := false
for {
// rank=1,排在第一位下标为0需要对比rank=2的下标为1故这里直接取rank即可
afterIndex := curItem.rank
if afterIndex >= len(r.dataList) {
break
}
afterItem := r.dataList[afterIndex]
if r.compar(afterItem.obj, curItem.obj) <= 0 {
break
}
// 交换操作
r.exchange(curItem, afterItem)
curItem = afterItem
changeRank = true
}
return changeRank
}
// exchange
// @description: 排行对象交换
// parameter:
// @receiver r:
// @a:对象a
// @b:对象b
// return:
// @delRank:因交换被移除排行榜的对象
func (r *RankUtil) exchange(a, b *Model) (dm *Model) {
tempObj := a.obj
tempKey := a.key
a.obj = b.obj
a.key = b.key
b.obj = tempObj
b.key = tempKey
if a.rank > r.maxCount {
delete(r.dataDict, a.key)
dm = a
} else {
r.dataDict[a.key] = a
}
if b.rank > r.maxCount {
delete(r.dataDict, b.key)
dm = b
} else {
r.dataDict[b.key] = b
}
return
}