Skip to content

Commit 1d5adc4

Browse files
committed
Add built-in dict.pop
1 parent b9082b0 commit 1d5adc4

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

tests/snippets/dict.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,11 @@ def __eq__(self, other):
166166

167167
y.update(y)
168168
assert y == {'a': 2, 'b': 12, 'c': 19, 'd': -1} # hasn't changed
169+
170+
x = {1: 'a', '1': None}
171+
assert x.pop(1) == 'a'
172+
assert x.pop('1') is None
173+
assert x == {}
174+
175+
with assertRaises(KeyError):
176+
x.pop("not here")

vm/src/dictdatatype.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,18 @@ impl<T: Clone> Dict<T> {
8787
}
8888
}
8989

90+
fn unchecked_get(&self, index: usize) -> T {
91+
if let Some(entry) = &self.entries[index] {
92+
entry.value.clone()
93+
} else {
94+
panic!("Lookup returned invalid index into entries!");
95+
}
96+
}
97+
9098
/// Retrieve a key
9199
pub fn get(&self, vm: &VirtualMachine, key: &PyObjectRef) -> PyResult<Option<T>> {
92100
if let LookupResult::Existing(index) = self.lookup(vm, key)? {
93-
if let Some(entry) = &self.entries[index] {
94-
Ok(Some(entry.value.clone()))
95-
} else {
96-
panic!("Lookup returned invalid index into entries!");
97-
}
101+
Ok(Some(self.unchecked_get(index)))
98102
} else {
99103
Ok(None)
100104
}
@@ -190,6 +194,19 @@ impl<T: Clone> Dict<T> {
190194
// warn!("Perturb value: {}", i);
191195
}
192196
}
197+
198+
/// Retrieve and delete a key
199+
pub fn pop(&mut self, vm: &VirtualMachine, key: &PyObjectRef) -> PyResult<T> {
200+
if let LookupResult::Existing(index) = self.lookup(vm, key)? {
201+
let value = self.unchecked_get(index);
202+
self.entries[index] = None;
203+
self.size -= 1;
204+
Ok(value)
205+
} else {
206+
let key_repr = vm.to_pystr(key)?;
207+
Err(vm.new_key_error(format!("Key not found: {}", key_repr)))
208+
}
209+
}
193210
}
194211

195212
enum LookupResult {

vm/src/obj/objdict.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ impl PyDictRef {
228228
PyDictRef::merge(&self.entries, dict_obj, kwargs, vm)
229229
}
230230

231+
fn pop(self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult {
232+
self.entries.borrow_mut().pop(vm, &key)
233+
}
234+
231235
/// Take a python dictionary and convert it to attributes.
232236
pub fn to_attributes(self) -> PyAttributes {
233237
let mut attrs = PyAttributes::new();
@@ -458,6 +462,7 @@ pub fn init(context: &PyContext) {
458462
"get" => context.new_rustfunc(PyDictRef::get),
459463
"copy" => context.new_rustfunc(PyDictRef::copy),
460464
"update" => context.new_rustfunc(PyDictRef::update),
465+
"pop" => context.new_rustfunc(PyDictRef::pop),
461466
});
462467

463468
PyDictKeys::extend_class(context, &context.dictkeys_type);

0 commit comments

Comments
 (0)