Skip to content

Commit 289ddea

Browse files
authored
Merge pull request RustPython#2878 from DimitrisJim/sets_reduce
Add reduce for set, frozenset.
2 parents cc40ae0 + ac0d5ff commit 289ddea

File tree

2 files changed

+44
-29
lines changed

2 files changed

+44
-29
lines changed

Lib/test/test_set.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ def test_iterator_pickling(self):
258258
it = pickle.loads(d)
259259
self.assertEqual(self.thetype(it), data - self.thetype((drop,)))
260260

261-
# TODO: RUSTPYTHON
262-
@unittest.expectedFailure
263261
def test_deepcopy(self):
264262
class Tracer:
265263
def __init__(self, value):
@@ -673,8 +671,6 @@ class TestSetSubclass(TestSet):
673671
thetype = SetSubclass
674672
basetype = set
675673

676-
# TODO: RUSTPYTHON
677-
@unittest.expectedFailure
678674
def test_pickling(self):
679675
super().test_pickling()
680676

@@ -688,8 +684,6 @@ def __init__(self, iterable=[], newarg=None):
688684
set.__init__(self, iterable)
689685

690686
class TestSetSubclassWithKeywordArgs(TestSet):
691-
# TODO: RUSTPYTHON
692-
@unittest.expectedFailure
693687
def test_keywords_in_subclass(self):
694688
'SF bug #1486663 -- this used to erroneously raise a TypeError'
695689
SetSubclassWithKeywordArgs(newarg=1)
@@ -787,8 +781,6 @@ class TestFrozenSetSubclass(TestFrozenSet):
787781
thetype = FrozenSetSubclass
788782
basetype = frozenset
789783

790-
# TODO: RUSTPYTHON
791-
@unittest.expectedFailure
792784
def test_pickling(self):
793785
super().test_pickling()
794786

@@ -1591,8 +1583,6 @@ class TestCopyingSingleton(TestCopying, unittest.TestCase):
15911583
def setUp(self):
15921584
self.set = set(["hello"])
15931585

1594-
# TODO: RUSTPYTHON
1595-
@unittest.expectedFailure
15961586
def test_deep_copy(self):
15971587
super().test_deep_copy()
15981588

@@ -1602,8 +1592,6 @@ class TestCopyingTriple(TestCopying, unittest.TestCase):
16021592
def setUp(self):
16031593
self.set = set(["zero", 0, None])
16041594

1605-
# TODO: RUSTPYTHON
1606-
@unittest.expectedFailure
16071595
def test_deep_copy(self):
16081596
super().test_deep_copy()
16091597

@@ -1613,8 +1601,6 @@ class TestCopyingTuple(TestCopying, unittest.TestCase):
16131601
def setUp(self):
16141602
self.set = set([(1, 2)])
16151603

1616-
# TODO: RUSTPYTHON
1617-
@unittest.expectedFailure
16181604
def test_deep_copy(self):
16191605
super().test_deep_copy()
16201606

@@ -1624,8 +1610,6 @@ class TestCopyingNested(TestCopying, unittest.TestCase):
16241610
def setUp(self):
16251611
self.set = set([((1, 2), (3, 4))])
16261612

1627-
# TODO: RUSTPYTHON
1628-
@unittest.expectedFailure
16291613
def test_deep_copy(self):
16301614
super().test_deep_copy()
16311615

