lightning/util/
indexed_map.rs

1//! This module has a map which can be iterated in a deterministic order. See the [`IndexedMap`].
2
3use crate::prelude::*;
4use alloc::slice::Iter;
5use core::hash::Hash;
6use core::ops::{Bound, RangeBounds};
7
8/// A map which can be iterated in a deterministic order.
9///
10/// This would traditionally be accomplished by simply using a [`BTreeMap`], however B-Trees
11/// generally have very slow lookups. Because we use a nodes+channels map while finding routes
12/// across the network graph, our network graph backing map must be as performant as possible.
13/// However, because peers expect to sync the network graph from us (and we need to support that
14/// without holding a lock on the graph for the duration of the sync or dumping the entire graph
15/// into our outbound message queue), we need an iterable map with a consistent iteration order we
16/// can jump to a starting point on.
17///
18/// Thus, we have a custom data structure here - its API mimics that of Rust's [`BTreeMap`], but is
19/// actually backed by a [`HashMap`], with some additional tracking to ensure we can iterate over
20/// keys in the order defined by [`Ord`].
21///
22/// This is not exported to bindings users as bindings provide alternate accessors rather than exposing maps directly.
23///
24/// [`BTreeMap`]: alloc::collections::BTreeMap
25#[derive(Clone, Debug, Eq)]
26pub struct IndexedMap<K: Hash + Ord, V> {
27	map: HashMap<K, V>,
28	keys: Vec<K>,
29}
30
31impl<K: Clone + Hash + Ord, V> IndexedMap<K, V> {
32	/// Constructs a new, empty map
33	pub fn new() -> Self {
34		Self { map: new_hash_map(), keys: Vec::new() }
35	}
36
37	/// Constructs a new, empty map with the given capacity pre-allocated
38	pub fn with_capacity(capacity: usize) -> Self {
39		Self { map: hash_map_with_capacity(capacity), keys: Vec::with_capacity(capacity) }
40	}
41
42	#[inline(always)]
43	/// Fetches the element with the given `key`, if one exists.
44	pub fn get(&self, key: &K) -> Option<&V> {
45		self.map.get(key)
46	}
47
48	/// Fetches a mutable reference to the element with the given `key`, if one exists.
49	pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
50		self.map.get_mut(key)
51	}
52
53	/// Fetches the key-value pair corresponding to the supplied key, if one exists.
54	pub fn get_key_value(&self, key: &K) -> Option<(&K, &V)> {
55		self.map.get_key_value(key)
56	}
57
58	#[inline]
59	/// Returns true if an element with the given `key` exists in the map.
60	pub fn contains_key(&self, key: &K) -> bool {
61		self.map.contains_key(key)
62	}
63
64	/// Removes the element with the given `key`, returning it, if one exists.
65	pub fn remove(&mut self, key: &K) -> Option<V> {
66		let ret = self.map.remove(key);
67		if let Some(_) = ret {
68			let idx =
69				self.keys.iter().position(|k| k == key).expect("map and keys must be consistent");
70			self.keys.remove(idx);
71		}
72		ret
73	}
74
75	/// Removes elements with the given `keys` in bulk, returning the set of removed elements.
76	pub fn remove_fetch_bulk(&mut self, keys: &HashSet<K>) -> Vec<(K, V)> {
77		let mut res = Vec::with_capacity(keys.len());
78		for key in keys.iter() {
79			if let Some((k, v)) = self.map.remove_entry(key) {
80				res.push((k, v));
81			}
82		}
83		self.keys.retain(|k| !keys.contains(k));
84		res
85	}
86
87	/// Removes elements with the given `keys` in bulk.
88	pub fn remove_bulk(&mut self, keys: &HashSet<K>) {
89		for key in keys.iter() {
90			self.map.remove(key);
91		}
92		self.keys.retain(|k| !keys.contains(k));
93	}
94
95	/// Inserts the given `key`/`value` pair into the map, returning the element that was
96	/// previously stored at the given `key`, if one exists.
97	pub fn insert(&mut self, key: K, value: V) -> Option<V> {
98		let ret = self.map.insert(key.clone(), value);
99		if ret.is_none() {
100			self.keys.push(key);
101		}
102		ret
103	}
104
105	/// Returns an [`Entry`] for the given `key` in the map, allowing access to the value.
106	pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
107		match self.map.entry(key.clone()) {
108			hash_map::Entry::Vacant(entry) => {
109				Entry::Vacant(VacantEntry { underlying_entry: entry, key, keys: &mut self.keys })
110			},
111			hash_map::Entry::Occupied(entry) => {
112				Entry::Occupied(OccupiedEntry { underlying_entry: entry, keys: &mut self.keys })
113			},
114		}
115	}
116
117	/// Returns an iterator which iterates over the keys in the map, in a random order.
118	pub fn unordered_keys(&self) -> impl Iterator<Item = &K> {
119		self.map.keys()
120	}
121
122	/// Returns an iterator which iterates over the `key`/`value` pairs in a random order.
123	pub fn unordered_iter(&self) -> impl Iterator<Item = (&K, &V)> {
124		self.map.iter()
125	}
126
127	/// Returns an iterator which iterates over the `key`s and mutable references to `value`s in a
128	/// random order.
129	pub fn unordered_iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
130		self.map.iter_mut()
131	}
132
133	/// Returns an iterator which iterates over the `key`/`value` pairs in a given range.
134	pub fn range<R: RangeBounds<K>>(&mut self, range: R) -> Range<'_, K, V> {
135		self.keys.sort_unstable();
136		let start = match range.start_bound() {
137			Bound::Unbounded => 0,
138			Bound::Included(key) => self.keys.binary_search(key).unwrap_or_else(|index| index),
139			Bound::Excluded(key) => {
140				self.keys.binary_search(key).map(|index| index + 1).unwrap_or_else(|index| index)
141			},
142		};
143		let end = match range.end_bound() {
144			Bound::Unbounded => self.keys.len(),
145			Bound::Included(key) => {
146				self.keys.binary_search(key).map(|index| index + 1).unwrap_or_else(|index| index)
147			},
148			Bound::Excluded(key) => self.keys.binary_search(key).unwrap_or_else(|index| index),
149		};
150
151		Range { inner_range: self.keys[start..end].iter(), map: &self.map }
152	}
153
154	/// Returns the number of `key`/`value` pairs in the map
155	pub fn len(&self) -> usize {
156		self.map.len()
157	}
158
159	/// Returns true if there are no elements in the map
160	pub fn is_empty(&self) -> bool {
161		self.map.is_empty()
162	}
163}
164
165impl<K: Hash + Ord + PartialEq, V: PartialEq> PartialEq for IndexedMap<K, V> {
166	fn eq(&self, other: &Self) -> bool {
167		self.map == other.map
168	}
169}
170
171/// An iterator over a range of values in an [`IndexedMap`]
172///
173/// This is not exported to bindings users as bindings provide alternate accessors rather than exposing maps directly.
174pub struct Range<'a, K: Hash + Ord, V> {
175	inner_range: Iter<'a, K>,
176	map: &'a HashMap<K, V>,
177}
178impl<'a, K: Hash + Ord, V: 'a> Iterator for Range<'a, K, V> {
179	type Item = (&'a K, &'a V);
180	fn next(&mut self) -> Option<(&'a K, &'a V)> {
181		self.inner_range
182			.next()
183			.map(|k| (k, self.map.get(k).expect("map and keys must be consistent")))
184	}
185}
186
187/// An [`Entry`] for a key which currently has no value
188///
189/// This is not exported to bindings users as bindings provide alternate accessors rather than exposing maps directly.
190pub struct VacantEntry<'a, K: Hash + Ord, V> {
191	underlying_entry: VacantHashMapEntry<'a, K, V>,
192	key: K,
193	keys: &'a mut Vec<K>,
194}
195
196/// An [`Entry`] for an existing key-value pair
197///
198/// This is not exported to bindings users as bindings provide alternate accessors rather than exposing maps directly.
199pub struct OccupiedEntry<'a, K: Hash + Ord, V> {
200	underlying_entry: OccupiedHashMapEntry<'a, K, V>,
201	keys: &'a mut Vec<K>,
202}
203
204/// A mutable reference to a position in the map. This can be used to reference, add, or update the
205/// value at a fixed key.
206///
207/// This is not exported to bindings users as bindings provide alternate accessors rather than exposing maps directly.
208pub enum Entry<'a, K: Hash + Ord, V> {
209	/// A mutable reference to a position within the map where there is no value.
210	Vacant(VacantEntry<'a, K, V>),
211	/// A mutable reference to a position within the map where there is currently a value.
212	Occupied(OccupiedEntry<'a, K, V>),
213}
214
215impl<'a, K: Hash + Ord, V> VacantEntry<'a, K, V> {
216	/// Insert a value into the position described by this entry.
217	pub fn insert(self, value: V) -> &'a mut V {
218		self.keys.push(self.key);
219		self.underlying_entry.insert(value)
220	}
221}
222
223impl<'a, K: Hash + Ord, V> OccupiedEntry<'a, K, V> {
224	/// Remove the value at the position described by this entry.
225	pub fn remove_entry(self) -> (K, V) {
226		let res = self.underlying_entry.remove_entry();
227		let idx =
228			self.keys.iter().position(|k| k == &res.0).expect("map and keys must be consistent");
229		self.keys.remove(idx);
230		res
231	}
232
233	/// Get a reference to the key at the position described by this entry.
234	pub fn key(&self) -> &K {
235		self.underlying_entry.key()
236	}
237
238	/// Get a reference to the value at the position described by this entry.
239	pub fn get(&self) -> &V {
240		self.underlying_entry.get()
241	}
242
243	/// Get a mutable reference to the value at the position described by this entry.
244	pub fn get_mut(&mut self) -> &mut V {
245		self.underlying_entry.get_mut()
246	}
247
248	/// Consume this entry, returning a mutable reference to the value at the position described by
249	/// this entry.
250	pub fn into_mut(self) -> &'a mut V {
251		self.underlying_entry.into_mut()
252	}
253}