gdnative_python/generation/builtins_templates/dictionary.tmpl.pxi

211 lines
8.2 KiB
Cython
Raw Normal View History

{%- block pxd_header %}
{% endblock -%}
{%- block pyx_header %}
{% endblock -%}
{# We can't do const in Python #}
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_operator_index_const") }}
@cython.final
cdef class Dictionary:
{% block cdef_attributes %}
2023-06-02 11:05:45 +02:00
cdef pandemonium_dictionary _gd_data
@staticmethod
cdef inline Dictionary new()
@staticmethod
2023-06-02 11:05:45 +02:00
cdef inline Dictionary from_ptr(const pandemonium_dictionary *_ptr)
cdef inline operator_update(self, Dictionary items)
cdef inline bint operator_equal(self, Dictionary other)
{% endblock %}
{% block python_defs %}
def __init__(self, iterable=None):
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_new") }}
if not iterable:
2023-06-02 11:05:45 +02:00
gdapi10.pandemonium_dictionary_new(&self._gd_data)
elif isinstance(iterable, Dictionary):
2023-06-02 11:05:45 +02:00
self._gd_data = gdapi12.pandemonium_dictionary_duplicate(&(<Dictionary>iterable)._gd_data, False)
# TODO: handle Pool*Array
elif isinstance(iterable, dict):
2023-06-02 11:05:45 +02:00
gdapi10.pandemonium_dictionary_new(&self._gd_data)
for k, v in iterable.items():
self[k] = v
else:
2023-06-02 11:05:45 +02:00
gdapi10.pandemonium_dictionary_new(&self._gd_data)
try:
for k, v in iterable:
self[k] = v
except ValueError as exc:
raise ValueError("dictionary update sequence element has length 1; 2 is required")
def __dealloc__(self):
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_destroy") }}
# /!\ if `__init__` is skipped, `_gd_data` must be initialized by
# hand otherwise we will get a segfault here
2023-06-02 11:05:45 +02:00
gdapi10.pandemonium_dictionary_destroy(&self._gd_data)
@staticmethod
cdef inline Dictionary new():
# Call to __new__ bypasses __init__ constructor
cdef Dictionary ret = Dictionary.__new__(Dictionary)
2023-06-02 11:05:45 +02:00
gdapi10.pandemonium_dictionary_new(&ret._gd_data)
return ret
@staticmethod
2023-06-02 11:05:45 +02:00
cdef inline Dictionary from_ptr(const pandemonium_dictionary *_ptr):
# Call to __new__ bypasses __init__ constructor
cdef Dictionary ret = Dictionary.__new__(Dictionary)
2023-06-02 11:05:45 +02:00
# `pandemonium_dictionary` is a cheap structure pointing on a refcounted hashmap
# of variants. Unlike it name could let think, `pandemonium_dictionary_new_copy`
# only increment the refcount of the underlying structure.
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_new_copy") }}
gdapi10.pandemonium_dictionary_new_copy(&ret._gd_data, _ptr)
return ret
def __repr__(self):
repr_dict = {}
for k, v in self.items():
if isinstance(k, GDString):
k = str(k)
if isinstance(v, GDString):
v = str(v)
repr_dict[k] = v
return f"<Dictionary({repr_dict})>"
def __getitem__(self, object key):
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_operator_index") }}
cdef pandemonium_variant var_key
if not pyobj_to_pandemonium_variant(key, &var_key):
raise TypeError(f"Cannot convert `{key!r}` to Godot Variant")
2023-06-02 11:05:45 +02:00
cdef pandemonium_variant *p_var_ret = gdapi10.pandemonium_dictionary_operator_index(&self._gd_data, &var_key)
gdapi10.pandemonium_variant_destroy(&var_key)
if p_var_ret == NULL:
raise KeyError(key)
else:
2023-06-02 11:05:45 +02:00
return pandemonium_variant_to_pyobj(p_var_ret)
{{ render_method("set", py_name="__setitem__") | indent }}
def __delitem__(self, object key):
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_erase_with_return") }}
cdef pandemonium_variant var_key
if not pyobj_to_pandemonium_variant(key, &var_key):
raise TypeError(f"Cannot convert `{key!r}` to Godot Variant")
2023-06-02 11:05:45 +02:00
cdef pandemonium_bool ret = gdapi11.pandemonium_dictionary_erase_with_return(&self._gd_data, &var_key)
gdapi10.pandemonium_variant_destroy(&var_key)
if not ret:
raise KeyError(key)
def __iter__(self):
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_next") }}
cdef pandemonium_variant *p_key = NULL
# TODO: mid iteration mutation should throw exception ?
while True:
2023-06-02 11:05:45 +02:00
p_key = gdapi10.pandemonium_dictionary_next(&self._gd_data, p_key)
if p_key == NULL:
return
2023-06-02 11:05:45 +02:00
yield pandemonium_variant_to_pyobj(p_key)
def __copy__(self):
return self.duplicate(False)
def __deepcopy__(self):
return self.duplicate(True)
def get(self, object key, object default=None):
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_get") }}
{{ force_mark_rendered("pandemonium_dictionary_get_with_default") }}
cdef pandemonium_variant var_key
pyobj_to_pandemonium_variant(key, &var_key)
cdef pandemonium_variant var_ret
cdef pandemonium_variant var_default
if default is not None:
2023-06-02 11:05:45 +02:00
pyobj_to_pandemonium_variant(default, &var_default)
var_ret = gdapi11.pandemonium_dictionary_get_with_default(&self._gd_data, &var_key, &var_default)
gdapi10.pandemonium_variant_destroy(&var_default)
else:
2023-06-02 11:05:45 +02:00
var_ret = gdapi10.pandemonium_dictionary_get(&self._gd_data, &var_key)
gdapi10.pandemonium_variant_destroy(&var_key)
cdef object ret = pandemonium_variant_to_pyobj(&var_ret)
gdapi10.pandemonium_variant_destroy(&var_ret)
return ret
cdef inline operator_update(self, Dictionary items):
2023-06-02 11:05:45 +02:00
cdef pandemonium_variant *p_value
cdef pandemonium_variant *p_key = NULL
while True:
2023-06-02 11:05:45 +02:00
p_key = gdapi10.pandemonium_dictionary_next(&items._gd_data, p_key)
if p_key == NULL:
break
2023-06-02 11:05:45 +02:00
p_value = gdapi10.pandemonium_dictionary_operator_index(&items._gd_data, p_key)
gdapi10.pandemonium_dictionary_set(&self._gd_data, p_key, p_value)
return self
def update(self, other):
cdef object k
cdef object v
if isinstance(other, Dictionary):
Dictionary.operator_update(self, other)
elif isinstance(other, dict):
for k, v in other.items():
self[k] = v
else:
2023-06-02 11:13:10 +02:00
raise TypeError("other must be pandemonium.Dictionary or dict")
def items(self):
2023-06-02 11:05:45 +02:00
cdef pandemonium_variant *p_key = NULL
cdef pandemonium_variant *p_value
# TODO: mid iteration mutation should throw exception ?
while True:
2023-06-02 11:05:45 +02:00
p_key = gdapi10.pandemonium_dictionary_next(&self._gd_data, p_key)
if p_key == NULL:
return
2023-06-02 11:05:45 +02:00
p_value = gdapi10.pandemonium_dictionary_operator_index(&self._gd_data, p_key)
yield pandemonium_variant_to_pyobj(p_key), pandemonium_variant_to_pyobj(p_value)
cdef inline bint operator_equal(self, Dictionary other):
if other is None:
return False
2023-06-02 11:05:45 +02:00
cdef pandemonium_int size = self.size()
if size != other.size():
return False
# TODO: gdnative should provide a function to do that
return dict(self) == dict(other)
def __eq__(self, other):
2023-06-02 11:13:10 +02:00
{# see https://github.com/pandemoniumengine/pandemonium/issues/27615 #}
2023-06-02 11:05:45 +02:00
{{ force_mark_rendered("pandemonium_dictionary_operator_equal") }}
try:
return Dictionary.operator_equal(self, <Dictionary?>other)
except TypeError:
return False
def __ne__(self, other):
try:
return not Dictionary.operator_equal(self, <Dictionary?>other)
except TypeError:
return True
{{ render_method("size", py_name="__len__") | indent }}
{{ render_method("hash", py_name="__hash__") | indent }}
{{ render_method("has", py_name="__contains__") | indent }}
{{ render_method("duplicate") | indent }}
{{ render_method("size") | indent }}
{{ render_method("empty") | indent }}
{{ render_method("clear") | indent }}
{{ render_method("has") | indent }}
{{ render_method("has_all") | indent }}
{{ render_method("erase") | indent }}
{{ render_method("hash") | indent }}
{{ render_method("keys") | indent }}
{{ render_method("values") | indent }}
{{ render_method("to_json") | indent }}
{% endblock %}
{%- block python_consts %}
{% endblock %}