summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/cyextension/immutabledict.pyx
diff options
context:
space:
mode:
authorFederico Caselli <cfederico87@gmail.com>2021-01-01 16:09:01 +0100
committerFederico Caselli <cfederico87@gmail.com>2021-12-17 21:29:05 +0100
commit76fa211620de167b76846f0e5db5b64b8756ad48 (patch)
treec435dbf6585b3758dc78ee82bf114e162a25d0e1 /lib/sqlalchemy/cyextension/immutabledict.pyx
parent3543fcc9c9601e81560d055ceadaea05c75815c0 (diff)
downloadsqlalchemy-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/cyextension/immutabledict.pyx')
-rw-r--r--lib/sqlalchemy/cyextension/immutabledict.pyx100
1 files changed, 100 insertions, 0 deletions
diff --git a/lib/sqlalchemy/cyextension/immutabledict.pyx b/lib/sqlalchemy/cyextension/immutabledict.pyx
new file mode 100644
index 000000000..89bcf3ed6
--- /dev/null
+++ b/lib/sqlalchemy/cyextension/immutabledict.pyx
@@ -0,0 +1,100 @@
+from cpython.dict cimport PyDict_New, PyDict_Update, PyDict_Size
+
+
+def _immutable_fn(obj):
+ raise TypeError("%s object is immutable" % obj.__class__.__name__)
+
+
+class ImmutableContainer:
+ def _immutable(self, *a,**kw):
+ _immutable_fn(self)
+
+ __delitem__ = __setitem__ = __setattr__ = _immutable
+
+
+cdef class immutabledict(dict):
+ def __repr__(self):
+ return f"immutabledict({dict.__repr__(self)})"
+
+ def union(self, *args, **kw):
+ cdef dict to_merge = None
+ cdef immutabledict result
+ cdef Py_ssize_t args_len = len(args)
+ if args_len > 1:
+ raise TypeError(
+ f'union expected at most 1 argument, got {args_len}'
+ )
+ if args_len == 1:
+ attribute = args[0]
+ if isinstance(attribute, dict):
+ to_merge = <dict> attribute
+ if to_merge is None:
+ to_merge = dict(*args, **kw)
+
+ if PyDict_Size(to_merge) == 0:
+ return self
+
+ # new + update is faster than immutabledict(self)
+ result = immutabledict()
+ PyDict_Update(result, self)
+ PyDict_Update(result, to_merge)
+ return result
+
+ def merge_with(self, *other):
+ cdef immutabledict result = None
+ cdef object d
+ cdef bint update = False
+ if not other:
+ return self
+ for d in other:
+ if d:
+ if update == False:
+ update = True
+ # new + update is faster than immutabledict(self)
+ result = immutabledict()
+ PyDict_Update(result, self)
+ PyDict_Update(
+ result, <dict>(d if isinstance(d, dict) else dict(d))
+ )
+
+ return self if update == False else result
+
+ def copy(self):
+ return self
+
+ def __reduce__(self):
+ return immutabledict, (dict(self), )
+
+ def __delitem__(self, k):
+ _immutable_fn(self)
+
+ def __setitem__(self, k, v):
+ _immutable_fn(self)
+
+ def __setattr__(self, k, v):
+ _immutable_fn(self)
+
+ def clear(self, *args, **kw):
+ _immutable_fn(self)
+
+ def pop(self, *args, **kw):
+ _immutable_fn(self)
+
+ def popitem(self, *args, **kw):
+ _immutable_fn(self)
+
+ def setdefault(self, *args, **kw):
+ _immutable_fn(self)
+
+ def update(self, *args, **kw):
+ _immutable_fn(self)
+
+ # PEP 584
+ def __ior__(self, other):
+ _immutable_fn(self)
+
+ def __or__(self, other):
+ return immutabledict(super().__or__(other))
+
+ def __ror__(self, other):
+ return immutabledict(super().__ror__(other))