diff --git a/convert.go b/convert.go index 4b5b0b0..52e4b68 100644 --- a/convert.go +++ b/convert.go @@ -149,16 +149,15 @@ func ToValue(from Object, to reflect.Value) bool { t := to.Type() to.Set(reflect.MakeMap(t)) dict := cast[Dict](from) - iter := dict.Iter() - for iter.HasNext() { - key, value := iter.Next() + dict.Items()(func(key, value Object) bool { vk := reflect.New(t.Key()).Elem() vv := reflect.New(t.Elem()).Elem() if !ToValue(key, vk) || !ToValue(value, vv) { return false } to.SetMapIndex(vk, vv) - } + return true + }) return true } else { return false diff --git a/dict.go b/dict.go index d1d214e..606e77f 100644 --- a/dict.go +++ b/dict.go @@ -2,6 +2,26 @@ package gp /* #include + +typedef struct pyCriticalSection { + uintptr_t _cs_prev; + void *_cs_mutex; +} pyCriticalSection; +static inline void pyCriticalSection_Begin(pyCriticalSection *pcs, PyObject *op) { +#if PY_VERSION_HEX >= 0x030D0000 + PyCriticalSection_Begin((PyCriticalSection*)pcs, op); +#else + PyGILState_STATE gstate = PyGILState_Ensure(); + pcs->_cs_prev = (uintptr_t)gstate; +#endif +} +static inline void pyCriticalSection_End(pyCriticalSection *pcs) { +#if PY_VERSION_HEX >= 0x030D0000 + PyCriticalSection_End((PyCriticalSection*)pcs); +#else + PyGILState_Release((PyGILState_STATE)pcs->_cs_prev); +#endif +} */ import "C" import ( @@ -75,26 +95,18 @@ func (d Dict) Del(key Objecter) { C.PyDict_DelItem(d.obj, key.cpyObj()) } -func (d Dict) Iter() *DictIter { - return &DictIter{dict: d, pos: 0} -} - -type DictIter struct { - dict Dict - pos C.long -} - -func (d *DictIter) HasNext() bool { - pos := d.pos - return C.PyDict_Next(d.dict.obj, &pos, nil, nil) != 0 -} - -func (d *DictIter) Next() (Object, Object) { - var key, value *C.PyObject - if C.PyDict_Next(d.dict.obj, &d.pos, &key, &value) == 0 { - return Nil(), Nil() +func (d Dict) Items() func(func(Object, Object) bool) { + obj := d.cpyObj() + var cs C.pyCriticalSection + C.pyCriticalSection_Begin(&cs, obj) + return func(fn func(Object, Object) bool) { + defer C.pyCriticalSection_End(&cs) + var pos C.long + var key, value *C.PyObject + for C.PyDict_Next(obj, &pos, &key, &value) == 1 { + if !fn(newObject(key), newObject(value)) { + return + } + } } - C.Py_IncRef(key) - C.Py_IncRef(value) - return newObject(key), newObject(value) } diff --git a/dict_test.go b/dict_test.go index ab4139d..38adc42 100644 --- a/dict_test.go +++ b/dict_test.go @@ -155,16 +155,15 @@ func TestDictForEach(t *testing.T) { "key3": "value3", } - iter := dict.Iter() - for iter.HasNext() { - key, value := iter.Next() + dict.Items()(func(key, value Object) bool { count++ k := key.String() v := value.String() if expectedVal, ok := expectedPairs[k]; !ok || expectedVal != v { t.Errorf("ForEach() unexpected pair: %v: %v", k, v) } - } + return true + }) if count != len(expectedPairs) { t.Errorf("ForEach() visited %d pairs, want %d", count, len(expectedPairs)) diff --git a/extension.go b/extension.go index 1158649..a0d68ff 100644 --- a/extension.go +++ b/extension.go @@ -272,7 +272,7 @@ func wrapperMethod_(typeMeta *typeMeta, methodMeta *slotMeta, self, args *C.PyOb } for i := 0; i < int(argc); i++ { - arg := C.PyTuple_GetItem(args, C.Py_ssize_t(i)) + arg := C.PySequence_GetItem(args, C.Py_ssize_t(i)) argType := methodType.In(i + argIndex) argPy := FromPy(arg) goValue := reflect.New(argType).Elem() diff --git a/list.go b/list.go index 0d38f97..3c99973 100644 --- a/list.go +++ b/list.go @@ -24,9 +24,7 @@ func MakeList(args ...any) List { } func (l List) GetItem(index int) Object { - v := C.PyList_GetItem(l.obj, C.Py_ssize_t(index)) - C.Py_IncRef(v) - return newObject(v) + return newObject(C.PySequence_GetItem(l.obj, C.Py_ssize_t(index))) } func (l List) SetItem(index int, item Objecter) { diff --git a/tuple.go b/tuple.go index bdc8b55..2e48eec 100644 --- a/tuple.go +++ b/tuple.go @@ -28,9 +28,7 @@ func MakeTuple(args ...any) Tuple { } func (t Tuple) Get(index int) Object { - v := C.PyTuple_GetItem(t.obj, C.Py_ssize_t(index)) - C.Py_IncRef(v) - return newObject(v) + return newObject(C.PySequence_GetItem(t.obj, C.Py_ssize_t(index))) } func (t Tuple) Set(index int, obj Objecter) {