forked from Vivino/rankdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
element.go
100 lines (87 loc) · 2.43 KB
/
element.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package rankdb
// Copyright 2019 Vivino. All rights reserved
//
// See LICENSE file for license details
//go:generate msgp $GOFILE
import (
"encoding/json"
"math"
)
// ElementID is the ID of an element in a list.
type ElementID uint64
// Element contains information about a single element in a list.
//msgp:tuple Element
type Element struct {
Score uint64
ID ElementID
Payload []byte
TieBreaker uint32
Updated uint32
}
// elementsVersion should be incremented if non-compatible changes are made.
const elementsVersion = 1
// Above returns true if e should be ranked above b.
// If score is equal, the tiebreaker is used, descending.
// If tiebreaker is equal, last update time wins.
// Final tiebreaker is element ID, where lowest ID gets first.
func (e Element) Above(b Element) bool {
if e.Score != b.Score {
return e.Score > b.Score
}
if e.TieBreaker != b.TieBreaker {
return e.TieBreaker > b.TieBreaker
}
if e.Updated != b.Updated {
return e.Updated < b.Updated
}
return e.ID < b.ID
}
// As above but purely on pointers.
func (e *Element) aboveP(b *Element) bool {
if e.Score != b.Score {
return e.Score > b.Score
}
if e.TieBreaker != b.TieBreaker {
return e.TieBreaker > b.TieBreaker
}
if e.Updated != b.Updated {
return e.Updated < b.Updated
}
return e.ID < b.ID
}
// String returns a readable string representation of the element.
func (e Element) String() string {
b, err := json.MarshalIndent(e, "", " ")
if err != nil {
return err.Error()
}
return string(b)
}
// IndexElement is an element that is used as an index.
type IndexElement struct {
Element
}
// AsIndex returns the index element of this element in the given collection.
func (e Element) AsIndex(s SegmentID) IndexElement {
return IndexElement{Element{ID: e.ID, Score: uint64(e.ID), Updated: e.Updated, TieBreaker: uint32(s)}}
}
// PrevMax will return the maximum just prior to the current element.
func (e Element) PrevMax() (score uint64, tie uint32) {
if e.Score == 0 && e.TieBreaker == 0 {
return 0, 0
}
if e.TieBreaker == 0 {
return e.Score - 1, math.MaxUint32
}
return e.Score, e.TieBreaker - 1
}
// AboveThis will return the score of the element just above this.
func (e Element) AboveThis() (score uint64, tie uint32) {
if e.Score == math.MaxUint64 && e.TieBreaker == math.MaxUint32 {
return math.MaxUint64, math.MaxUint32
}
if e.TieBreaker == math.MaxUint32 {
return e.Score + 1, 0
}
return e.Score, e.TieBreaker + 1
}