138 lines
4.1 KiB
Go
138 lines
4.1 KiB
Go
package moreser
|
|
|
|
// NormalizePage 规范化分页参数,限制单次请求数量避免大分页拖垮 MongoDB。
|
|
func NormalizePage(pageNum, pageSize, defaultPageSize, maxPageSize int64) (int64, int64) {
|
|
if pageNum <= 0 {
|
|
pageNum = 1
|
|
}
|
|
if pageSize <= 0 {
|
|
pageSize = defaultPageSize
|
|
}
|
|
if pageSize > maxPageSize {
|
|
pageSize = maxPageSize
|
|
}
|
|
return pageNum, pageSize
|
|
}
|
|
|
|
// InsertedAdsCount 计算实际可穿插的广告数量,每 interval 条内容后插入 1 条广告。
|
|
func InsertedAdsCount(contentTotal, adsTotal, interval int64) int64 {
|
|
if contentTotal <= 0 || adsTotal <= 0 || interval <= 0 {
|
|
return 0
|
|
}
|
|
insertSlots := contentTotal / interval
|
|
if insertSlots > adsTotal {
|
|
return adsTotal
|
|
}
|
|
return insertSlots
|
|
}
|
|
|
|
// ContentPosition 计算内容原始下标在混排列表中的全局位置。
|
|
func ContentPosition(contentIndex, adsTotal, interval int64) int64 {
|
|
if interval <= 0 {
|
|
return contentIndex
|
|
}
|
|
adsBefore := contentIndex / interval
|
|
if adsBefore > adsTotal {
|
|
adsBefore = adsTotal
|
|
}
|
|
return contentIndex + adsBefore
|
|
}
|
|
|
|
// FirstContentIndexAtOrAfter 找到指定混排位置之后第一条内容下标。
|
|
func FirstContentIndexAtOrAfter(pos, contentTotal, adsTotal, interval int64) int64 {
|
|
left, right := int64(0), contentTotal
|
|
for left < right {
|
|
mid := left + (right-left)/2
|
|
if ContentPosition(mid, adsTotal, interval) < pos {
|
|
left = mid + 1
|
|
continue
|
|
}
|
|
right = mid
|
|
}
|
|
return left
|
|
}
|
|
|
|
// ContentRange 计算当前混排分页需要读取的内容下标范围。
|
|
func ContentRange(start, end, contentTotal, adsTotal, interval int64) (int64, int64) {
|
|
contentStart := FirstContentIndexAtOrAfter(start, contentTotal, adsTotal, interval)
|
|
contentEnd := FirstContentIndexAtOrAfter(end, contentTotal, adsTotal, interval)
|
|
if contentStart >= contentEnd {
|
|
return 0, 0
|
|
}
|
|
return contentStart, contentEnd - contentStart
|
|
}
|
|
|
|
// ContentRangeWithoutTotal 计算当前混排分页需要读取的内容范围,不依赖内容总数。
|
|
// 适用于列表接口不返回 totalCount 的场景;广告位仍按“每 interval 条内容后插入 1 条广告”计算。
|
|
func ContentRangeWithoutTotal(start, end, adsTotal, interval int64) (int64, int64) {
|
|
if start < 0 || end <= start {
|
|
return 0, 0
|
|
}
|
|
contentStart := contentIndexAtMixedPosition(start, adsTotal, interval)
|
|
contentEnd := contentIndexAtMixedPosition(end, adsTotal, interval)
|
|
if contentStart >= contentEnd {
|
|
return 0, 0
|
|
}
|
|
return contentStart, contentEnd - contentStart
|
|
}
|
|
|
|
// ContentIndexAtPositionWithoutTotal 计算混排位置对应的内容下标,不判断该位置是否为广告。
|
|
func ContentIndexAtPositionWithoutTotal(pos, adsTotal, interval int64) int64 {
|
|
return contentIndexAtMixedPosition(pos, adsTotal, interval)
|
|
}
|
|
|
|
// AdIndexAtPositionWithoutTotal 计算混排位置对应的广告下标,返回 -1 表示该位置不是广告。
|
|
func AdIndexAtPositionWithoutTotal(pos, adsTotal, interval int64) int64 {
|
|
if adsTotal <= 0 || interval <= 0 || pos < 0 {
|
|
return -1
|
|
}
|
|
cycle := interval + 1
|
|
if pos >= adsTotal*cycle {
|
|
return -1
|
|
}
|
|
if pos%cycle != interval {
|
|
return -1
|
|
}
|
|
return pos / cycle
|
|
}
|
|
|
|
// contentIndexAtMixedPosition 返回混排位置之前已经出现的内容数量。
|
|
func contentIndexAtMixedPosition(pos, adsTotal, interval int64) int64 {
|
|
if pos <= 0 {
|
|
return 0
|
|
}
|
|
if adsTotal <= 0 || interval <= 0 {
|
|
return pos
|
|
}
|
|
adCycle := interval + 1
|
|
adAreaSize := adsTotal * adCycle
|
|
if pos >= adAreaSize {
|
|
return pos - adsTotal
|
|
}
|
|
fullCycles := pos / adCycle
|
|
remain := pos % adCycle
|
|
return fullCycles*interval + minInt64(remain, interval)
|
|
}
|
|
|
|
func minInt64(a, b int64) int64 {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
// AdIndexAtPosition 计算混排位置对应的广告下标,返回 -1 表示该位置不是广告。
|
|
func AdIndexAtPosition(pos, contentTotal, adsTotal, interval int64) int64 {
|
|
if interval <= 0 {
|
|
return -1
|
|
}
|
|
nextContent := FirstContentIndexAtOrAfter(pos+1, contentTotal, adsTotal, interval)
|
|
prevContent := nextContent - 1
|
|
if prevContent >= 0 && (prevContent+1)%interval == 0 && (prevContent+1)/interval-1 < adsTotal {
|
|
if ContentPosition(prevContent, adsTotal, interval)+1 == pos {
|
|
return (prevContent+1)/interval - 1
|
|
}
|
|
}
|
|
return -1
|
|
}
|