Commit 7dc0be45 authored by Boxiang Sun's avatar Boxiang Sun

some set stuff

parent e8fd652b
......@@ -39,8 +39,9 @@ class BoxedSetIterator : public Box {
public:
BoxedSet* s;
decltype(BoxedSet::s)::iterator it;
long size;
BoxedSetIterator(BoxedSet* s) : s(s), it(s->s.begin()) {}
BoxedSetIterator(BoxedSet* s) : s(s), it(s->s.begin()), size(s->s.size()) {}
DEFAULT_CLASS(set_iterator_cls);
......@@ -68,9 +69,17 @@ Box* setiteratorHasnext(BoxedSetIterator* self) {
Box* setiteratorNext(BoxedSetIterator* self) {
RELEASE_ASSERT(self->cls == set_iterator_cls, "");
if (self->s->s.size() != self->size) {
raiseExcHelper(RuntimeError, "Set changed size during iteration");
}
return self->next();
}
Box* setiteratorLength(BoxedSetIterator* self) {
RELEASE_ASSERT(self->cls == set_iterator_cls, "");
return boxInt(self->s->s.size());
}
Box* setiter_next(Box* _self) noexcept {
RELEASE_ASSERT(_self->cls == set_iterator_cls, "");
BoxedSetIterator* self = (BoxedSetIterator*)_self;
......@@ -100,51 +109,90 @@ BoxedSet* makeNewSet(BoxedClass* cls, Box* container) {
BoxedSet* rtn = new (cls) BoxedSet();
if (container) {
for (Box* e : container->pyElements()) {
rtn->s.insert(e);
if (PyAnySet_Check(container)) {
for (auto&& elt : ((BoxedSet*)container)->s) {
rtn->s.insert(elt);
}
} else if (PyDict_CheckExact(container)) {
for (auto&& elt : ((BoxedDict*)container)->d) {
rtn->s.insert(elt.first);
}
} else {
for (auto elt : container->pyElements()) {
rtn->s.insert(elt);
}
}
}
return rtn;
}
Box* frozensetNew(Box* _cls, Box* container) {
Box* frozensetNew(Box* _cls, Box* container, BoxedDict* kwargs) {
RELEASE_ASSERT(_cls->cls == type_cls, "");
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
RELEASE_ASSERT(isSubclass(cls, frozenset_cls), "");
if (_cls == frozenset_cls && !_PyArg_NoKeywords("frozenset()", kwargs)) {
throwCAPIException();
}
// Some optimizations from CPython: frozensets can be shared:
if (_cls == frozenset_cls) {
if (!container) {
static Box* emptyfrozenset = PyGC_AddRoot(new (frozenset_cls) BoxedSet());
return emptyfrozenset;
}
if (_cls != frozenset_cls) {
return makeNewSet(cls, container);
}
if (container != NULL) {
if (container->cls == frozenset_cls)
return container;
}
return makeNewSet(cls, container);
BoxedSet* result = makeNewSet(cls, container);
if (result->s.size() != 0) {
return result;
}
}
static Box* emptyfrozenset = PyGC_AddRoot(new (frozenset_cls) BoxedSet());
return emptyfrozenset;
}
Box* setNew(Box* _cls, Box* container) {
Box* setNew(Box* _cls, Box* container, BoxedDict* kwargs) {
RELEASE_ASSERT(_cls->cls == type_cls, "");
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
RELEASE_ASSERT(isSubclass(cls, set_cls), "");
if (_cls == set_cls && !_PyArg_NoKeywords("set()", kwargs)) {
throwCAPIException();
}
// Note: set.__new__ explicitly ignores the container argument.
return makeNewSet(cls, NULL);
}
Box* setInit(Box* _self, Box* container) {
Box* setInit(Box* _self, Box* container, BoxedDict* kwargs) {
RELEASE_ASSERT(PySet_Check(_self), "");
if (PySet_Check(_self) && !_PyArg_NoKeywords("set()", kwargs)) {
throwCAPIException();
}
if (!container)
return None;
BoxedSet* self = static_cast<BoxedSet*>(_self);
for (Box* e : container->pyElements()) {
self->s.insert(e);
self->s.clear();
if (PyAnySet_Check(container)) {
for (auto&& elt : ((BoxedSet*)container)->s) {
self->s.insert(elt);
}
} else if (PyDict_CheckExact(container)) {
for (auto&& elt : ((BoxedDict*)container)->d) {
self->s.insert(elt.first);
}
} else {
for (auto elt : container->pyElements()) {
self->s.insert(elt);
}
}
return None;
}
......@@ -203,6 +251,7 @@ static void _setSymmetricDifferenceUpdate(BoxedSet* self, Box* other) {
other = makeNewSet(self->cls, other);
BoxedSet* other_set = static_cast<BoxedSet*>(other);
for (auto elt : other_set->s) {
bool found = self->s.erase(elt);
if (!found)
......@@ -213,7 +262,7 @@ static void _setSymmetricDifferenceUpdate(BoxedSet* self, Box* other) {
static BoxedSet* setIntersection2(BoxedSet* self, Box* container) {
RELEASE_ASSERT(PyAnySet_Check(self), "");
BoxedSet* rtn = new BoxedSet();
BoxedSet* rtn = makeNewSet(self->cls, NULL);
for (auto elt : container->pyElements()) {
if (self->s.count(elt))
rtn->s.insert(elt);
......@@ -340,27 +389,6 @@ extern "C" int PySet_Add(PyObject* set, PyObject* key) noexcept {
}
}
Box* setRemove(BoxedSet* self, Box* v) {
RELEASE_ASSERT(isSubclass(self->cls, set_cls), "");
auto it = self->s.find(v);
if (it == self->s.end()) {
raiseExcHelper(KeyError, v);
}
self->s.erase(it);
return None;
}
Box* setDiscard(BoxedSet* self, Box* v) {
RELEASE_ASSERT(isSubclass(self->cls, set_cls), "");
auto it = self->s.find(v);
if (it != self->s.end())
self->s.erase(it);
return None;
}
Box* setClear(BoxedSet* self, Box* v) {
RELEASE_ASSERT(isSubclass(self->cls, set_cls), "");
......@@ -401,7 +429,7 @@ Box* setUnion(BoxedSet* self, BoxedTuple* args) {
if (!PyAnySet_Check(self))
raiseExcHelper(TypeError, "descriptor 'union' requires a 'set' object but received a '%s'", getTypeName(self));
BoxedSet* rtn = new BoxedSet();
BoxedSet* rtn = makeNewSet(self->cls, self);
rtn->s.insert(self->s.begin(), self->s.end());
for (auto container : args->pyElements()) {
......@@ -414,9 +442,19 @@ Box* setUnion(BoxedSet* self, BoxedTuple* args) {
}
static void _setDifferenceUpdate(BoxedSet* self, BoxedTuple* args) {
for (auto container : *args) {
for (auto elt : container->pyElements()) {
self->s.erase(elt);
for (auto container : args->pyElements()) {
if (PyAnySet_Check(container)) {
for (auto&& elt : ((BoxedSet*)container)->s) {
self->s.erase(elt);
}
} else if (PyDict_CheckExact(container)) {
for (auto&& elt : ((BoxedDict*)container)->d) {
self->s.erase(elt.first);
}
} else {
for (auto elt : container->pyElements()) {
self->s.erase(elt);
}
}
}
}
......@@ -528,6 +566,15 @@ Box* setCopy(BoxedSet* self) {
return rtn;
}
Box* frozensetCopy(BoxedSet* self) {
RELEASE_ASSERT(PyAnySet_Check(self), "");
if (self->cls == frozenset_cls) {
return self;
}
return setCopy(self);
}
Box* setPop(BoxedSet* self) {
RELEASE_ASSERT(isSubclass(self->cls, set_cls), "");
......@@ -540,11 +587,6 @@ Box* setPop(BoxedSet* self) {
return rtn;
}
Box* setContains(BoxedSet* self, Box* v) {
RELEASE_ASSERT(PyAnySet_Check(self), "");
return boxBool(self->s.find(v) != self->s.end());
}
Box* setEq(BoxedSet* self, BoxedSet* rhs) {
RELEASE_ASSERT(PyAnySet_Check(self), "");
if (!PyAnySet_Check(rhs))
......@@ -600,20 +642,116 @@ Box* setGt(BoxedSet* self, BoxedSet* rhs) {
return setIssuperset(self, rhs);
}
Box* setContains(BoxedSet* self, Box* key) {
RELEASE_ASSERT(PyAnySet_Check(self), "");
if (PySet_Check(key)) {
try {
BoxAndHash k_hash(key);
return boxBool(self->s.find(k_hash) != self->s.end());
} catch (ExcInfo e) {
if (!e.matches(TypeError))
throw e;
BoxedSet* tmpKey = makeNewSet(frozenset_cls, key);
return boxBool(self->s.find(tmpKey) != self->s.end());
}
}
return boxBool(self->s.find(key) != self->s.end());
}
Box* setRemove(BoxedSet* self, Box* key) {
RELEASE_ASSERT(isSubclass(self->cls, set_cls), "");
if (PySet_Check(key)) {
try {
BoxAndHash k_hash(key);
if (self->s.find(k_hash) != self->s.end()) {
bool existed = self->s.erase(k_hash);
if (existed)
return None;
}
} catch (ExcInfo e) {
if (!e.matches(TypeError))
throw e;
BoxedSet* tmpKey = makeNewSet(frozenset_cls, key);
if (self->s.find(tmpKey) != self->s.end()) {
bool existed = self->s.erase(tmpKey);
if (existed)
return None;
}
}
raiseExcHelper(KeyError, key);
}
auto it = self->s.find(key);
if (it == self->s.end()) {
raiseExcHelper(KeyError, key);
}
self->s.erase(it);
return None;
}
Box* setDiscard(BoxedSet* self, Box* key) {
RELEASE_ASSERT(isSubclass(self->cls, set_cls), "");
if (PySet_Check(key)) {
try {
BoxAndHash k_hash(key);
if (self->s.find(k_hash) != self->s.end()) {
self->s.erase(k_hash);
}
} catch (ExcInfo e) {
if (!e.matches(TypeError))
throw e;
BoxedSet* tmpKey = makeNewSet(frozenset_cls, key);
if (self->s.find(tmpKey) != self->s.end()) {
self->s.erase(tmpKey);
}
}
return None;
}
auto it = self->s.find(key);
if (it != self->s.end())
self->s.erase(it);
return None;
}
Box* setNocmp(BoxedSet* self, BoxedSet* rhs) {
raiseExcHelper(TypeError, "cannot compare sets using cmp()");
}
Box* setNonzero(BoxedSet* self) {
RELEASE_ASSERT(PyAnySet_Check(self), "");
return boxBool(self->s.size());
}
Box* setNotImplemented(BoxedSet* self) {
raiseExcHelper(TypeError, "unhashable type: 'set'");
}
Box* setHash(BoxedSet* self) {
RELEASE_ASSERT(isSubclass(self->cls, frozenset_cls), "");
int64_t rtn = 1927868237L;
int64_t h, hash = 1927868237L;
hash *= self->s.size() + 1;
for (auto&& e : self->s) {
rtn ^= e.hash + 0x9e3779b9 + (rtn << 6) + (rtn >> 2);
h = e.hash;
hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u;
}
return boxInt(rtn);
hash = hash * 69069L + 907133923L;
if (hash == -1)
hash = 590923713L;
return boxInt(hash);
}
extern "C" PyObject* PySet_New(PyObject* iterable) noexcept {
......@@ -698,14 +836,16 @@ void setupSet() {
set_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1)));
set_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)setiteratorNext, UNKNOWN, 1)));
set_iterator_cls->giveAttr("__length_hint__",
new BoxedFunction(boxRTFunction((void*)setiteratorLength, BOXED_INT, 1)));
set_iterator_cls->freeze();
set_iterator_cls->tp_iternext = setiter_next;
set_iterator_cls->tp_iter = PyObject_SelfIter;
set_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)setNew, UNKNOWN, 2, false, false), { NULL }));
set_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)setInit, UNKNOWN, 2, false, false), { NULL }));
set_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)setNew, UNKNOWN, 2, false, true), { NULL }));
set_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)setInit, UNKNOWN, 2, false, true), { NULL }));
frozenset_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)frozensetNew, UNKNOWN, 2, false, false), { NULL }));
new BoxedFunction(boxRTFunction((void*)frozensetNew, UNKNOWN, 2, false, true), { NULL }));
Box* set_repr = new BoxedFunction(boxRTFunction((void*)setRepr, STR, 1));
set_cls->giveAttr("__repr__", set_repr);
......@@ -762,6 +902,8 @@ void setupSet() {
set_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)setContains, BOXED_BOOL, 2)));
frozenset_cls->giveAttr("__contains__", set_cls->getattr(internStringMortal("__contains__")));
set_cls->giveAttr("__cmp__", new BoxedFunction(boxRTFunction((void*)setNocmp, NONE, 2)));
frozenset_cls->giveAttr("__cmp__", new BoxedFunction(boxRTFunction((void*)setNocmp, NONE, 2)));
set_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)setEq, BOXED_BOOL, 2)));
frozenset_cls->giveAttr("__eq__", set_cls->getattr(internStringMortal("__eq__")));
set_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)setNe, BOXED_BOOL, 2)));
......@@ -811,6 +953,7 @@ void setupSet() {
frozenset_cls->giveAttr("isdisjoint", set_cls->getattr(internStringMortal("isdisjoint")));
set_cls->giveAttr("copy", new BoxedFunction(boxRTFunction((void*)setCopy, UNKNOWN, 1)));
frozenset_cls->giveAttr("copy", new BoxedFunction(boxRTFunction((void*)frozensetCopy, UNKNOWN, 1)));
set_cls->giveAttr("pop", new BoxedFunction(boxRTFunction((void*)setPop, UNKNOWN, 1)));
for (auto& md : set_methods) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment