Skip to content

Commit 7ee2078

Browse files
authored
Merge pull request #76 from dtolnay/entry
Implement Entry API, Rebased #42
2 parents 4202182 + dbdfd29 commit 7ee2078

File tree

2 files changed

+406
-29
lines changed

2 files changed

+406
-29
lines changed

src/lib.rs

Lines changed: 300 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,24 @@ impl<K: Hash + Eq, V> LinkedHashMap<K, V> {
124124
}
125125

126126
impl<K, V, S> LinkedHashMap<K, V, S> {
127+
#[inline]
128+
fn detach(&mut self, node: *mut Node<K, V>) {
129+
unsafe {
130+
(*(*node).prev).next = (*node).next;
131+
(*(*node).next).prev = (*node).prev;
132+
}
133+
}
134+
135+
#[inline]
136+
fn attach(&mut self, node: *mut Node<K, V>) {
137+
unsafe {
138+
(*node).next = (*self.head).next;
139+
(*node).prev = self.head;
140+
(*self.head).next = node;
141+
(*(*node).next).prev = node;
142+
}
143+
}
144+
127145
// Caller must check `!self.head.is_null()`
128146
unsafe fn drop_entries(&mut self) {
129147
let mut cur = (*self.head).next;
@@ -145,6 +163,17 @@ impl<K, V, S> LinkedHashMap<K, V, S> {
145163
self.free = ptr::null_mut();
146164
}
147165
}
166+
167+
fn ensure_guard_node(&mut self) {
168+
if self.head.is_null() {
169+
// allocate the guard node if not present
170+
unsafe {
171+
self.head = Box::into_raw(Box::new(mem::uninitialized()));
172+
(*self.head).next = self.head;
173+
(*self.head).prev = self.head;
174+
}
175+
}
176+
}
148177
}
149178

150179
impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
@@ -182,6 +211,79 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
182211
self.clear_free_list();
183212
}
184213

214+
/// Gets the given key's corresponding entry in the map for in-place manipulation.
215+
///
216+
/// # Examples
217+
///
218+
/// ```
219+
/// use linked_hash_map::LinkedHashMap;
220+
///
221+
/// let mut letters = LinkedHashMap::new();
222+
///
223+
/// for ch in "a short treatise on fungi".chars() {
224+
/// let counter = letters.entry(ch).or_insert(0);
225+
/// *counter += 1;
226+
/// }
227+
///
228+
/// assert_eq!(letters[&'s'], 2);
229+
/// assert_eq!(letters[&'t'], 3);
230+
/// assert_eq!(letters[&'u'], 1);
231+
/// assert_eq!(letters.get(&'y'), None);
232+
/// ```
233+
pub fn entry(&mut self, k: K) -> Entry<K, V, S> {
234+
let self_ptr: *mut Self = self;
235+
236+
if let Some(entry) = self.map.get_mut(&KeyRef{k: &k}) {
237+
return Entry::Occupied(OccupiedEntry {
238+
entry: *entry,
239+
map: self_ptr,
240+
marker: marker::PhantomData,
241+
});
242+
}
243+
244+
Entry::Vacant(VacantEntry {
245+
key: k,
246+
map: self,
247+
})
248+
}
249+
250+
/// Returns an iterator visiting all entries in insertion order.
251+
/// Iterator element type is `OccupiedEntry<K, V, S>`. Allows for removal
252+
/// as well as replacing the entry.
253+
///
254+
/// # Examples
255+
/// ```
256+
/// use linked_hash_map::LinkedHashMap;
257+
///
258+
/// let mut map = LinkedHashMap::new();
259+
/// map.insert("a", 10);
260+
/// map.insert("c", 30);
261+
/// map.insert("b", 20);
262+
///
263+
/// {
264+
/// let mut iter = map.entries();
265+
/// let mut entry = iter.next().unwrap();
266+
/// assert_eq!(&"a", entry.key());
267+
/// *entry.get_mut() = 17;
268+
/// }
269+
///
270+
/// assert_eq!(&17, map.get(&"a").unwrap());
271+
/// ```
272+
pub fn entries(&mut self) -> Entries<K, V, S> {
273+
let head = if ! self.head.is_null() {
274+
unsafe { (*self.head).prev }
275+
} else {
276+
ptr::null_mut()
277+
};
278+
Entries {
279+
map: self,
280+
head: head,
281+
tail: self.head,
282+
remaining: self.len(),
283+
marker: marker::PhantomData,
284+
}
285+
}
286+
185287
/// Inserts a key-value pair into the map. If the key already existed, the old value is
186288
/// returned.
187289
///
@@ -197,14 +299,8 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
197299
/// assert_eq!(map[&2], "b");
198300
/// ```
199301
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
200-
if self.head.is_null() {
201-
// allocate the guard node if not present
202-
unsafe {
203-
self.head = Box::into_raw(Box::new(mem::uninitialized()));
204-
(*self.head).next = self.head;
205-
(*self.head).prev = self.head;
206-
}
207-
}
302+
self.ensure_guard_node();
303+
208304
let (node, old_val) = match self.map.get(&KeyRef{k: &k}) {
209305
Some(node) => {
210306
let old_val = unsafe { ptr::replace(&mut (**node).value, v) };
@@ -612,26 +708,6 @@ impl<'a, K, V, S, Q: ?Sized> IndexMut<&'a Q> for LinkedHashMap<K, V, S>
612708
}
613709
}
614710

