This commit is contained in:
blueloveTH 2023-10-28 15:00:53 +08:00
parent 7916bb035f
commit a12eb4c8bc
10 changed files with 113 additions and 77 deletions

View File

@ -231,7 +231,7 @@ Compare two python objects
```cpp
PyObject* obj1 = py_var(vm, 1);
PyObject* obj2 = py_var(vm, 2);
bool ok = vm->py_equals(obj1, obj2);
bool ok = vm->py_eq(obj1, obj2);
```
Convert a python object to string

View File

@ -23,7 +23,7 @@
#include <bitset>
#include <deque>
#define PK_VERSION "1.2.7"
#define PK_VERSION "1.2.9"
#include "config.h"
#include "export.h"

View File

@ -304,7 +304,12 @@ public:
PK_OBJ_GET(NativeFunc, nf).set_userdata(f);
}
bool py_equals(PyObject* lhs, PyObject* rhs);
bool py_eq(PyObject* lhs, PyObject* rhs);
// new in v1.2.9
bool py_lt(PyObject* lhs, PyObject* rhs);
bool py_le(PyObject* lhs, PyObject* rhs);
bool py_gt(PyObject* lhs, PyObject* rhs);
bool py_ge(PyObject* lhs, PyObject* rhs);
template<int ARGC>
PyObject* bind_func(Str type, Str name, NativeFuncC fn) {

View File

@ -286,38 +286,6 @@ def __f(self, reverse=False, key=None):
self.reverse()
list.sort = __f
def __f(self, other):
for i, j in zip(self, other):
if i != j:
return i < j
return len(self) < len(other)
tuple.__lt__ = __f
list.__lt__ = __f
def __f(self, other):
for i, j in zip(self, other):
if i != j:
return i > j
return len(self) > len(other)
tuple.__gt__ = __f
list.__gt__ = __f
def __f(self, other):
for i, j in zip(self, other):
if i != j:
return i <= j
return len(self) <= len(other)
tuple.__le__ = __f
list.__le__ = __f
def __f(self, other):
for i, j in zip(self, other):
if i != j:
return i >= j
return len(self) >= len(other)
tuple.__ge__ = __f
list.__ge__ = __f
type.__repr__ = lambda self: "<class '" + self.__name__ + "'>"
type.__getitem__ = lambda self, *args: self # for generics

View File

@ -2,6 +2,48 @@
namespace pkpy{
#define BINARY_F_COMPARE(func, op, rfunc) \
PyObject* ret; \
const PyTypeInfo* _ti = _inst_type_info(_0); \
if(_ti->m##func){ \
ret = _ti->m##func(this, _0, _1); \
}else{ \
PyObject* self; \
PyObject* _2 = get_unbound_method(_0, func, &self, false); \
if(_2 != nullptr) ret = call_method(self, _2, _1); \
else ret = NotImplemented; \
} \
if(ret == NotImplemented){ \
PyObject* self; \
PyObject* _2 = get_unbound_method(_1, rfunc, &self, false); \
if(_2 != nullptr) ret = call_method(self, _2, _0); \
else BinaryOptError(op); \
if(ret == NotImplemented) BinaryOptError(op); \
}
bool VM::py_lt(PyObject* _0, PyObject* _1){
BINARY_F_COMPARE(__lt__, "<", __gt__);
return CAST(bool, ret);
}
bool VM::py_le(PyObject* _0, PyObject* _1){
BINARY_F_COMPARE(__le__, "<=", __ge__);
return CAST(bool, ret);
}
bool VM::py_gt(PyObject* _0, PyObject* _1){
BINARY_F_COMPARE(__gt__, ">", __lt__);
return CAST(bool, ret);
}
bool VM::py_ge(PyObject* _0, PyObject* _1){
BINARY_F_COMPARE(__ge__, ">=", __le__);
return CAST(bool, ret);
}
#undef BINARY_F_COMPARE
static i64 _py_sint(PyObject* obj) noexcept {
return (i64)(PK_BITS(obj) >> 2);
}
@ -386,34 +428,34 @@ __NEXT_STEP:;
if(TOP() == NotImplemented) BinaryOptError("%");
} DISPATCH()
TARGET(COMPARE_LT){
PyObject* _0; PyObject* _1; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__lt__);
BINARY_OP_RSPECIAL("<", __gt__);
PyObject* _1 = POPX();
PyObject* _0 = TOP();
TOP() = VAR(py_lt(_0, _1));
} DISPATCH()
TARGET(COMPARE_LE){
PyObject* _0; PyObject* _1; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__le__);
BINARY_OP_RSPECIAL("<=", __ge__);
PyObject* _1 = POPX();
PyObject* _0 = TOP();
TOP() = VAR(py_le(_0, _1));
} DISPATCH()
TARGET(COMPARE_EQ){
PyObject* _1 = POPX();
PyObject* _0 = TOP();
TOP() = VAR(py_equals(_0, _1));
TOP() = VAR(py_eq(_0, _1));
} DISPATCH()
TARGET(COMPARE_NE){
PyObject* _1 = POPX();
PyObject* _0 = TOP();
TOP() = VAR(!py_equals(_0, _1));
TOP() = VAR(!py_eq(_0, _1));
} DISPATCH()
TARGET(COMPARE_GT){
PyObject* _0; PyObject* _1; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__gt__);
BINARY_OP_RSPECIAL(">", __lt__);
PyObject* _1 = POPX();
PyObject* _0 = TOP();
TOP() = VAR(py_gt(_0, _1));
} DISPATCH()
TARGET(COMPARE_GE){
PyObject* _0; PyObject* _1; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__ge__);
BINARY_OP_RSPECIAL(">=", __le__);
PyObject* _1 = POPX();
PyObject* _0 = TOP();
TOP() = VAR(py_ge(_0, _1));
} DISPATCH()
TARGET(BITWISE_LSHIFT){
PyObject* _0; PyObject* _1; const PyTypeInfo* _ti;

View File

@ -145,7 +145,7 @@ namespace pkpy
if (self.dequeItems.size() != other.dequeItems.size()) // trivial case
return VAR(false);
for (int i = 0; i < self.dequeItems.size(); i++)
if (!vm->py_equals(self.dequeItems[i], other.dequeItems[i]))
if (!vm->py_eq(self.dequeItems[i], other.dequeItems[i]))
return VAR(false);
return VAR(true);
});
@ -235,7 +235,7 @@ namespace pkpy
int cnt = 0, sz = self.dequeItems.size();
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
{
if (vm->py_equals((*it), obj))
if (vm->py_eq((*it), obj))
cnt++;
if (sz != self.dequeItems.size())// mutating the deque during iteration is not allowed
vm->RuntimeError("deque mutated during iteration");
@ -265,9 +265,9 @@ namespace pkpy
PyDeque &self = _CAST(PyDeque &, args[0]);
PyObject *obj = args[1];
int start = 0, stop = self.dequeItems.size(); // default values
if (!vm->py_equals(args[2], vm->None))
if (!vm->py_eq(args[2], vm->None))
start = CAST(int, args[2]);
if (!vm->py_equals(args[3], vm->None))
if (!vm->py_eq(args[3], vm->None))
stop = CAST(int, args[3]);
int index = self.findIndex(vm, obj, start, stop);
if (index != -1)
@ -398,7 +398,7 @@ namespace pkpy
PyDeque::PyDeque(VM *vm, PyObject *iterable, PyObject *maxlen)
{
if (!vm->py_equals(maxlen, vm->None)) // fix the maxlen first
if (!vm->py_eq(maxlen, vm->None)) // fix the maxlen first
{
int tmp = CAST(int, maxlen);
if (tmp < 0)
@ -414,7 +414,7 @@ namespace pkpy
this->bounded = false;
this->maxlen = -1;
}
if (!vm->py_equals(iterable, vm->None))
if (!vm->py_eq(iterable, vm->None))
{
this->dequeItems.clear(); // clear the deque
auto _lock = vm->heap.gc_scope_lock(); // locking the heap
@ -467,7 +467,7 @@ namespace pkpy
int sz = this->dequeItems.size();
for (int i = start; i < loopSize; i++)
{
if (vm->py_equals(this->dequeItems[i], obj))
if (vm->py_eq(this->dequeItems[i], obj))
return i;
if (sz != this->dequeItems.size())// mutating the deque during iteration is not allowed
vm->RuntimeError("deque mutated during iteration");
@ -479,7 +479,7 @@ namespace pkpy
/// @param front if true, pop from the front of the deque
/// @param back if true, pop from the back of the deque
/// @param item if front and back is not set, remove the first occurence of item from the deque
/// @param vm is needed for the py_equals
/// @param vm is needed for the py_eq
/// @return PyObject* if front or back is set, this is a pop operation and we return a PyObject*, if front and back are not set, this is a remove operation and we return the removed item or nullptr
PyObject *PyDeque::popObj(bool front, bool back, PyObject *item, VM *vm)
{
@ -510,7 +510,7 @@ namespace pkpy
int sz = this->dequeItems.size();
for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it)
{
bool found = vm->py_equals((*it), item);
bool found = vm->py_eq((*it), item);
if (sz != this->dequeItems.size()) // mutating the deque during iteration is not allowed
vm->IndexError("deque mutated during iteration");
if (found)

View File

@ -736,14 +736,14 @@ void init_builtins(VM* _vm) {
_vm->bind__contains__(_vm->tp_list, [](VM* vm, PyObject* obj, PyObject* item) {
List& self = _CAST(List&, obj);
for(PyObject* i: self) if(vm->py_equals(i, item)) return vm->True;
for(PyObject* i: self) if(vm->py_eq(i, item)) return vm->True;
return vm->False;
});
_vm->bind_method<1>("list", "count", [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]);
int count = 0;
for(PyObject* i: self) if(vm->py_equals(i, args[1])) count++;
for(PyObject* i: self) if(vm->py_eq(i, args[1])) count++;
return VAR(count);
});
@ -753,7 +753,7 @@ void init_builtins(VM* _vm) {
List& b = _CAST(List&, rhs);
if(a.size() != b.size()) return vm->False;
for(int i=0; i<a.size(); i++){
if(!vm->py_equals(a[i], b[i])) return vm->False;
if(!vm->py_eq(a[i], b[i])) return vm->False;
}
return vm->True;
});
@ -762,7 +762,7 @@ void init_builtins(VM* _vm) {
List& self = _CAST(List&, args[0]);
PyObject* obj = args[1];
for(int i=0; i<self.size(); i++){
if(vm->py_equals(self[i], obj)) return VAR(i);
if(vm->py_eq(self[i], obj)) return VAR(i);
}
vm->ValueError(_CAST(Str&, vm->py_repr(obj)) + " is not in list");
return vm->None;
@ -772,7 +772,7 @@ void init_builtins(VM* _vm) {
List& self = _CAST(List&, args[0]);
PyObject* obj = args[1];
for(int i=0; i<self.size(); i++){
if(vm->py_equals(self[i], obj)){
if(vm->py_eq(self[i], obj)){
self.erase(i);
return vm->None;
}
@ -858,6 +858,30 @@ void init_builtins(VM* _vm) {
_vm->bind_method<0>("list", "copy", PK_LAMBDA(VAR(_CAST(List, args[0]))));
#define BIND_RICH_CMP(name, op, _t, _T) \
_vm->bind__##name##__(_vm->_t, [](VM* vm, PyObject* lhs, PyObject* rhs){ \
if(!is_non_tagged_type(rhs, vm->_t)) return vm->NotImplemented; \
auto& a = _CAST(_T&, lhs); \
auto& b = _CAST(_T&, rhs); \
for(int i=0; i<a.size() && i<b.size(); i++){ \
if(vm->py_eq(a[i], b[i])) continue; \
return VAR(vm->py_##name(a[i], b[i])); \
} \
return VAR(a.size() op b.size()); \
});
BIND_RICH_CMP(lt, <, tp_list, List)
BIND_RICH_CMP(le, <=, tp_list, List)
BIND_RICH_CMP(gt, >, tp_list, List)
BIND_RICH_CMP(ge, >=, tp_list, List)
BIND_RICH_CMP(lt, <, tp_tuple, Tuple)
BIND_RICH_CMP(le, <=, tp_tuple, Tuple)
BIND_RICH_CMP(gt, >, tp_tuple, Tuple)
BIND_RICH_CMP(ge, >=, tp_tuple, Tuple)
#undef BIND_RICH_CMP
_vm->bind__add__(_vm->tp_list, [](VM* vm, PyObject* lhs, PyObject* rhs) {
const List& self = _CAST(List&, lhs);
const List& other = CAST(List&, rhs);
@ -900,14 +924,14 @@ void init_builtins(VM* _vm) {
_vm->bind__contains__(_vm->tp_tuple, [](VM* vm, PyObject* obj, PyObject* item) {
Tuple& self = _CAST(Tuple&, obj);
for(PyObject* i: self) if(vm->py_equals(i, item)) return vm->True;
for(PyObject* i: self) if(vm->py_eq(i, item)) return vm->True;
return vm->False;
});
_vm->bind_method<1>("tuple", "count", [](VM* vm, ArgsView args) {
Tuple& self = _CAST(Tuple&, args[0]);
int count = 0;
for(PyObject* i: self) if(vm->py_equals(i, args[1])) count++;
for(PyObject* i: self) if(vm->py_eq(i, args[1])) count++;
return VAR(count);
});
@ -917,7 +941,7 @@ void init_builtins(VM* _vm) {
const Tuple& other = _CAST(Tuple&, rhs);
if(self.size() != other.size()) return vm->False;
for(int i = 0; i < self.size(); i++) {
if(!vm->py_equals(self[i], other[i])) return vm->False;
if(!vm->py_eq(self[i], other[i])) return vm->False;
}
return vm->True;
});
@ -1282,7 +1306,7 @@ void init_builtins(VM* _vm) {
if(item.first == nullptr) continue;
PyObject* value = other.try_get(item.first);
if(value == nullptr) return vm->False;
if(!vm->py_equals(item.second, value)) return vm->False;
if(!vm->py_eq(item.second, value)) return vm->False;
}
return vm->True;
});

View File

@ -249,7 +249,7 @@ namespace pkpy{
return &_all_types[obj->type];
}
bool VM::py_equals(PyObject* lhs, PyObject* rhs){
bool VM::py_eq(PyObject* lhs, PyObject* rhs){
if(lhs == rhs) return true;
const PyTypeInfo* ti = _inst_type_info(lhs);
PyObject* res;
@ -1230,7 +1230,7 @@ void Dict::_probe_0(PyObject *key, bool &ok, int &i) const{
// std::cout << CAST(Str, vm->py_repr(key)) << " " << hash << " " << i << std::endl;
for(int j=0; j<_capacity; j++) {
if(_items[i].first != nullptr){
if(vm->py_equals(_items[i].first, key)) { ok = true; break; }
if(vm->py_eq(_items[i].first, key)) { ok = true; break; }
}else{
if(_items[i].second == nullptr) break;
}
@ -1244,7 +1244,7 @@ void Dict::_probe_1(PyObject *key, bool &ok, int &i) const{
ok = false;
i = vm->py_hash(key) & _mask;
while(_items[i].first != nullptr) {
if(vm->py_equals(_items[i].first, key)) { ok = true; break; }
if(vm->py_eq(_items[i].first, key)) { ok = true; break; }
// https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166
i = ((5*i) + 1) & _mask;
}

View File

@ -826,6 +826,3 @@ d = deque()
for i in range(100):
d.append(1)
gc.collect()
print('', "ALL TEST PASSED!!")

View File

@ -380,7 +380,7 @@ except:
# #####: 649: List& self = _CAST(List&, args[0]);
# #####: 650: PyObject* obj = args[1];
# #####: 651: for(int i=0; i<self.size(); i++){
# #####: 652: if(vm->py_equals(self[i], obj)) return VAR(i);
# #####: 652: if(vm->py_eq(self[i], obj)) return VAR(i);
# -: 653: }
# #####: 654: vm->ValueError(_CAST(Str&, vm->py_repr(obj)) + " is not in list");
# #####: 655: return vm->None;
@ -401,7 +401,7 @@ except:
# 1: 659: List& self = _CAST(List&, args[0]);
# 1: 660: PyObject* obj = args[1];
# 2: 661: for(int i=0; i<self.size(); i++){
# 2: 662: if(vm->py_equals(self[i], obj)){
# 2: 662: if(vm->py_eq(self[i], obj)){
# 1: 663: self.erase(i);
# 1: 664: return vm->None;
# -: 665: }
@ -474,7 +474,7 @@ except:
# 未完全测试准确性-----------------------------------------------
# 118: 793: _vm->bind__contains__(_vm->tp_tuple, [](VM* vm, PyObject* obj, PyObject* item) {
# 1: 794: Tuple& self = _CAST(Tuple&, obj);
# 3: 795: for(PyObject* i: self) if(vm->py_equals(i, item)) return vm->True;
# 3: 795: for(PyObject* i: self) if(vm->py_eq(i, item)) return vm->True;
# #####: 796: return vm->False;
# 1: 797: });
# test tuple.__contains__:
@ -485,7 +485,7 @@ assert (1,2,3).__contains__(5) == False
# 116: 799: _vm->bind_method<1>("tuple", "count", [](VM* vm, ArgsView args) {
# #####: 800: Tuple& self = _CAST(Tuple&, args[0]);
# -: 801: int count = 0;
# #####: 802: for(PyObject* i: self) if(vm->py_equals(i, args[1])) count++;
# #####: 802: for(PyObject* i: self) if(vm->py_eq(i, args[1])) count++;
# #####: 803: return VAR(count);
# -: 804: });
# test tuple.count: