hopper_core/collections/
sorted_vec.rs1use crate::account::{FixedLayout, Pod};
12use hopper_runtime::error::ProgramError;
13
14const HEADER_SIZE: usize = 4;
15
16pub struct SortedVec<'a, T: Pod + FixedLayout + Ord> {
21 data: &'a mut [u8],
22 _phantom: core::marker::PhantomData<T>,
23}
24
25impl<'a, T: Pod + FixedLayout + Ord> SortedVec<'a, T> {
26 #[inline]
28 pub fn from_bytes(data: &'a mut [u8]) -> Result<Self, ProgramError> {
29 if data.len() < HEADER_SIZE {
30 return Err(ProgramError::AccountDataTooSmall);
31 }
32 Ok(Self {
33 data,
34 _phantom: core::marker::PhantomData,
35 })
36 }
37
38 #[inline(always)]
40 pub fn len(&self) -> usize {
41 u32::from_le_bytes([self.data[0], self.data[1], self.data[2], self.data[3]]) as usize
42 }
43
44 #[inline(always)]
46 pub fn capacity(&self) -> usize {
47 (self.data.len() - HEADER_SIZE) / T::SIZE
48 }
49
50 #[inline(always)]
52 pub fn is_empty(&self) -> bool {
53 self.len() == 0
54 }
55
56 #[inline(always)]
58 pub fn is_full(&self) -> bool {
59 self.len() >= self.capacity()
60 }
61
62 #[inline(always)]
63 fn set_len(&mut self, len: usize) {
64 let bytes = (len as u32).to_le_bytes();
65 self.data[0] = bytes[0];
66 self.data[1] = bytes[1];
67 self.data[2] = bytes[2];
68 self.data[3] = bytes[3];
69 }
70
71 #[inline(always)]
72 fn element_offset(index: usize) -> usize {
73 HEADER_SIZE + index * T::SIZE
74 }
75
76 #[inline]
78 fn read_at(&self, index: usize) -> T {
79 let offset = Self::element_offset(index);
80 unsafe { core::ptr::read_unaligned(self.data.as_ptr().add(offset) as *const T) }
82 }
83
84 #[inline]
86 fn write_at(&mut self, index: usize, value: T) {
87 let offset = Self::element_offset(index);
88 unsafe { core::ptr::write_unaligned(self.data.as_mut_ptr().add(offset) as *mut T, value) }
90 }
91
92 #[inline]
95 pub fn binary_search(&self, target: &T) -> Result<usize, usize> {
96 let len = self.len();
97 if len == 0 {
98 return Err(0);
99 }
100 let mut lo: usize = 0;
101 let mut hi: usize = len;
102 while lo < hi {
103 let mid = lo + (hi - lo) / 2;
104 let elem = self.read_at(mid);
105 match elem.cmp(target) {
106 core::cmp::Ordering::Less => lo = mid + 1,
107 core::cmp::Ordering::Equal => return Ok(mid),
108 core::cmp::Ordering::Greater => hi = mid,
109 }
110 }
111 Err(lo)
112 }
113
114 #[inline]
116 pub fn contains(&self, target: &T) -> bool {
117 self.binary_search(target).is_ok()
118 }
119
120 #[inline]
122 pub fn get(&self, index: usize) -> Result<T, ProgramError> {
123 if index >= self.len() {
124 return Err(ProgramError::InvalidArgument);
125 }
126 Ok(self.read_at(index))
127 }
128
129 #[inline]
132 pub fn insert(&mut self, value: T) -> Result<usize, ProgramError> {
133 let len = self.len();
134 if len >= self.capacity() {
135 return Err(ProgramError::AccountDataTooSmall);
136 }
137 let insert_idx = match self.binary_search(&value) {
138 Ok(idx) => idx, Err(idx) => idx,
140 };
141 if insert_idx < len {
143 let src_offset = Self::element_offset(insert_idx);
144 let dst_offset = Self::element_offset(insert_idx + 1);
145 let byte_count = (len - insert_idx) * T::SIZE;
146 unsafe {
148 core::ptr::copy(
149 self.data.as_ptr().add(src_offset),
150 self.data.as_mut_ptr().add(dst_offset),
151 byte_count,
152 );
153 }
154 }
155 self.write_at(insert_idx, value);
156 self.set_len(len + 1);
157 Ok(insert_idx)
158 }
159
160 #[inline]
163 pub fn insert_unique(&mut self, value: T) -> Result<usize, usize> {
164 match self.binary_search(&value) {
165 Ok(existing) => Err(existing),
166 Err(insert_idx) => {
167 let len = self.len();
168 if len >= self.capacity() {
169 return Err(usize::MAX); }
171 if insert_idx < len {
172 let src_offset = Self::element_offset(insert_idx);
173 let dst_offset = Self::element_offset(insert_idx + 1);
174 let byte_count = (len - insert_idx) * T::SIZE;
175 unsafe {
177 core::ptr::copy(
178 self.data.as_ptr().add(src_offset),
179 self.data.as_mut_ptr().add(dst_offset),
180 byte_count,
181 );
182 }
183 }
184 self.write_at(insert_idx, value);
185 self.set_len(len + 1);
186 Ok(insert_idx)
187 }
188 }
189 }
190
191 #[inline]
193 pub fn remove(&mut self, index: usize) -> Result<T, ProgramError> {
194 let len = self.len();
195 if index >= len {
196 return Err(ProgramError::InvalidArgument);
197 }
198 let removed = self.read_at(index);
199 if index + 1 < len {
201 let src_offset = Self::element_offset(index + 1);
202 let dst_offset = Self::element_offset(index);
203 let byte_count = (len - index - 1) * T::SIZE;
204 unsafe {
206 core::ptr::copy(
207 self.data.as_ptr().add(src_offset),
208 self.data.as_mut_ptr().add(dst_offset),
209 byte_count,
210 );
211 }
212 }
213 let last_offset = Self::element_offset(len - 1);
215 for b in &mut self.data[last_offset..last_offset + T::SIZE] {
216 *b = 0;
217 }
218 self.set_len(len - 1);
219 Ok(removed)
220 }
221
222 #[inline]
224 pub fn remove_value(&mut self, value: &T) -> Result<T, ProgramError> {
225 match self.binary_search(value) {
226 Ok(idx) => self.remove(idx),
227 Err(_) => Err(ProgramError::InvalidArgument),
228 }
229 }
230
231 #[inline]
233 pub fn min(&self) -> Result<T, ProgramError> {
234 if self.is_empty() {
235 return Err(ProgramError::InvalidArgument);
236 }
237 Ok(self.read_at(0))
238 }
239
240 #[inline]
242 pub fn max(&self) -> Result<T, ProgramError> {
243 let len = self.len();
244 if len == 0 {
245 return Err(ProgramError::InvalidArgument);
246 }
247 Ok(self.read_at(len - 1))
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254 use crate::abi::WireU64;
255
256 #[test]
257 fn sorted_vec_insert_and_search() {
258 let mut buf = [0u8; 4 + 8 * 8]; let mut sv = SortedVec::<WireU64>::from_bytes(&mut buf).unwrap();
260
261 sv.insert(WireU64::new(50)).unwrap();
263 sv.insert(WireU64::new(10)).unwrap();
264 sv.insert(WireU64::new(30)).unwrap();
265 sv.insert(WireU64::new(20)).unwrap();
266 sv.insert(WireU64::new(40)).unwrap();
267
268 assert_eq!(sv.len(), 5);
269
270 assert_eq!(sv.get(0).unwrap().get(), 10);
272 assert_eq!(sv.get(1).unwrap().get(), 20);
273 assert_eq!(sv.get(2).unwrap().get(), 30);
274 assert_eq!(sv.get(3).unwrap().get(), 40);
275 assert_eq!(sv.get(4).unwrap().get(), 50);
276
277 assert!(sv.contains(&WireU64::new(30)));
279 assert!(!sv.contains(&WireU64::new(25)));
280 assert_eq!(sv.binary_search(&WireU64::new(30)), Ok(2));
281 assert_eq!(sv.binary_search(&WireU64::new(25)), Err(2));
282 }
283
284 #[test]
285 fn sorted_vec_min_max() {
286 let mut buf = [0u8; 4 + 8 * 4];
287 let mut sv = SortedVec::<WireU64>::from_bytes(&mut buf).unwrap();
288 sv.insert(WireU64::new(100)).unwrap();
289 sv.insert(WireU64::new(5)).unwrap();
290 sv.insert(WireU64::new(42)).unwrap();
291
292 assert_eq!(sv.min().unwrap().get(), 5);
293 assert_eq!(sv.max().unwrap().get(), 100);
294 }
295
296 #[test]
297 fn sorted_vec_remove() {
298 let mut buf = [0u8; 4 + 8 * 4];
299 let mut sv = SortedVec::<WireU64>::from_bytes(&mut buf).unwrap();
300 sv.insert(WireU64::new(10)).unwrap();
301 sv.insert(WireU64::new(20)).unwrap();
302 sv.insert(WireU64::new(30)).unwrap();
303
304 sv.remove_value(&WireU64::new(20)).unwrap();
305 assert_eq!(sv.len(), 2);
306 assert_eq!(sv.get(0).unwrap().get(), 10);
307 assert_eq!(sv.get(1).unwrap().get(), 30);
308 }
309
310 #[test]
311 fn sorted_vec_insert_unique() {
312 let mut buf = [0u8; 4 + 8 * 4];
313 let mut sv = SortedVec::<WireU64>::from_bytes(&mut buf).unwrap();
314 assert!(sv.insert_unique(WireU64::new(10)).is_ok());
315 assert!(sv.insert_unique(WireU64::new(20)).is_ok());
316 assert!(sv.insert_unique(WireU64::new(10)).is_err());
318 assert_eq!(sv.len(), 2);
319 }
320}