vm/src/builtins/set.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
22
* Builtin set type with a sequence of unique items.
33
*/
4-
use super::pytype::PyTypeRef;
4+
use super::{pytype::PyTypeRef, PyDictRef};
55
use crate::common::hash::PyHash;
66
use crate::common::rc::PyRc;
77
use crate::dictdatatype;
8-
use crate::function::{Args, OptionalArg};
8+
use crate::function::{Args, FuncArgs, OptionalArg};
99
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable};
1010
use crate::vm::{ReprGuard, VirtualMachine};
1111
use crate::{
@@ -113,7 +113,7 @@ impl PySetInner {
113113
} else {
114114
(self, other)
115115
};
116-
for key in subset.content.keys() {
116+
for key in subset.elements() {
117117
if !superset.contains(&key, vm)? {
118118
return Ok(false);
119119
}
@@ -155,7 +155,7 @@ impl PySetInner {
155155
// We want to remove duplicates in other
156156
let other_set = Self::new(other, vm)?;
157157

158-
for item in other_set.content.keys() {
158+
for item in other_set.elements() {
159159
new_inner.content.delete_or_insert(vm, &item, ())?
160160
}
161161

@@ -193,14 +193,14 @@ impl PySetInner {
193193

194194
PySetIterator {
195195
dict: PyRc::clone(&self.content),
196-
elements: self.content.keys(),
196+
elements: self.elements(),
197197
size_info: AtomicCell::new(set_size),
198198
}
199199
}
200200

201201
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
202202
let mut str_parts = Vec::with_capacity(self.content.len());
203-
for key in self.content.keys() {
203+
for key in self.elements() {
204204
let part = vm.to_repr(&key)?;
205205
str_parts.push(part.as_str().to_owned());
206206
}
@@ -224,6 +224,10 @@ impl PySetInner {
224224
self.content.clear()
225225
}
226226

227+
fn elements(&self) -> Vec<PyObjectRef> {
228+
self.content.keys()
229+
}
230+
227231
fn pop(&self, vm: &VirtualMachine) -> PyResult {
228232
// TODO: should be pop_front, but that requires rearranging every index
229233
if let Some((key, _)) = self.content.pop_back() {
@@ -275,15 +279,15 @@ impl PySetInner {
275279
for iterable in others {
276280
// We want to remove duplicates in iterable
277281
let iterable_set = Self::new(iterable, vm)?;
278-
for item in iterable_set.content.keys() {
282+
for item in iterable_set.elements() {
279283
self.content.delete_or_insert(vm, &item, ())?;
280284
}
281285
}
282286
Ok(())
283287
}
284288

285289
fn hash(&self, vm: &VirtualMachine) -> PyResult<PyHash> {
286-
crate::utils::hash_iter_unordered(self.content.keys().iter(), vm)
290+
crate::utils::hash_iter_unordered(self.elements().iter(), vm)
287291
}
288292

289293
// Run operation, on failure, if item is a set/set subclass, convert it
@@ -331,6 +335,21 @@ fn extract_set(obj: &PyObjectRef) -> Option<&PySetInner> {
331335
})
332336
}
333337

338+
fn reduce_set(
339+
zelf: &PyObjectRef,
340+
vm: &VirtualMachine,
341+
) -> PyResult<(PyTypeRef, PyObjectRef, Option<PyDictRef>)> {
342+
Ok((
343+
zelf.clone_class(),
344+
vm.ctx.new_tuple(vec![vm.ctx.new_list(
345+
extract_set(zelf)
346+
.unwrap_or(&PySetInner::default())
347+
.elements(),
348+
)]),
349+
zelf.dict(),
350+
))
351+
}
352+
334353
macro_rules! multi_args_set {
335354
($vm:expr, $others:expr, $zelf:expr, $op:tt) => {{
336355
let mut res = $zelf.inner.copy();
@@ -344,11 +363,7 @@ macro_rules! multi_args_set {
344363
#[pyimpl(with(Hashable, Comparable, Iterable), flags(BASETYPE))]
345364
impl PySet {
346365
#[pyslot]
347-
fn tp_new(
348-
cls: PyTypeRef,
349-
_iterable: OptionalArg<PyIterable>,
350-
vm: &VirtualMachine,
351-
) -> PyResult<PyRef<Self>> {
366+
fn tp_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
352367
PySet::default().into_ref_with_type(vm, cls)
353368
}
354369

@@ -543,6 +558,14 @@ impl PySet {
543558
.symmetric_difference_update(iterable.iterable, vm)?;
544559
Ok(zelf.as_object().clone())
545560
}
561+
562+
#[pymethod(magic)]
563+
fn reduce(
564+
zelf: PyRef<Self>,
565+
vm: &VirtualMachine,
566+
) -> PyResult<(PyTypeRef, PyObjectRef, Option<PyDictRef>)> {
567+
reduce_set(&zelf.into_object(), vm)
568+
}
546569
}
547570

548571
impl Comparable for PySet {
@@ -719,6 +742,14 @@ impl PyFrozenSet {
719742
};
720743
Ok(vm.ctx.new_str(s))
721744
}
745+
746+
#[pymethod(magic)]
747+
fn reduce(
748+
zelf: PyRef<Self>,
749+
vm: &VirtualMachine,
750+
) -> PyResult<(PyTypeRef, PyObjectRef, Option<PyDictRef>)> {
751+
reduce_set(&zelf.into_object(), vm)
752+
}
722753
}
723754

724755
impl Hashable for PyFrozenSet {

0 commit comments

Comments
 (0)