615-
impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
616-
#[inline]
617-
fn detach(&mut self, node: *mut Node<K, V>) {
618-
unsafe {
619-
(*(*node).prev).next = (*node).next;
620-
(*(*node).next).prev = (*node).prev;
621-
}
622-
}
623-
624-
#[inline]
625-
fn attach(&mut self, node: *mut Node<K, V>) {
626-
unsafe {
627-
(*node).next = (*self.head).next;
628-
(*node).prev = self.head;
629-
(*self.head).next = node;
630-
(*(*node).next).prev = node;
631-
}
632-
}
633-
}
634-
635711
impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher + Clone> Clone for LinkedHashMap<K, V, S> {
636712
fn clone(&self) -> Self {
637713
let mut map = Self::with_hasher(self.map.hasher().clone());
@@ -760,18 +836,32 @@ pub struct IntoIter<K, V> {
760836
marker: marker::PhantomData<(K, V)>,
761837
}
762838

839+
/// An insertion-order iterator over a `LinkedHashMap`'s entries represented as
840+
/// an `OccupiedEntry`.
841+
pub struct Entries<'a, K: 'a, V: 'a, S: 'a = hash_map::RandomState> {
842+
map: *mut LinkedHashMap<K, V, S>,
843+
head: *mut Node<K, V>,
844+
tail: *mut Node<K, V>,
845+
remaining: usize,
846+
marker: marker::PhantomData<(&'a K, &'a mut V, &'a S)>,
847+
}
848+
763849
unsafe impl<'a, K, V> Send for Iter<'a, K, V> where K: Send, V: Send {}
764850

765851
unsafe impl<'a, K, V> Send for IterMut<'a, K, V> where K: Send, V: Send {}
766852

767853
unsafe impl<K, V> Send for IntoIter<K, V> where K: Send, V: Send {}
768854

855+
unsafe impl<'a, K, V, S> Send for Entries<'a, K, V, S> where K: Send, V: Send, S: Send {}
856+
769857
unsafe impl<'a, K, V> Sync for Iter<'a, K, V> where K: Sync, V: Sync {}
770858

771859
unsafe impl<'a, K, V> Sync for IterMut<'a, K, V> where K: Sync, V: Sync {}
772860

773861
unsafe impl<K, V> Sync for IntoIter<K, V> where K: Sync, V: Sync {}
774862

863+
unsafe impl<'a, K, V, S> Sync for Entries<'a, K, V, S> where K: Sync, V: Sync, S: Sync {}
864+
775865
impl<'a, K, V> Clone for Iter<'a, K, V> {
776866
fn clone(&self) -> Self { Iter { ..*self } }
777867
}
@@ -874,6 +964,32 @@ impl<K, V> Iterator for IntoIter<K, V> {
874964
}
875965
}
876966

967+
impl<'a, K, V, S: BuildHasher> Iterator for Entries<'a, K, V, S> {
968+
type Item = OccupiedEntry<'a, K, V, S>;
969+
970+
fn next(&mut self) -> Option<OccupiedEntry<'a, K, V, S>> {
971+
if self.head == self.tail {
972+
None
973+
} else {
974+
self.remaining -= 1;
975+
unsafe {
976+
let r = Some(OccupiedEntry {
977+
map: self.map,
978+
entry: self.head,
979+
marker: marker::PhantomData,
980+
});
981+
982+
self.head = (*self.head).prev;
983+
r
984+
}
985+
}
986+
}
987+
988+
fn size_hint(&self) -> (usize, Option<usize>) {
989+
(self.remaining, Some(self.remaining))
990+
}
991+
}
992+
877993
impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> {
878994
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
879995
if self.head == self.tail {
@@ -1029,6 +1145,162 @@ impl<K: Hash + Eq, V, S: BuildHasher> IntoIterator for LinkedHashMap<K, V, S> {
10291145
}
10301146
}
10311147

1148+
/// A view into a single location in a map, which may be vacant or occupied.
1149+
pub enum Entry<'a, K: 'a, V: 'a, S: 'a = hash_map::RandomState> {
1150+
/// An occupied Entry.
1151+
Occupied(OccupiedEntry<'a, K, V, S>),
1152+
/// A vacant Entry.
1153+
Vacant(VacantEntry<'a, K, V, S>),
1154+
}
1155+
1156+
/// A view into a single occupied location in a `LinkedHashMap`.
1157+
pub struct OccupiedEntry<'a, K: 'a, V: 'a, S: 'a = hash_map::RandomState> {
1158+
entry: *mut Node<K, V>,
1159+
map: *mut LinkedHashMap<K, V, S>,
1160+
marker: marker::PhantomData<&'a K>,
1161+
}
1162+
1163+
/// A view into a single empty location in a `LinkedHashMap`.
1164+
pub struct VacantEntry<'a, K: 'a, V: 'a, S: 'a = hash_map::RandomState> {
1165+
key: K,
1166+
map: &'a mut LinkedHashMap<K, V, S>,
1167+
}
1168+
1169+
impl<'a, K: Hash + Eq, V, S: BuildHasher> Entry<'a, K, V, S> {
1170+
/// Returns the entry key
1171+
///
1172+
/// # Examples
1173+
///
1174+
/// ```
1175+
/// use linked_hash_map::LinkedHashMap;
1176+
///
1177+
/// let mut map = LinkedHashMap::<String, u32>::new();
1178+
///
1179+
/// assert_eq!("hello", map.entry("hello".to_string()).key());
1180+
/// ```
1181+
pub fn key(&self) -> &K {
1182+
match *self {
1183+
Entry::Occupied(ref e) => e.key(),
1184+
Entry::Vacant(ref e) => e.key(),
1185+
}
1186+
}
1187+
1188+
/// Ensures a value is in the entry by inserting the default if empty, and returns
1189+
/// a mutable reference to the value in the entry.
1190+
pub fn or_insert(self, default: V) -> &'a mut V {
1191+
match self {
1192+
Entry::Occupied(entry) => entry.into_mut(),
1193+
Entry::Vacant(entry) => entry.insert(default),
1194+
}
1195+
}
1196+
1197+
/// Ensures a value is in the entry by inserting the result of the default function if empty,
1198+
/// and returns a mutable reference to the value in the entry.
1199+
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
1200+
match self {
1201+
Entry::Occupied(entry) => entry.into_mut(),
1202+
Entry::Vacant(entry) => entry.insert(default()),
1203+
}
1204+
}
1205+
}
1206+
1207+
impl<'a, K: Hash + Eq, V, S: BuildHasher> OccupiedEntry<'a, K, V, S> {
1208+
/// Gets a reference to the entry key
1209+
///
1210+
/// # Examples
1211+
///
1212+
/// ```
1213+
/// use linked_hash_map::LinkedHashMap;
1214+
///
1215+
/// let mut map = LinkedHashMap::new();
1216+
///
1217+
/// map.insert("foo".to_string(), 1);
1218+
/// assert_eq!("foo", map.entry("foo".to_string()).key());
1219+
/// ```
1220+
pub fn key(&self) -> &K {
1221+
unsafe { &(*self.entry).key }
1222+
}
1223+
1224+
/// Gets a reference to the value in the entry.
1225+
pub fn get(&self) -> &V {
1226+
unsafe { &(*self.entry).value }
1227+
}
1228+
1229+
/// Gets a mutable reference to the value in the entry.
1230+
pub fn get_mut(&mut self) -> &mut V {
1231+
unsafe { &mut (*self.entry).value }
1232+
}
1233+
1234+
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
1235+
/// with a lifetime bound to the map itself
1236+
pub fn into_mut(self) -> &'a mut V {
1237+
unsafe { &mut (*self.entry).value }
1238+
}
1239+
1240+
/// Sets the value of the entry, and returns the entry's old value
1241+
pub fn insert(&mut self, value: V) -> V {
1242+
unsafe {
1243+
(*self.map).ensure_guard_node();
1244+
1245+
let old_val = mem::replace(&mut (*self.entry).value, value);
1246+
let node_ptr: *mut Node<K, V> = self.entry;
1247+
1248+
// Existing node, just update LRU position
1249+
(*self.map).detach(node_ptr);
1250+
(*self.map).attach(node_ptr);
1251+
1252+
old_val
1253+
}
1254+
}
1255+
1256+
/// Takes the value out of the entry, and returns it
1257+
pub fn remove(self) -> V {
1258+
unsafe { (*self.map).remove(&(*self.entry).key) }.unwrap()
1259+
}
1260+
}
1261+
1262+
impl<'a, K: 'a + Hash + Eq, V: 'a, S: BuildHasher> VacantEntry<'a, K, V, S> {
1263+
/// Gets a reference to the entry key
1264+
///
1265+
/// # Examples
1266+
///
1267+
/// ```
1268+
/// use linked_hash_map::LinkedHashMap;
1269+
///
1270+
/// let mut map = LinkedHashMap::<String, u32>::new();
1271+
///
1272+
/// assert_eq!("foo", map.entry("foo".to_string()).key());
1273+
/// ```
1274+
pub fn key(&self) -> &K {
1275+
&self.key
1276+
}
1277+
1278+
/// Sets the value of the entry with the VacantEntry's key,
1279+
/// and returns a mutable reference to it
1280+
pub fn insert(self, value: V) -> &'a mut V {
1281+
self.map.ensure_guard_node();
1282+
1283+
let node = if self.map.free.is_null() {
1284+
Box::into_raw(Box::new(Node::new(self.key, value)))
1285+
} else {
1286+
// use a recycled box
1287+
unsafe {
1288+
let free = self.map.free;
1289+
self.map.free = (*free).next;
1290+
ptr::write(free, Node::new(self.key, value));
1291+
free
1292+
}
1293+
};
1294+
1295+
let keyref = unsafe { &(*node).key };
1296+
1297+
self.map.attach(node);
1298+
1299+
let ret = self.map.map.entry(KeyRef{k: keyref}).or_insert(node);
1300+
unsafe { &mut (**ret).value }
1301+
}
1302+
}
1303+
10321304
#[cfg(all(feature = "nightly", test))]
10331305
mod bench {
10341306
extern crate test;

0 commit comments

Comments
 (0)