Skip to content

Commit 7481524

Browse files
committed
auto merge of #5528 : thestinger/rust/find_mut, r=brson
This currently requires workarounds for the borrow checker not being flow-sensitive for `LinearMap` and `TrieMap`, but it can already be expressed for `TreeMap` and `SmallIntMap` without that.
2 parents 47ddb59 + e8bf0a4 commit 7481524

File tree

6 files changed

+135
-9
lines changed

6 files changed

+135
-9
lines changed

src/libcore/container.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,12 @@ pub trait Map<K, V>: Mutable {
3838
/// Iterate over the map and mutate the contained values
3939
fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool);
4040

41-
/// Return the value corresponding to the key in the map
41+
/// Return a reference to the value corresponding to the key
4242
fn find(&self, key: &K) -> Option<&'self V>;
4343

44+
/// Return a mutable reference to the value corresponding to the key
45+
fn find_mut(&mut self, key: &K) -> Option<&'self mut V>;
46+
4447
/// Insert a key-value pair into the map. An existing value for a
4548
/// key is replaced by the new value. Return true if the key did
4649
/// not already exist in the map.

src/libcore/hashmap.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub mod linear {
2424
use rand;
2525
use uint;
2626
use vec;
27+
use util::unreachable;
2728

2829
static INITIAL_CAPACITY: uint = 32u; // 2^5
2930

@@ -192,6 +193,14 @@ pub mod linear {
192193
}
193194
}
194195
196+
#[inline(always)]
197+
fn mut_value_for_bucket(&mut self, idx: uint) -> &'self mut V {
198+
match self.buckets[idx] {
199+
Some(ref mut bkt) => &mut bkt.value,
200+
None => unreachable()
201+
}
202+
}
203+
195204
/// Inserts the key value pair into the buckets.
196205
/// Assumes that there will be a bucket.
197206
/// True if there was no previous entry with that key
@@ -338,14 +347,25 @@ pub mod linear {
338347
}
339348
}
340349
341-
/// Return the value corresponding to the key in the map
350+
/// Return a reference to the value corresponding to the key
342351
fn find(&self, k: &K) -> Option<&'self V> {
343352
match self.bucket_for_key(k) {
344353
FoundEntry(idx) => Some(self.value_for_bucket(idx)),
345354
TableFull | FoundHole(_) => None,
346355
}
347356
}
348357
358+
/// Return a mutable reference to the value corresponding to the key
359+
fn find_mut(&mut self, k: &K) -> Option<&'self mut V> {
360+
let idx = match self.bucket_for_key(k) {
361+
FoundEntry(idx) => idx,
362+
TableFull | FoundHole(_) => return None
363+
};
364+
unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker
365+
Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx)))
366+
}
367+
}
368+
349369
/// Insert a key-value pair into the map. An existing value for a
350370
/// key is replaced by the new value. Return true if the key did
351371
/// not already exist in the map.
@@ -655,6 +675,19 @@ pub mod linear {
655675
fail_unless!(*m.get(&2) == 4);
656676
}
657677

678+
#[test]
679+
fn test_find_mut() {
680+
let mut m = LinearMap::new();
681+
fail_unless!(m.insert(1, 12));
682+
fail_unless!(m.insert(2, 8));
683+
fail_unless!(m.insert(5, 14));
684+
let new = 100;
685+
match m.find_mut(&5) {
686+
None => fail!(), Some(x) => *x = new
687+
}
688+
assert_eq!(m.find(&5), Some(&new));
689+
}
690+
658691
#[test]
659692
pub fn test_insert_overwrite() {
660693
let mut m = LinearMap::new();

src/libcore/trie.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! A radix trie for storing integers in sorted order
11+
//! An ordered map and set for integer keys implemented as a radix trie
1212
1313
use prelude::*;
1414

@@ -90,7 +90,7 @@ impl<T> Map<uint, T> for TrieMap<T> {
9090
self.root.mutate_values(f);
9191
}
9292

93-
/// Return the value corresponding to the key in the map
93+
/// Return a reference to the value corresponding to the key
9494
#[inline(hint)]
9595
fn find(&self, key: &uint) -> Option<&'self T> {
9696
let mut node: &'self TrieNode<T> = &self.root;
@@ -111,6 +111,12 @@ impl<T> Map<uint, T> for TrieMap<T> {
111111
}
112112
}
113113

