From be9d8a4a56a4abcfd12e11f6c956f9b15459366b Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Sat, 22 Feb 2020 11:22:01 +0200 Subject: [PATCH 1/4] Fix symmetric_difference --- Lib/test/test_set.py | 3 --- vm/src/obj/objset.rs | 13 +++++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 0d9ac1fc0..45ebdc846 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -172,7 +172,6 @@ class TestJointOps: else: self.fail("s-t did not screen-out general iterables") - @unittest.skip("TODO: RUSTPYTHON") def test_symmetric_difference(self): i = self.s.symmetric_difference(self.otherword) for c in self.letters: @@ -187,7 +186,6 @@ class TestJointOps: self.assertEqual(self.thetype('abcba').symmetric_difference(C('ccb')), set('a')) self.assertEqual(self.thetype('abcba').symmetric_difference(C('ef')), set('abcef')) - @unittest.skip("TODO: RUSTPYTHON") def test_xor(self): i = self.s.symmetric_difference(self.otherword) self.assertEqual(self.s ^ set(self.otherword), i) @@ -582,7 +580,6 @@ class TestSet(TestJointOps, unittest.TestCase): else: self.assertNotIn(c, self.s) - @unittest.skip("TODO: RUSTPYTHON") def test_symmetric_difference_update(self): retval = self.s.symmetric_difference_update(self.otherword) self.assertEqual(retval, None) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 1483a8a3d..bf9c2c2ed 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -206,8 +206,11 @@ impl PySetInner { fn symmetric_difference(&self, other: PyIterable, vm: &VirtualMachine) -> PyResult { let mut new_inner = self.clone(); - for item in other.iter(vm)? { - new_inner.content.delete_or_insert(vm, &item?, ())? + // We want to remove duplicates in other + let other_set = Self::new(other, vm)?; + + for item in other_set.content.keys() { + new_inner.content.delete_or_insert(vm, &item, ())? } Ok(new_inner) @@ -322,8 +325,10 @@ impl PySetInner { vm: &VirtualMachine, ) -> PyResult<()> { for iterable in others { - for item in iterable.iter(vm)? { - self.content.delete_or_insert(vm, &item?, ())?; + // We want to remove duplicates in iterable + let iterable_set = Self::new(iterable, vm)?; + for item in iterable_set.content.keys() { + self.content.delete_or_insert(vm, &item, ())?; } } Ok(()) From 84250294b019baf4dbb7745b37d09935fe4cd36c Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Sat, 22 Feb 2020 12:36:27 +0200 Subject: [PATCH 2/4] Fix frozenset hash --- Lib/test/test_set.py | 3 --- vm/src/obj/objset.rs | 11 +++++++++++ vm/src/pyhash.rs | 13 +++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 45ebdc846..3e51977f1 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -205,7 +205,6 @@ class TestJointOps: self.assertNotEqual(self.s, frozenset(self.otherword)) self.assertEqual(self.s != self.word, True) - @unittest.skip("TODO: RUSTPYTHON") def test_setOfFrozensets(self): t = map(frozenset, ['abcdef', 'bcd', 'bdcb', 'fed', 'fedccba']) s = self.thetype(t) @@ -710,7 +709,6 @@ class TestFrozenSet(TestJointOps, unittest.TestCase): t = self.thetype(s) self.assertEqual(id(s), id(t)) - @unittest.skip("TODO: RUSTPYTHON") def test_hash(self): self.assertEqual(hash(self.thetype('abcdeb')), hash(self.thetype('ebecda'))) @@ -729,7 +727,6 @@ class TestFrozenSet(TestJointOps, unittest.TestCase): dup = self.s.copy() self.assertEqual(id(self.s), id(dup)) - @unittest.skip("TODO: RUSTPYTHON") def test_frozen_as_dictkey(self): seq = list(range(10)) + list('abcdefg') + ['apple'] key1 = self.thetype(seq) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index bf9c2c2ed..b68c459b7 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -9,6 +9,7 @@ use super::objlist::PyListIterator; use super::objtype::{self, PyClassRef}; use crate::dictdatatype; use crate::function::{Args, OptionalArg}; +use crate::pyhash; use crate::pyobject::{ PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, @@ -333,6 +334,11 @@ impl PySetInner { } Ok(()) } + + fn hash(&self, vm: &VirtualMachine) -> PyResult { + // let items: Vec = self.content.keys().collect(); + pyhash::hash_iter_no_order(self.content.keys(), vm) + } } macro_rules! try_set_cmp { @@ -785,6 +791,11 @@ impl PyFrozenSet { }; Ok(vm.new_str(s)) } + + #[pymethod(name = "__hash__")] + fn hash(&self, vm: &VirtualMachine) -> PyResult { + self.inner.hash(vm) + } } struct SetIterable { diff --git a/vm/src/pyhash.rs b/vm/src/pyhash.rs index 83776bd58..90f8c5090 100644 --- a/vm/src/pyhash.rs +++ b/vm/src/pyhash.rs @@ -84,6 +84,19 @@ pub fn hash_iter<'a, I: std::iter::Iterator>( Ok(hasher.finish() as PyHash) } +pub fn hash_iter_no_order>( + iter: I, + vm: &VirtualMachine, +) -> PyResult { + let mut hash: PyHash = 0; + for element in iter { + let item_hash = vm._hash(&element)?; + // xor is commutative and hash should be independent of order + hash ^= item_hash; + } + Ok(hash) +} + pub fn hash_bigint(value: &BigInt) -> PyHash { match value.to_i64() { Some(i64_value) => (i64_value % MODULUS as i64), From 3db197c4b12970fedfaba780b3e7d7b9eb76691d Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Sat, 22 Feb 2020 12:59:48 +0200 Subject: [PATCH 3/4] Fix set intersection_update --- Lib/test/test_set.py | 1 - vm/src/obj/objset.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 3e51977f1..78e0283a8 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -512,7 +512,6 @@ class TestSet(TestJointOps, unittest.TestCase): for c in (self.word + self.otherword): self.assertIn(c, self.s) - @unittest.skip("TODO: RUSTPYTHON") def test_intersection_update(self): retval = self.s.intersection_update(self.otherword) self.assertEqual(retval, None) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index b68c459b7..e4d72a5f4 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -298,7 +298,7 @@ impl PySetInner { others: Args, vm: &VirtualMachine, ) -> PyResult<()> { - let temp_inner = self.copy(); + let mut temp_inner = self.copy(); self.clear(); for iterable in others { for item in iterable.iter(vm)? { @@ -307,6 +307,7 @@ impl PySetInner { self.add(&obj, vm)?; } } + temp_inner = self.copy() } Ok(()) } From 69ba6cf88783d42434768883c4a2b5eb97435371 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Sat, 29 Feb 2020 09:40:16 +0200 Subject: [PATCH 4/4] Rename hash_iter_no_order to hash_iter_unordered --- vm/src/obj/objset.rs | 3 +-- vm/src/pyhash.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index e4d72a5f4..369af668d 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -337,8 +337,7 @@ impl PySetInner { } fn hash(&self, vm: &VirtualMachine) -> PyResult { - // let items: Vec = self.content.keys().collect(); - pyhash::hash_iter_no_order(self.content.keys(), vm) + pyhash::hash_iter_unordered(self.content.keys(), vm) } } diff --git a/vm/src/pyhash.rs b/vm/src/pyhash.rs index 90f8c5090..03b912b9f 100644 --- a/vm/src/pyhash.rs +++ b/vm/src/pyhash.rs @@ -84,7 +84,7 @@ pub fn hash_iter<'a, I: std::iter::Iterator>( Ok(hasher.finish() as PyHash) } -pub fn hash_iter_no_order>( +pub fn hash_iter_unordered>( iter: I, vm: &VirtualMachine, ) -> PyResult {