| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- // Dict primitive operations
- //
- // These are registered in mypyc.primitives.dict_ops.
- #include <Python.h>
- #include "CPy.h"
- #ifndef Py_TPFLAGS_MAPPING
- #define Py_TPFLAGS_MAPPING (1 << 6)
- #endif
- // Dict subclasses like defaultdict override things in interesting
- // ways, so we don't want to just directly use the dict methods. Not
- // sure if it is actually worth doing all this stuff, but it saves
- // some indirections.
- PyObject *CPyDict_GetItem(PyObject *dict, PyObject *key) {
- if (PyDict_CheckExact(dict)) {
- PyObject *res = PyDict_GetItemWithError(dict, key);
- if (!res) {
- if (!PyErr_Occurred()) {
- PyErr_SetObject(PyExc_KeyError, key);
- }
- } else {
- Py_INCREF(res);
- }
- return res;
- } else {
- return PyObject_GetItem(dict, key);
- }
- }
- PyObject *CPyDict_Build(Py_ssize_t size, ...) {
- Py_ssize_t i;
- PyObject *res = _PyDict_NewPresized(size);
- if (res == NULL) {
- return NULL;
- }
- va_list args;
- va_start(args, size);
- for (i = 0; i < size; i++) {
- PyObject *key = va_arg(args, PyObject *);
- PyObject *value = va_arg(args, PyObject *);
- if (PyDict_SetItem(res, key, value)) {
- Py_DECREF(res);
- return NULL;
- }
- }
- va_end(args);
- return res;
- }
- PyObject *CPyDict_Get(PyObject *dict, PyObject *key, PyObject *fallback) {
- // We are dodgily assuming that get on a subclass doesn't have
- // different behavior.
- PyObject *res = PyDict_GetItemWithError(dict, key);
- if (!res) {
- if (PyErr_Occurred()) {
- return NULL;
- }
- res = fallback;
- }
- Py_INCREF(res);
- return res;
- }
- PyObject *CPyDict_GetWithNone(PyObject *dict, PyObject *key) {
- return CPyDict_Get(dict, key, Py_None);
- }
- PyObject *CPyDict_SetDefault(PyObject *dict, PyObject *key, PyObject *value) {
- if (PyDict_CheckExact(dict)) {
- PyObject* ret = PyDict_SetDefault(dict, key, value);
- Py_XINCREF(ret);
- return ret;
- }
- _Py_IDENTIFIER(setdefault);
- return _PyObject_CallMethodIdObjArgs(dict, &PyId_setdefault, key, value, NULL);
- }
- PyObject *CPyDict_SetDefaultWithNone(PyObject *dict, PyObject *key) {
- return CPyDict_SetDefault(dict, key, Py_None);
- }
- PyObject *CPyDict_SetDefaultWithEmptyDatatype(PyObject *dict, PyObject *key,
- int data_type) {
- PyObject *res = CPyDict_GetItem(dict, key);
- if (!res) {
- // CPyDict_GetItem() would generates a PyExc_KeyError
- // when key is not found.
- PyErr_Clear();
- PyObject *new_obj;
- if (data_type == 1) {
- new_obj = PyList_New(0);
- } else if (data_type == 2) {
- new_obj = PyDict_New();
- } else if (data_type == 3) {
- new_obj = PySet_New(NULL);
- } else {
- return NULL;
- }
- if (CPyDict_SetItem(dict, key, new_obj) == -1) {
- return NULL;
- } else {
- return new_obj;
- }
- } else {
- return res;
- }
- }
- int CPyDict_SetItem(PyObject *dict, PyObject *key, PyObject *value) {
- if (PyDict_CheckExact(dict)) {
- return PyDict_SetItem(dict, key, value);
- } else {
- return PyObject_SetItem(dict, key, value);
- }
- }
- static inline int CPy_ObjectToStatus(PyObject *obj) {
- if (obj) {
- Py_DECREF(obj);
- return 0;
- } else {
- return -1;
- }
- }
- static int CPyDict_UpdateGeneral(PyObject *dict, PyObject *stuff) {
- _Py_IDENTIFIER(update);
- PyObject *res = _PyObject_CallMethodIdOneArg(dict, &PyId_update, stuff);
- return CPy_ObjectToStatus(res);
- }
- int CPyDict_UpdateInDisplay(PyObject *dict, PyObject *stuff) {
- // from https://github.com/python/cpython/blob/55d035113dfb1bd90495c8571758f504ae8d4802/Python/ceval.c#L2710
- int ret = PyDict_Update(dict, stuff);
- if (ret < 0) {
- if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
- PyErr_Format(PyExc_TypeError,
- "'%.200s' object is not a mapping",
- Py_TYPE(stuff)->tp_name);
- }
- }
- return ret;
- }
- int CPyDict_Update(PyObject *dict, PyObject *stuff) {
- if (PyDict_CheckExact(dict)) {
- return PyDict_Update(dict, stuff);
- } else {
- return CPyDict_UpdateGeneral(dict, stuff);
- }
- }
- int CPyDict_UpdateFromAny(PyObject *dict, PyObject *stuff) {
- if (PyDict_CheckExact(dict)) {
- // Argh this sucks
- _Py_IDENTIFIER(keys);
- if (PyDict_Check(stuff) || _CPyObject_HasAttrId(stuff, &PyId_keys)) {
- return PyDict_Update(dict, stuff);
- } else {
- return PyDict_MergeFromSeq2(dict, stuff, 1);
- }
- } else {
- return CPyDict_UpdateGeneral(dict, stuff);
- }
- }
- PyObject *CPyDict_FromAny(PyObject *obj) {
- if (PyDict_Check(obj)) {
- return PyDict_Copy(obj);
- } else {
- int res;
- PyObject *dict = PyDict_New();
- if (!dict) {
- return NULL;
- }
- _Py_IDENTIFIER(keys);
- if (_CPyObject_HasAttrId(obj, &PyId_keys)) {
- res = PyDict_Update(dict, obj);
- } else {
- res = PyDict_MergeFromSeq2(dict, obj, 1);
- }
- if (res < 0) {
- Py_DECREF(dict);
- return NULL;
- }
- return dict;
- }
- }
- PyObject *CPyDict_KeysView(PyObject *dict) {
- if (PyDict_CheckExact(dict)){
- return _CPyDictView_New(dict, &PyDictKeys_Type);
- }
- _Py_IDENTIFIER(keys);
- return _PyObject_CallMethodIdNoArgs(dict, &PyId_keys);
- }
- PyObject *CPyDict_ValuesView(PyObject *dict) {
- if (PyDict_CheckExact(dict)){
- return _CPyDictView_New(dict, &PyDictValues_Type);
- }
- _Py_IDENTIFIER(values);
- return _PyObject_CallMethodIdNoArgs(dict, &PyId_values);
- }
- PyObject *CPyDict_ItemsView(PyObject *dict) {
- if (PyDict_CheckExact(dict)){
- return _CPyDictView_New(dict, &PyDictItems_Type);
- }
- _Py_IDENTIFIER(items);
- return _PyObject_CallMethodIdNoArgs(dict, &PyId_items);
- }
- PyObject *CPyDict_Keys(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- return PyDict_Keys(dict);
- }
- // Inline generic fallback logic to also return a list.
- PyObject *list = PyList_New(0);
- _Py_IDENTIFIER(keys);
- PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_keys);
- if (view == NULL) {
- return NULL;
- }
- PyObject *res = _PyList_Extend((PyListObject *)list, view);
- Py_DECREF(view);
- if (res == NULL) {
- return NULL;
- }
- Py_DECREF(res);
- return list;
- }
- PyObject *CPyDict_Values(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- return PyDict_Values(dict);
- }
- // Inline generic fallback logic to also return a list.
- PyObject *list = PyList_New(0);
- _Py_IDENTIFIER(values);
- PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_values);
- if (view == NULL) {
- return NULL;
- }
- PyObject *res = _PyList_Extend((PyListObject *)list, view);
- Py_DECREF(view);
- if (res == NULL) {
- return NULL;
- }
- Py_DECREF(res);
- return list;
- }
- PyObject *CPyDict_Items(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- return PyDict_Items(dict);
- }
- // Inline generic fallback logic to also return a list.
- PyObject *list = PyList_New(0);
- _Py_IDENTIFIER(items);
- PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_items);
- if (view == NULL) {
- return NULL;
- }
- PyObject *res = _PyList_Extend((PyListObject *)list, view);
- Py_DECREF(view);
- if (res == NULL) {
- return NULL;
- }
- Py_DECREF(res);
- return list;
- }
- char CPyDict_Clear(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- PyDict_Clear(dict);
- } else {
- _Py_IDENTIFIER(clear);
- PyObject *res = _PyObject_CallMethodIdNoArgs(dict, &PyId_clear);
- if (res == NULL) {
- return 0;
- }
- }
- return 1;
- }
- PyObject *CPyDict_Copy(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- return PyDict_Copy(dict);
- }
- _Py_IDENTIFIER(copy);
- return _PyObject_CallMethodIdNoArgs(dict, &PyId_copy);
- }
- PyObject *CPyDict_GetKeysIter(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- // Return dict itself to indicate we can use fast path instead.
- Py_INCREF(dict);
- return dict;
- }
- return PyObject_GetIter(dict);
- }
- PyObject *CPyDict_GetItemsIter(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- // Return dict itself to indicate we can use fast path instead.
- Py_INCREF(dict);
- return dict;
- }
- _Py_IDENTIFIER(items);
- PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_items);
- if (view == NULL) {
- return NULL;
- }
- PyObject *iter = PyObject_GetIter(view);
- Py_DECREF(view);
- return iter;
- }
- PyObject *CPyDict_GetValuesIter(PyObject *dict) {
- if (PyDict_CheckExact(dict)) {
- // Return dict itself to indicate we can use fast path instead.
- Py_INCREF(dict);
- return dict;
- }
- _Py_IDENTIFIER(values);
- PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_values);
- if (view == NULL) {
- return NULL;
- }
- PyObject *iter = PyObject_GetIter(view);
- Py_DECREF(view);
- return iter;
- }
- static void _CPyDict_FromNext(tuple_T3CIO *ret, PyObject *dict_iter) {
- // Get next item from iterator and set "should continue" flag.
- ret->f2 = PyIter_Next(dict_iter);
- if (ret->f2 == NULL) {
- ret->f0 = 0;
- Py_INCREF(Py_None);
- ret->f2 = Py_None;
- } else {
- ret->f0 = 1;
- }
- }
- // Helpers for fast dictionary iteration, return a single tuple
- // instead of writing to multiple registers, for exact dicts use
- // the fast path, and fall back to generic iterator logic for subclasses.
- tuple_T3CIO CPyDict_NextKey(PyObject *dict_or_iter, CPyTagged offset) {
- tuple_T3CIO ret;
- Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset);
- PyObject *dummy;
- if (PyDict_CheckExact(dict_or_iter)) {
- ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &ret.f2, &dummy);
- if (ret.f0) {
- ret.f1 = CPyTagged_FromSsize_t(py_offset);
- } else {
- // Set key to None, so mypyc can manage refcounts.
- ret.f1 = 0;
- ret.f2 = Py_None;
- }
- // PyDict_Next() returns borrowed references.
- Py_INCREF(ret.f2);
- } else {
- // offset is dummy in this case, just use the old value.
- ret.f1 = offset;
- _CPyDict_FromNext(&ret, dict_or_iter);
- }
- return ret;
- }
- tuple_T3CIO CPyDict_NextValue(PyObject *dict_or_iter, CPyTagged offset) {
- tuple_T3CIO ret;
- Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset);
- PyObject *dummy;
- if (PyDict_CheckExact(dict_or_iter)) {
- ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &dummy, &ret.f2);
- if (ret.f0) {
- ret.f1 = CPyTagged_FromSsize_t(py_offset);
- } else {
- // Set value to None, so mypyc can manage refcounts.
- ret.f1 = 0;
- ret.f2 = Py_None;
- }
- // PyDict_Next() returns borrowed references.
- Py_INCREF(ret.f2);
- } else {
- // offset is dummy in this case, just use the old value.
- ret.f1 = offset;
- _CPyDict_FromNext(&ret, dict_or_iter);
- }
- return ret;
- }
- tuple_T4CIOO CPyDict_NextItem(PyObject *dict_or_iter, CPyTagged offset) {
- tuple_T4CIOO ret;
- Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset);
- if (PyDict_CheckExact(dict_or_iter)) {
- ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &ret.f2, &ret.f3);
- if (ret.f0) {
- ret.f1 = CPyTagged_FromSsize_t(py_offset);
- } else {
- // Set key and value to None, so mypyc can manage refcounts.
- ret.f1 = 0;
- ret.f2 = Py_None;
- ret.f3 = Py_None;
- }
- } else {
- ret.f1 = offset;
- PyObject *item = PyIter_Next(dict_or_iter);
- if (item == NULL || !PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2) {
- if (item != NULL) {
- PyErr_SetString(PyExc_TypeError, "a tuple of length 2 expected");
- }
- ret.f0 = 0;
- ret.f2 = Py_None;
- ret.f3 = Py_None;
- } else {
- ret.f0 = 1;
- ret.f2 = PyTuple_GET_ITEM(item, 0);
- ret.f3 = PyTuple_GET_ITEM(item, 1);
- Py_DECREF(item);
- }
- }
- // PyDict_Next() returns borrowed references.
- Py_INCREF(ret.f2);
- Py_INCREF(ret.f3);
- return ret;
- }
- int CPyMapping_Check(PyObject *obj) {
- return Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MAPPING;
- }
|