344 lines
6.6 KiB
Go
344 lines
6.6 KiB
Go
|
|
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
|
|||
|
|
}
|