make dict delete remains order

This commit is contained in:
eldpswp99
2021-08-17 20:41:37 +09:00
parent 4e9f9ff129
commit ce99057c81
4 changed files with 49 additions and 39 deletions

View File

@@ -474,8 +474,6 @@ class DictTest(unittest.TestCase):
for i in d:
d[i+1] = 1
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_mutating_iteration_delete(self):
# change dict content during iteration
d = {}
@@ -485,8 +483,6 @@ class DictTest(unittest.TestCase):
del d[0]
d[0] = 0
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_mutating_iteration_delete_over_values(self):
# change dict content during iteration
d = {}
@@ -496,8 +492,6 @@ class DictTest(unittest.TestCase):
del d[0]
d[0] = 0
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_mutating_iteration_delete_over_items(self):
# change dict content during iteration
d = {}

View File

@@ -360,7 +360,7 @@ impl PyDict {
#[pymethod]
fn popitem(&self, vm: &VirtualMachine) -> PyResult {
if let Some((key, value)) = self.entries.pop_back() {
if let Some((key, value)) = self.entries.pop_back(vm) {
Ok(vm.ctx.new_tuple(vec![key, value]))
} else {
let err_msg = vm.ctx.new_str("popitem(): dictionary is empty");

View File

@@ -226,7 +226,7 @@ impl PySetInner {
fn pop(&self, vm: &VirtualMachine) -> PyResult {
// TODO: should be pop_front, but that requires rearranging every index
if let Some((key, _)) = self.content.pop_back() {
if let Some((key, _)) = self.content.pop_back(vm) {
Ok(key)
} else {
let err_msg = vm.ctx.new_str("pop from an empty set");

View File

@@ -221,8 +221,8 @@ impl<T: Clone> Dict<T> {
/// Store a key
pub fn insert<K>(&self, vm: &VirtualMachine, key: K, value: T) -> PyResult<()>
where
K: DictKey,
where
K: DictKey,
{
let hash = key.key_hash(vm)?;
let _removed = loop {
@@ -320,8 +320,8 @@ impl<T: Clone> Dict<T> {
/// Delete a key
pub fn delete<K>(&self, vm: &VirtualMachine, key: K) -> PyResult<()>
where
K: DictKey,
where
K: DictKey,
{
if self.delete_if_exists(vm, &key)? {
Ok(())
@@ -331,8 +331,8 @@ impl<T: Clone> Dict<T> {
}
pub fn delete_if_exists<K>(&self, vm: &VirtualMachine, key: &K) -> PyResult<bool>
where
K: DictKey,
where
K: DictKey,
{
let hash = key.key_hash(vm)?;
let deleted = loop {
@@ -376,9 +376,9 @@ impl<T: Clone> Dict<T> {
}
pub fn setdefault<K, F>(&self, vm: &VirtualMachine, key: K, default: F) -> PyResult<T>
where
K: DictKey,
F: FnOnce() -> T,
where
K: DictKey,
F: FnOnce() -> T,
{
let hash = key.key_hash(vm)?;
let res = loop {
@@ -419,9 +419,9 @@ impl<T: Clone> Dict<T> {
key: K,
default: F,
) -> PyResult<(PyObjectRef, T)>
where
K: DictKey,
F: FnOnce() -> T,
where
K: DictKey,
F: FnOnce() -> T,
{
let hash = key.key_hash(vm)?;
let res = loop {
@@ -489,9 +489,12 @@ impl<T: Clone> Dict<T> {
}
pub fn keys(&self) -> Vec<PyObjectRef> {
self.read().entries.iter()
self.read()
.entries
.iter()
.filter(|v| v.is_some())
.map(|v| v.as_ref().unwrap().key.clone()).collect()
.map(|v| v.as_ref().unwrap().key.clone())
.collect()
}
/// Lookup the index for the given key.
@@ -562,7 +565,8 @@ impl<T: Clone> Dict<T> {
return Ok(None);
};
let mut inner = self.write();
if matches!(inner.entries.get(entry_index), Some(entry) if entry.as_ref().unwrap().index == index_index) {
if matches!(inner.entries.get(entry_index), Some(entry) if entry.as_ref().unwrap().index == index_index)
{
// all good
} else {
// The dict was changed since we did lookup. Let's try again.
@@ -570,14 +574,9 @@ impl<T: Clone> Dict<T> {
};
inner.indices[index_index] = IndexEntry::DUMMY;
inner.used -= 1;
let removed = if entry_index == inner.used {
inner.entries.pop().unwrap()
} else {
let last_index = inner.entries.last().unwrap().as_ref().unwrap().index;
let removed = inner.entries.swap_remove(entry_index);
inner.indices[last_index] = entry_index as i64;
removed
};
let removed = inner.entries[entry_index].clone();
inner.entries[entry_index] = None;
Ok(Some(removed.unwrap()))
}
@@ -595,14 +594,31 @@ impl<T: Clone> Dict<T> {
Ok(removed)
}
pub fn pop_back(&self) -> Option<(PyObjectRef, T)> {
let mut inner = self.write();
inner.entries.pop().map(|entry| {
let entry = entry.unwrap();
inner.used -= 1;
inner.indices[entry.index] = IndexEntry::DUMMY;
(entry.key, entry.value)
})
pub fn pop_back(&self, vm: &VirtualMachine) -> Option<(PyObjectRef, T)> {
let inner = self.read();
let mut idx: i64 = inner.size().entries_size as i64 - 1;
while idx >= 0 && inner.entries.get(idx as usize).unwrap().is_none() {
idx -= 1;
}
if idx < 0 {
None
} else {
let idx = idx as usize;
let entry = inner.entries.get(idx).unwrap().as_ref().unwrap().clone();
let removed_key = entry.key;
let removed_item = entry.value;
if let Ok(lookup) = self.lookup(vm, &removed_key, entry.hash, Some(inner)) {
match self.pop_inner(lookup) {
Ok(_) => Some((removed_key, removed_item)),
Err(_) => None,
}
} else {
None
}
}
}
pub fn sizeof(&self) -> usize {