diff options
author | Federico Caselli <cfederico87@gmail.com> | 2021-01-01 16:09:01 +0100 |
---|---|---|
committer | Federico Caselli <cfederico87@gmail.com> | 2021-12-17 21:29:05 +0100 |
commit | 76fa211620de167b76846f0e5db5b64b8756ad48 (patch) | |
tree | c435dbf6585b3758dc78ee82bf114e162a25d0e1 /lib/sqlalchemy/cextension/immutabledict.c | |
parent | 3543fcc9c9601e81560d055ceadaea05c75815c0 (diff) | |
download | sqlalchemy-workflow_test_cython.tar.gz |
Replace c extension with cython versions.workflow_test_cython
Re-implement c version immutabledict / processors / resultproxy / utils with cython.
Performance is in general in par or better than the c version
Added a collection module that has cython version of OrderedSet and IdentitySet
Added a new test/perf file to compare the implementations.
Run ``python test/perf/compiled_extensions.py all`` to execute the comparison test.
See results here: https://docs.google.com/document/d/1nOcDGojHRtXEkuy4vNXcW_XOJd9gqKhSeALGG3kYr6A/edit?usp=sharing
Fixes: #7256
Change-Id: I2930ef1894b5048210384728118e586e813f6a76
Signed-off-by: Federico Caselli <cfederico87@gmail.com>
Diffstat (limited to 'lib/sqlalchemy/cextension/immutabledict.c')
-rw-r--r-- | lib/sqlalchemy/cextension/immutabledict.c | 526 |
1 files changed, 0 insertions, 526 deletions
diff --git a/lib/sqlalchemy/cextension/immutabledict.c b/lib/sqlalchemy/cextension/immutabledict.c deleted file mode 100644 index 1188dcd2b..000000000 --- a/lib/sqlalchemy/cextension/immutabledict.c +++ /dev/null @@ -1,526 +0,0 @@ -/* -immuatbledict.c -Copyright (C) 2005-2021 the SQLAlchemy authors and contributors <see AUTHORS file> - -This module is part of SQLAlchemy and is released under -the MIT License: https://www.opensource.org/licenses/mit-license.php -*/ - -#include <Python.h> - -#define MODULE_NAME "cimmutabledict" -#define MODULE_DOC "immutable dictionary implementation" - - -typedef struct { - PyObject_HEAD - PyObject *dict; -} ImmutableDict; - -static PyTypeObject ImmutableDictType; - - -#if PY_MAJOR_VERSION < 3 -/* For Python 2.7, VENDORED from cPython: https://github.com/python/cpython/commit/1c496178d2c863f135bd4a43e32e0f099480cd06 - This function was added to Python 2.7.12 as an underscore function. - - Variant of PyDict_GetItem() that doesn't suppress exceptions. - This returns NULL *with* an exception set if an exception occurred. - It returns NULL *without* an exception set if the key wasn't present. -*/ -PyObject * -PyDict_GetItemWithError(PyObject *op, PyObject *key) -{ - long hash; - PyDictObject *mp = (PyDictObject *)op; - PyDictEntry *ep; - if (!PyDict_Check(op)) { - PyErr_BadInternalCall(); - return NULL; - } - if (!PyString_CheckExact(key) || - (hash = ((PyStringObject *) key)->ob_shash) == -1) - { - hash = PyObject_Hash(key); - if (hash == -1) { - return NULL; - } - } - - ep = (mp->ma_lookup)(mp, key, hash); - if (ep == NULL) { - return NULL; - } - return ep->me_value; -} -#endif - -static PyObject * - -ImmutableDict_new(PyTypeObject *type, PyObject *args, PyObject *kw) - -{ - ImmutableDict *new_obj; - PyObject *arg_dict = NULL; - PyObject *our_dict; - - if (!PyArg_UnpackTuple(args, "ImmutableDict", 0, 1, &arg_dict)) { - return NULL; - } - - if (arg_dict != NULL && PyDict_CheckExact(arg_dict)) { - // going on the unproven theory that doing PyDict_New + PyDict_Update - // is faster than just calling CallObject, as we do below to - // accommodate for other dictionary argument forms - our_dict = PyDict_New(); - if (our_dict == NULL) { - return NULL; - } - - if (PyDict_Update(our_dict, arg_dict) == -1) { - Py_DECREF(our_dict); - return NULL; - } - } - else { - // for other calling styles, let PyDict figure it out - our_dict = PyObject_Call((PyObject *) &PyDict_Type, args, kw); - } - - new_obj = PyObject_GC_New(ImmutableDict, &ImmutableDictType); - if (new_obj == NULL) { - Py_DECREF(our_dict); - return NULL; - } - new_obj->dict = our_dict; - PyObject_GC_Track(new_obj); - - return (PyObject *)new_obj; - -} - - -Py_ssize_t -ImmutableDict_length(ImmutableDict *self) -{ - return PyDict_Size(self->dict); -} - -static PyObject * -ImmutableDict_subscript(ImmutableDict *self, PyObject *key) -{ - PyObject *value; -#if PY_MAJOR_VERSION >= 3 - PyObject *err_bytes; -#endif - - value = PyDict_GetItemWithError(self->dict, key); - - if (value == NULL) { - if (PyErr_Occurred() != NULL) { - // there was an error while hashing the key - return NULL; - } -#if PY_MAJOR_VERSION >= 3 - err_bytes = PyUnicode_AsUTF8String(key); - if (err_bytes == NULL) - return NULL; - PyErr_Format(PyExc_KeyError, "%s", PyBytes_AS_STRING(err_bytes)); -#else - PyErr_Format(PyExc_KeyError, "%s", PyString_AsString(key)); -#endif - return NULL; - } - - Py_INCREF(value); - - return value; -} - - -static void -ImmutableDict_dealloc(ImmutableDict *self) -{ - PyObject_GC_UnTrack(self); - Py_XDECREF(self->dict); - PyObject_GC_Del(self); -} - - -static PyObject * -ImmutableDict_reduce(ImmutableDict *self) -{ - return Py_BuildValue("O(O)", Py_TYPE(self), self->dict); -} - - -static PyObject * -ImmutableDict_repr(ImmutableDict *self) -{ - return PyUnicode_FromFormat("immutabledict(%R)", self->dict); -} - - -static PyObject * -ImmutableDict_union(PyObject *self, PyObject *args, PyObject *kw) -{ - PyObject *arg_dict, *new_dict; - - ImmutableDict *new_obj; - - if (!PyArg_UnpackTuple(args, "ImmutableDict", 0, 1, &arg_dict)) { - return NULL; - } - - if (!PyDict_CheckExact(arg_dict)) { - // if we didn't get a dict, and got lists of tuples or - // keyword args, make a dict - arg_dict = PyObject_Call((PyObject *) &PyDict_Type, args, kw); - if (arg_dict == NULL) { - return NULL; - } - } - else { - // otherwise we will use the dict as is - Py_INCREF(arg_dict); - } - - if (PyDict_Size(arg_dict) == 0) { - Py_DECREF(arg_dict); - Py_INCREF(self); - return self; - } - - new_dict = PyDict_New(); - if (new_dict == NULL) { - Py_DECREF(arg_dict); - return NULL; - } - - if (PyDict_Update(new_dict, ((ImmutableDict *)self)->dict) == -1) { - Py_DECREF(arg_dict); - Py_DECREF(new_dict); - return NULL; - } - - if (PyDict_Update(new_dict, arg_dict) == -1) { - Py_DECREF(arg_dict); - Py_DECREF(new_dict); - return NULL; - } - - Py_DECREF(arg_dict); - - new_obj = PyObject_GC_New(ImmutableDict, Py_TYPE(self)); - if (new_obj == NULL) { - Py_DECREF(new_dict); - return NULL; - } - - new_obj->dict = new_dict; - - PyObject_GC_Track(new_obj); - - return (PyObject *)new_obj; -} - - -static PyObject * -ImmutableDict_merge_with(PyObject *self, PyObject *args) -{ - PyObject *element, *arg, *new_dict = NULL; - - ImmutableDict *new_obj; - - Py_ssize_t num_args = PyTuple_Size(args); - Py_ssize_t i; - - for (i=0; i<num_args; i++) { - element = PyTuple_GetItem(args, i); - - if (element == NULL) { - Py_XDECREF(new_dict); - return NULL; - } - else if (element == Py_None) { - // none was passed, skip it - continue; - } - - if (!PyDict_CheckExact(element)) { - // not a dict, try to make a dict - - arg = PyTuple_Pack(1, element); - - element = PyObject_CallObject((PyObject *) &PyDict_Type, arg); - - Py_DECREF(arg); - - if (element == NULL) { - Py_XDECREF(new_dict); - return NULL; - } - } - else { - Py_INCREF(element); - if (PyDict_Size(element) == 0) { - continue; - } - } - - // initialize a new dictionary only if we receive data that - // is not empty. otherwise we return self at the end. - if (new_dict == NULL) { - - new_dict = PyDict_New(); - if (new_dict == NULL) { - Py_DECREF(element); - return NULL; - } - - if (PyDict_Update(new_dict, ((ImmutableDict *)self)->dict) == -1) { - Py_DECREF(element); - Py_DECREF(new_dict); - return NULL; - } - } - - if (PyDict_Update(new_dict, element) == -1) { - Py_DECREF(element); - Py_DECREF(new_dict); - return NULL; - } - - Py_DECREF(element); - } - - - if (new_dict != NULL) { - new_obj = PyObject_GC_New(ImmutableDict, Py_TYPE(self)); - if (new_obj == NULL) { - Py_DECREF(new_dict); - return NULL; - } - - new_obj->dict = new_dict; - PyObject_GC_Track(new_obj); - return (PyObject *)new_obj; - } - else { - Py_INCREF(self); - return self; - } - -} - - -static PyObject * -ImmutableDict_get(ImmutableDict *self, PyObject *args) -{ - PyObject *key; - PyObject *value; - PyObject *default_value = Py_None; - - if (!PyArg_UnpackTuple(args, "key", 1, 2, &key, &default_value)) { - return NULL; - } - - value = PyDict_GetItemWithError(self->dict, key); - - if (value == NULL) { - if (PyErr_Occurred() != NULL) { - // there was an error while hashing the key - return NULL; - } else { - // return default - Py_INCREF(default_value); - return default_value; - } - } else { - Py_INCREF(value); - return value; - } -} - -static PyObject * -ImmutableDict_keys(ImmutableDict *self) -{ - return PyDict_Keys(self->dict); -} - -static int -ImmutableDict_traverse(ImmutableDict *self, visitproc visit, void *arg) -{ - Py_VISIT(self->dict); - return 0; -} - -static PyObject * -ImmutableDict_richcompare(ImmutableDict *self, PyObject *other, int op) -{ - return PyObject_RichCompare(self->dict, other, op); -} - -static PyObject * -ImmutableDict_iter(ImmutableDict *self) -{ - return PyObject_GetIter(self->dict); -} - -static PyObject * -ImmutableDict_items(ImmutableDict *self) -{ - return PyDict_Items(self->dict); -} - -static PyObject * -ImmutableDict_values(ImmutableDict *self) -{ - return PyDict_Values(self->dict); -} - -static PyObject * -ImmutableDict_contains(ImmutableDict *self, PyObject *key) -{ - int ret; - - ret = PyDict_Contains(self->dict, key); - - if (ret == 1) Py_RETURN_TRUE; - else if (ret == 0) Py_RETURN_FALSE; - else return NULL; -} - -static PyMethodDef ImmutableDict_methods[] = { - {"union", (PyCFunction) ImmutableDict_union, METH_VARARGS | METH_KEYWORDS, - "provide a union of this dictionary with the given dictionary-like arguments"}, - {"merge_with", (PyCFunction) ImmutableDict_merge_with, METH_VARARGS, - "provide a union of this dictionary with those given"}, - {"keys", (PyCFunction) ImmutableDict_keys, METH_NOARGS, - "return dictionary keys"}, - - {"__contains__",(PyCFunction)ImmutableDict_contains, METH_O, - "test a member for containment"}, - - {"items", (PyCFunction) ImmutableDict_items, METH_NOARGS, - "return dictionary items"}, - {"values", (PyCFunction) ImmutableDict_values, METH_NOARGS, - "return dictionary values"}, - {"get", (PyCFunction) ImmutableDict_get, METH_VARARGS, - "get a value"}, - {"__reduce__", (PyCFunction)ImmutableDict_reduce, METH_NOARGS, - "Pickle support method."}, - {NULL}, -}; - - -static PyMappingMethods ImmutableDict_as_mapping = { - (lenfunc)ImmutableDict_length, /* mp_length */ - (binaryfunc)ImmutableDict_subscript, /* mp_subscript */ - 0 /* mp_ass_subscript */ -}; - - - - -static PyTypeObject ImmutableDictType = { - PyVarObject_HEAD_INIT(NULL, 0) - "sqlalchemy.cimmutabledict.immutabledict", /* tp_name */ - sizeof(ImmutableDict), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)ImmutableDict_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)ImmutableDict_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - &ImmutableDict_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC , /* tp_flags */ - "immutable dictionary", /* tp_doc */ - (traverseproc)ImmutableDict_traverse, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)ImmutableDict_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)ImmutableDict_iter, /* tp_iter */ - 0, /* tp_iternext */ - ImmutableDict_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - ImmutableDict_new, /* tp_new */ - 0, /* tp_free */ -}; - - - - - -static PyMethodDef module_methods[] = { - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif - - -#if PY_MAJOR_VERSION >= 3 - -static struct PyModuleDef module_def = { - PyModuleDef_HEAD_INIT, - MODULE_NAME, - MODULE_DOC, - -1, - module_methods -}; - -#define INITERROR return NULL - -PyMODINIT_FUNC -PyInit_cimmutabledict(void) - -#else - -#define INITERROR return - -PyMODINIT_FUNC -initcimmutabledict(void) - -#endif - -{ - PyObject *m; - - if (PyType_Ready(&ImmutableDictType) < 0) - INITERROR; - - -#if PY_MAJOR_VERSION >= 3 - m = PyModule_Create(&module_def); -#else - m = Py_InitModule3(MODULE_NAME, module_methods, MODULE_DOC); -#endif - if (m == NULL) - INITERROR; - - Py_INCREF(&ImmutableDictType); - PyModule_AddObject(m, "immutabledict", (PyObject *)&ImmutableDictType); - -#if PY_MAJOR_VERSION >= 3 - return m; -#endif -} |