Make setdefault atomic

This commit is contained in:
Noah committed 2020-09-24 23:51:33 -05:00
1 parent b835321664
commit 131736eecf
3 files changed
+41 -18

No files matched your search

-2
View File
@@ -368,8 +368,6 @@ class DictTest(unittest.TestCase):
x.fail = True
self.assertRaises(Exc, d.setdefault, x, [])
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_setdefault_atomic(self):
# Issue #13521: setdefault() calls __hash__ and __eq__ only once.
class Hashed(object):
+39 -8
View File
@@ -157,6 +157,7 @@ impl<T> DictInner<T> {
hash_value: HashValue,
key: PyObjectRef,
value: T,
index_entry: IndexEntry,
) {
let entry = DictEntry {
hash: hash_value,
@@ -168,6 +169,12 @@ impl<T> DictInner<T> {
self.entries.push(entry);
self.indices[index] = entry_index as i64;
self.used += 1;
if let IndexEntry::Free = index_entry {
self.filled += 1;
if let Some(new_size) = self.should_resize() {
self.resize(new_size)
}
}
}
fn size(&self) -> DictSize {
@@ -223,13 +230,7 @@ impl<T: Clone> Dict<T> {
} else {
// New key:
let mut inner = self.borrow_value_mut();
inner.unchecked_push(index_index, hash, key.into_pyobject(vm), value);
if let IndexEntry::Free = entry_index {
inner.filled += 1;
if let Some(new_size) = inner.should_resize() {
inner.resize(new_size)
}
}
inner.unchecked_push(index_index, hash, key.into_pyobject(vm), value, entry_index);
break None;
}
};
@@ -328,13 +329,43 @@ impl<T: Clone> Dict<T> {
}
} else {
let mut inner = self.borrow_value_mut();
inner.unchecked_push(index_index, hash, key.clone(), value);
inner.unchecked_push(index_index, hash, key.clone(), value, entry);
break None;
}
};
Ok(())
}
pub fn setdefault<F>(&self, vm: &VirtualMachine, key: PyObjectRef, default: F) -> PyResult<T>
where
F: FnOnce() -> T,
{
let hash = key.key_hash(vm)?;
let res = loop {
let lookup = self.lookup(vm, &key, hash, None)?;
let (entry, index_index) = lookup;
if let IndexEntry::Index(index) = entry {
let inner = self.borrow_value();
if let Some(entry) = inner.entries.get(index) {
if entry.index == index_index {
break entry.value.clone();
} else {
// stuff shifted around, let's try again
}
} else {
// The dict was changed since we did lookup, let's try again.
continue;
}
} else {
let value = default();
let mut inner = self.borrow_value_mut();
inner.unchecked_push(index_index, hash, key, value.clone(), entry);
break value;
}
};
Ok(res)
}
pub fn len(&self) -> usize {
self.borrow_value().used
}
+2 -8
View File
@@ -299,14 +299,8 @@ impl PyDict {
default: OptionalArg<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult {
match self.entries.get(vm, &key)? {
Some(value) => Ok(value),
None => {
let set_value = default.unwrap_or_none(vm);
self.entries.insert(vm, key, set_value.clone())?;
Ok(set_value)
}
}
self.entries
.setdefault(vm, key, || default.unwrap_or_none(vm))
}
#[pymethod]