raw_btree/node/
leaf.rs

1use std::cmp::Ordering;
2
3use crate::{
4	utils::{binary_search_min, Array},
5	Storage, M,
6};
7
8use super::{Balance, Offset, WouldUnderflow};
9
10#[derive(Clone)]
11pub struct Leaf<T, S: Storage<T>> {
12	parent: Option<S::Node>,
13	items: Array<T, { M + 1 }>,
14}
15
16impl<T, S: Storage<T>> Leaf<T, S> {
17	pub fn new(parent: Option<S::Node>, items: Array<T, { M + 1 }>) -> Self {
18		Self { parent, items }
19	}
20
21	#[inline]
22	pub fn from_item(parent: Option<S::Node>, item: T) -> Leaf<T, S> {
23		let mut items = Array::new();
24		items.push(item);
25
26		Leaf { parent, items }
27	}
28
29	/// Forget the node content without running the items destructors.
30	pub fn forget(&mut self) {
31		std::mem::forget(std::mem::take(&mut self.items));
32	}
33
34	#[inline]
35	pub fn parent(&self) -> Option<S::Node> {
36		self.parent
37	}
38
39	#[inline]
40	pub fn set_parent(&mut self, p: Option<S::Node>) {
41		self.parent = p
42	}
43
44	#[inline]
45	pub fn item_count(&self) -> usize {
46		self.items.len()
47	}
48
49	#[inline]
50	pub fn items(&self) -> &Array<T, { M + 1 }> {
51		&self.items
52	}
53
54	#[inline]
55	pub fn iter(&self) -> std::slice::Iter<T> {
56		self.items.as_ref().iter()
57	}
58
59	#[inline]
60	pub fn get<Q: ?Sized>(&self, cmp: impl Fn(&T, &Q) -> Ordering, key: &Q) -> Option<&T> {
61		match binary_search_min(cmp, &self.items, key) {
62			Some((i, eq)) => {
63				if eq {
64					Some(&self.items[i])
65				} else {
66					None
67				}
68			}
69			_ => None,
70		}
71	}
72
73	#[inline]
74	pub fn get_mut<Q: ?Sized>(
75		&mut self,
76		cmp: impl Fn(&T, &Q) -> Ordering,
77		key: &Q,
78	) -> Option<&mut T> {
79		match binary_search_min(cmp, &self.items, key) {
80			Some((i, eq)) => {
81				if eq {
82					Some(&mut self.items[i])
83				} else {
84					None
85				}
86			}
87			_ => None,
88		}
89	}
90
91	/// Find the offset of the item matching the given key.
92	#[inline]
93	pub fn offset_of<Q: ?Sized>(
94		&self,
95		cmp: impl Fn(&T, &Q) -> Ordering,
96		key: &Q,
97	) -> Result<Offset, Offset> {
98		match binary_search_min(cmp, &self.items, key) {
99			Some((i, eq)) => {
100				if eq {
101					Ok(i.into())
102				} else {
103					Err((i + 1).into())
104				}
105			}
106			None => Err(0.into()),
107		}
108	}
109
110	#[inline]
111	pub fn item(&self, offset: Offset) -> Option<&T> {
112		match offset.value() {
113			Some(offset) => self.items.get(offset),
114			None => None,
115		}
116	}
117
118	#[inline]
119	pub fn item_mut(&mut self, offset: Offset) -> Option<&mut T> {
120		match offset.value() {
121			Some(offset) => self.items.get_mut(offset),
122			None => None,
123		}
124	}
125
126	#[inline]
127	pub fn insert_by_key(
128		&mut self,
129		cmp: impl Fn(&T, &T) -> Ordering,
130		mut item: T,
131	) -> (Offset, Option<T>) {
132		match binary_search_min(cmp, &self.items, &item) {
133			Some((i, eq)) => {
134				if eq {
135					std::mem::swap(&mut item, &mut self.items[i]);
136					(i.into(), Some(item))
137				} else {
138					self.items.insert(i + 1, item);
139					((i + 1).into(), None)
140				}
141			}
142			None => {
143				self.items.insert(0, item);
144				(0.into(), None)
145			}
146		}
147	}
148
149	#[inline]
150	pub fn split(&mut self) -> (usize, T, Leaf<T, S>) {
151		assert!(self.is_overflowing());
152
153		let median_i = (self.items.len() - 1) / 2;
154
155		let right_items = self.items.drain(median_i + 1..).collect();
156		let median = self.items.pop().unwrap();
157
158		let right_leaf = Leaf {
159			parent: self.parent,
160			items: right_items,
161		};
162
163		assert!(!self.is_underflowing());
164		assert!(!right_leaf.is_underflowing());
165
166		(self.items.len(), median, right_leaf)
167	}
168
169	#[inline]
170	pub fn append(&mut self, separator: T, mut other: Leaf<T, S>) -> Offset {
171		let offset = self.items.len();
172		self.items.push(separator);
173		self.items.append(&mut other.items);
174		offset.into()
175	}
176
177	#[inline]
178	pub fn push_left(&mut self, item: T) {
179		self.items.insert(0, item)
180	}
181
182	#[inline]
183	pub fn pop_left(&mut self) -> Result<T, WouldUnderflow> {
184		if self.item_count() < M / 2 {
185			Err(WouldUnderflow)
186		} else {
187			Ok(self.items.remove(0).unwrap())
188		}
189	}
190
191	#[inline]
192	pub fn push_right(&mut self, item: T) -> Offset {
193		let offset = self.items.len();
194		self.items.push(item);
195		offset.into()
196	}
197
198	#[inline]
199	pub fn pop_right(&mut self) -> Result<(Offset, T), WouldUnderflow> {
200		if self.item_count() < M / 2 {
201			Err(WouldUnderflow)
202		} else {
203			let offset = self.items.len();
204			let item = self.items.pop().unwrap();
205			Ok((offset.into(), item))
206		}
207	}
208
209	#[inline]
210	pub fn balance(&self) -> Balance {
211		if self.is_overflowing() {
212			Balance::Overflow
213		} else if self.is_underflowing() {
214			Balance::Underflow(self.items.is_empty())
215		} else {
216			Balance::Balanced
217		}
218	}
219
220	#[inline]
221	pub fn is_overflowing(&self) -> bool {
222		self.item_count() > M
223	}
224
225	#[inline]
226	pub fn is_underflowing(&self) -> bool {
227		self.item_count() < M / 2 - 1
228	}
229
230	/// It is assumed that the leaf will not overflow.
231	#[inline]
232	pub fn insert(&mut self, offset: Offset, item: T) {
233		match offset.value() {
234			Some(offset) => self.items.insert(offset, item),
235			None => panic!("Offset out of bounds"),
236		}
237	}
238
239	/// Remove the item at the given offset.
240	/// Return the new balance of the leaf.
241	#[inline]
242	pub fn remove(&mut self, offset: Offset) -> T {
243		match offset.value() {
244			Some(offset) => self.items.remove(offset).unwrap(),
245			None => panic!("Offset out of bounds"),
246		}
247	}
248
249	#[inline]
250	pub fn remove_last(&mut self) -> T {
251		self.items.pop().unwrap()
252	}
253
254	/// Write the label of the leaf in the DOT language.
255	///
256	/// Requires the `dot` feature.
257	#[cfg(feature = "dot")]
258	#[inline]
259	pub fn dot_write_label<W: std::io::Write>(&self, f: &mut W) -> std::io::Result<()>
260	where
261		T: std::fmt::Display,
262	{
263		for item in &self.items {
264			write!(f, "{{{}}}|", item)?;
265		}
266
267		Ok(())
268	}
269
270	#[cfg(debug_assertions)]
271	pub fn validate(
272		&self,
273		cmp: impl Fn(&T, &T) -> Ordering,
274		parent: Option<S::Node>,
275		min: Option<&T>,
276		max: Option<&T>,
277	) {
278		if self.parent() != parent {
279			panic!("wrong parent")
280		}
281
282		if min.is_some() || max.is_some() {
283			// not root
284			match self.balance() {
285				Balance::Overflow => panic!("leaf is overflowing"),
286				Balance::Underflow(_) => panic!("leaf is underflowing"),
287				_ => (),
288			}
289		}
290
291		if !self.items.windows(2).all(|w| cmp(&w[0], &w[1]).is_lt()) {
292			panic!("leaf items are not sorted")
293		}
294
295		if let Some(min) = min {
296			if let Some(item) = self.items.first() {
297				if cmp(min, item).is_ge() {
298					panic!("leaf item key is greater than right separator")
299				}
300			}
301		}
302
303		if let Some(max) = max {
304			if let Some(item) = self.items.last() {
305				if cmp(max, item).is_le() {
306					panic!("leaf item key is less than left separator")
307				}
308			}
309		}
310	}
311}