1use crate::bal::BlockAccessIndex;
4use std::vec::Vec;
5
6#[derive(Debug, Default, Clone, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct BalWrites<T: PartialEq + Clone> {
12 pub writes: Vec<(BlockAccessIndex, T)>,
14}
15
16impl<T: PartialEq + Clone> BalWrites<T> {
17 pub fn new(mut writes: Vec<(BlockAccessIndex, T)>) -> Self {
19 writes.sort_by_key(|(index, _)| *index);
20 Self { writes }
21 }
22
23 #[inline(never)]
25 pub fn get_linear_search(&self, bal_index: BlockAccessIndex) -> Option<T> {
26 let mut last_item = None;
27 for (index, item) in self.writes.iter() {
28 if index >= &bal_index {
30 return last_item;
31 }
32 last_item = Some(item.clone());
33 }
34 last_item
35 }
36
37 pub fn get(&self, bal_index: BlockAccessIndex) -> Option<T> {
39 if self.writes.len() < 5 {
40 return self.get_linear_search(bal_index);
41 }
42 let i = match self
44 .writes
45 .binary_search_by_key(&bal_index, |(index, _)| *index)
46 {
47 Ok(i) => i,
48 Err(i) => i,
49 };
50 (i != 0).then(|| self.writes[i - 1].1.clone())
52 }
53
54 pub fn extend(&mut self, other: BalWrites<T>) {
56 self.writes.extend(other.writes);
57 }
58
59 pub const fn is_empty(&self) -> bool {
61 self.writes.is_empty()
62 }
63
64 #[inline]
72 pub fn force_update(&mut self, index: BlockAccessIndex, value: T) {
73 if let Some(last) = self.writes.last_mut() {
74 if index == last.0 {
75 last.1 = value;
76 return;
77 }
78 }
79 self.writes.push((index, value));
80 }
81
82 pub fn update(&mut self, index: BlockAccessIndex, original_value: &T, value: T) {
86 self.update_with_key(index, original_value, value, |i| i);
87 }
88
89 #[inline]
95 pub fn update_with_key<K: PartialEq, F>(
96 &mut self,
97 index: BlockAccessIndex,
98 original_subvalue: &K,
99 value: T,
100 f: F,
101 ) where
102 F: Fn(&T) -> &K,
103 {
104 if let Some(last) = self.writes.last_mut() {
106 if last.0 != index {
107 if f(&last.1) != f(&value) {
109 self.writes.push((index, value));
110 }
111 return;
112 }
113 }
114
115 let (previous, last) = match self.writes.as_mut_slice() {
117 [.., previous, last] => (f(&previous.1), last),
118 [last] => (original_subvalue, last),
119 [] => {
120 if original_subvalue != f(&value) {
122 self.writes.push((index, value));
123 }
124 return;
125 }
126 };
127
128 if previous == f(&value) {
130 self.writes.pop();
131 return;
132 }
133
134 last.1 = value;
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 const fn idx(index: u64) -> BlockAccessIndex {
144 BlockAccessIndex::new(index)
145 }
146
147 #[test]
148 fn test_get() {
149 let bal_writes = BalWrites::new(vec![(idx(0), 1), (idx(1), 2), (idx(2), 3)]);
150 assert_eq!(bal_writes.get(idx(0)), None);
151 assert_eq!(bal_writes.get(idx(1)), Some(1));
152 assert_eq!(bal_writes.get(idx(2)), Some(2));
153 assert_eq!(bal_writes.get(idx(3)), Some(3));
154 assert_eq!(bal_writes.get(idx(4)), Some(3));
155 }
156
157 fn get_binary_search(threshold: u64) {
158 let entries: Vec<_> = (0..threshold - 1)
160 .map(|i| (idx(i), i + 1))
161 .chain(std::iter::once((idx(threshold), threshold + 1)))
162 .collect();
163
164 let bal_writes = BalWrites::new(entries);
165
166 assert_eq!(bal_writes.get(idx(0)), None);
168
169 for i in 1..threshold - 1 {
171 assert_eq!(bal_writes.get(idx(i)), Some(i));
172 }
173
174 assert_eq!(bal_writes.get(idx(threshold)), Some(threshold - 1));
176
177 assert_eq!(bal_writes.get(idx(threshold + 1)), Some(threshold + 1));
179 }
180
181 #[test]
182 fn test_get_binary_search() {
183 get_binary_search(4);
184 get_binary_search(5);
185 get_binary_search(6);
186 get_binary_search(7);
187 }
188}