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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/// [`Epoch`] is a unit of time that dictates the lifetime of retired memory regions.
///
/// The global epoch rotates `64` [`Epoch`] values in a range of `[0..63]`, instead of monotonically
/// increasing to reduce the memory footprint.
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Epoch {
value: u8,
}
impl Epoch {
/// This crate uses `64` epoch values.
pub(super) const NUM_EPOCHS: u8 = 64;
/// Returns a future [`Epoch`] when the current readers will not be present.
///
/// The current [`Epoch`] may lag behind the global epoch value by `1`, therefore this method
/// returns an [`Epoch`] three epochs next to `self`.
///
/// # Examples
///
/// ```
/// use sdd::Epoch;
///
/// let initial = Epoch::default();
///
/// let next_generation = initial.next_generation();
/// assert_eq!(next_generation, initial.next().next().next());
/// ```
#[inline]
#[must_use]
pub const fn next_generation(self) -> Epoch {
self.next().next().next()
}
/// Checks if the current [`Epoch`] is in the same generation as the given [`Epoch`].
///
/// This operation is not commutative, e.g., `a.in_same_generation(b)` is not the same as
/// `b.in_same_generation(a)`. This returns `true` if the other [`Epoch`] is either the same
/// with the current one, the next one, or the next one after that. The meaning of `false`
/// returned by this method is that a memory region retired in the current [`Epoch`] will no
/// longer be reachable in the other [`Epoch`].
///
/// # Examples
///
/// ```
/// use sdd::Epoch;
///
/// let initial = Epoch::default();
///
/// let next_generation = initial.next_generation();
/// assert!(initial.in_same_generation(initial.next().next()));
/// assert!(!initial.in_same_generation(initial.next().next().next()));
/// ```
#[inline]
#[must_use]
pub const fn in_same_generation(self, other: Epoch) -> bool {
other.value == self.value
|| other.value == self.next().value
|| other.value == self.next().next().value
}
/// Returns the next [`Epoch`] value.
///
/// # Examples
///
/// ```
/// use sdd::Epoch;
///
/// let initial = Epoch::default();
///
/// let next = initial.next();
/// assert!(initial < next);
///
/// let next_prev = next.prev();
/// assert_eq!(initial, next_prev);
/// ```
#[inline]
#[must_use]
pub const fn next(self) -> Epoch {
Epoch {
value: (self.value + 1) % Self::NUM_EPOCHS,
}
}
/// Returns the previous [`Epoch`] value.
///
/// # Examples
///
/// ```
/// use sdd::Epoch;
///
/// let initial = Epoch::default();
///
/// let prev = initial.prev();
/// assert!(initial < prev);
///
/// let prev_next = prev.next();
/// assert_eq!(initial, prev_next);
/// ```
#[inline]
#[must_use]
pub const fn prev(self) -> Epoch {
Epoch {
value: (self.value + Self::NUM_EPOCHS - 1) % Self::NUM_EPOCHS,
}
}
/// Construct an [`Epoch`] from a [`u8`] value.
#[inline]
pub(super) const fn from_u8(value: u8) -> Epoch {
Epoch { value }
}
}
impl From<Epoch> for u8 {
#[inline]
fn from(epoch: Epoch) -> Self {
epoch.value
}
}
impl TryFrom<u8> for Epoch {
type Error = Epoch;
#[inline]
fn try_from(value: u8) -> Result<Self, Self::Error> {
if value < Self::NUM_EPOCHS {
Ok(Epoch { value })
} else {
Err(Epoch {
value: value % Self::NUM_EPOCHS,
})
}
}
}