114+
/// Return a mutable reference to the value corresponding to the key
115+
#[inline(always)]
116+
fn find_mut(&mut self, key: &uint) -> Option<&'self mut T> {
117+
find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1)
118+
}
119+
114120
/// Insert a key-value pair into the map. An existing value for a
115121
/// key is replaced by the new value. Return true if the key did
116122
/// not already exist in the map.
@@ -276,6 +282,17 @@ fn chunk(n: uint, idx: uint) -> uint {
276282
(n >> sh) & MASK
277283
}
278284

285+
fn find_mut<T>(child: &'r mut Child<T>, key: uint, idx: uint) -> Option<&'r mut T> {
286+
unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker
287+
(match *child {
288+
External(_, ref value) => Some(cast::transmute_mut(value)),
289+
Internal(ref x) => find_mut(cast::transmute_mut(&x.children[chunk(key, idx)]),
290+
key, idx + 1),
291+
Nothing => None
292+
}).map_consume(|x| cast::transmute_mut_region(x))
293+
}
294+
}
295+
279296
fn insert<T>(count: &mut uint, child: &mut Child<T>, key: uint, value: T,
280297
idx: uint) -> bool {
281298
let mut tmp = Nothing;
@@ -357,8 +374,22 @@ pub fn check_integrity<T>(trie: &TrieNode<T>) {
357374
#[cfg(test)]
358375
mod tests {
359376
use super::*;
377+
use core::option::{Some, None};
360378
use uint;
361379

380+
#[test]
381+
fn test_find_mut() {
382+
let mut m = TrieMap::new();
383+
fail_unless!(m.insert(1, 12));
384+
fail_unless!(m.insert(2, 8));
385+
fail_unless!(m.insert(5, 14));
386+
let new = 100;
387+
match m.find_mut(&5) {
388+
None => fail!(), Some(x) => *x = new
389+
}
390+
assert_eq!(m.find(&5), Some(&new));
391+
}
392+
362393
#[test]
363394
fn test_step() {
364395
let mut trie = TrieMap::new();

src/libstd/smallintmap.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl<V> Map<uint, V> for SmallIntMap<V> {
8686
self.each(|&(_, v)| blk(v))
8787
}
8888

89-
/// Visit all key-value pairs in order
89+
/// Iterate over the map and mutate the contained values
9090
fn mutate_values(&mut self, it: &fn(&uint, &'self mut V) -> bool) {
9191
for uint::range(0, self.v.len()) |i| {
9292
match self.v[i] {
@@ -96,7 +96,7 @@ impl<V> Map<uint, V> for SmallIntMap<V> {
9696
}
9797
}
9898

99-
/// Iterate over the map and mutate the contained values
99+
/// Return a reference to the value corresponding to the key
100100
fn find(&self, key: &uint) -> Option<&'self V> {
101101
if *key < self.v.len() {
102102
match self.v[*key] {
@@ -108,6 +108,18 @@ impl<V> Map<uint, V> for SmallIntMap<V> {
108108
}
109109
}
110110

111+
/// Return a mutable reference to the value corresponding to the key
112+
fn find_mut(&mut self, key: &uint) -> Option<&'self mut V> {
113+
if *key < self.v.len() {
114+
match self.v[*key] {
115+
Some(ref mut value) => Some(value),
116+
None => None
117+
}
118+
} else {
119+
None
120+
}
121+
}
122+
111123
/// Insert a key-value pair into the map. An existing value for a
112124
/// key is replaced by the new value. Return true if the key did
113125
/// not already exist in the map.
@@ -160,6 +172,20 @@ pub impl<V:Copy> SmallIntMap<V> {
160172
#[cfg(test)]
161173
mod tests {
162174
use super::SmallIntMap;
175+
use core::prelude::*;
176+
177+
#[test]
178+
fn test_find_mut() {
179+
let mut m = SmallIntMap::new();
180+
fail_unless!(m.insert(1, 12));
181+
fail_unless!(m.insert(2, 8));
182+
fail_unless!(m.insert(5, 14));
183+
let new = 100;
184+
match m.find_mut(&5) {
185+
None => fail!(), Some(x) => *x = new
186+
}
187+
assert_eq!(m.find(&5), Some(&new));
188+
}
163189

164190
#[test]
165191
fn test_len() {

src/libstd/treemap.rs

+34-3
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl<K: TotalOrd, V> Map<K, V> for TreeMap<K, V> {
135135
mutate_values(&mut self.root, f);
136136
}
137137

138-
/// Return the value corresponding to the key in the map
138+
/// Return a reference to the value corresponding to the key
139139
fn find(&self, key: &K) -> Option<&'self V> {
140140
let mut current: &'self Option<~TreeNode<K, V>> = &self.root;
141141
loop {
@@ -152,6 +152,12 @@ impl<K: TotalOrd, V> Map<K, V> for TreeMap<K, V> {
152152
}
153153
}
154154

155+
/// Return a mutable reference to the value corresponding to the key
156+
#[inline(always)]
157+
fn find_mut(&mut self, key: &K) -> Option<&'self mut V> {
158+
find_mut(&mut self.root, key)
159+
}
160+
155161
/// Insert a key-value pair into the map. An existing value for a
156162
/// key is replaced by the new value. Return true if the key did
157163
/// not already exist in the map.
@@ -584,8 +590,20 @@ fn split<K: TotalOrd, V>(node: &mut ~TreeNode<K, V>) {
584590
}
585591
}
586592

587-
fn insert<K: TotalOrd, V>(node: &mut Option<~TreeNode<K, V>>, key: K,
588-
value: V) -> bool {
593+
fn find_mut<K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>, key: &K) -> Option<&'r mut V> {
594+
match *node {
595+
Some(ref mut x) => {
596+
match key.cmp(&x.key) {
597+
Less => find_mut(&mut x.left, key),
598+
Greater => find_mut(&mut x.right, key),
599+
Equal => Some(&mut x.value),
600+
}
601+
}
602+
None => None
603+
}
604+
}
605+
606+
fn insert<K: TotalOrd, V>(node: &mut Option<~TreeNode<K, V>>, key: K, value: V) -> bool {
589607
match *node {
590608
Some(ref mut save) => {
591609
match key.cmp(&save.key) {
@@ -716,6 +734,19 @@ mod test_treemap {
716734
fail_unless!(m.find(&2) == None);
717735
}
718736

737+
#[test]
738+
fn test_find_mut() {
739+
let mut m = TreeMap::new();
740+
fail_unless!(m.insert(1, 12));
741+
fail_unless!(m.insert(2, 8));
742+
fail_unless!(m.insert(5, 14));
743+
let new = 100;
744+
match m.find_mut(&5) {
745+
None => fail!(), Some(x) => *x = new
746+
}
747+
assert_eq!(m.find(&5), Some(&new));
748+
}
749+
719750
#[test]
720751
fn insert_replace() {
721752
let mut m = TreeMap::new();

src/test/run-pass/class-impl-very-parameterized-trait.rs

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ impl<T> Map<int, T> for cat<T> {
9898
}
9999
}
100100
101+
fn find_mut(&mut self, k: &int) -> Option<&'self mut T> { fail!() }
102+
101103
fn remove(&mut self, k: &int) -> bool {
102104
if self.find(k).is_some() {
103105
self.meows -= *k; true

0 commit comments

Comments
 (0)