3#ifndef __NUITKA_DICTIONARIES_H__
4#define __NUITKA_DICTIONARIES_H__
6static inline Py_ssize_t DICT_SIZE(PyObject *dict) {
8 assert(PyDict_CheckExact(dict));
10 return ((PyDictObject *)dict)->ma_used;
13static inline PyDictObject *MODULE_DICT(PyObject *module) {
16 PyDictObject *dict = (PyDictObject *)(((
PyModuleObject *)module)->md_dict);
21#if PYTHON_VERSION < 0x300
24typedef PyDictEntry *Nuitka_DictEntryHandle;
26static PyDictEntry *GET_STRING_DICT_ENTRY(PyDictObject *dict, Nuitka_StringObject *key) {
27 assert(PyDict_CheckExact(dict));
28 assert(Nuitka_String_CheckExact(key));
30 Py_hash_t hash = key->ob_shash;
34 if (unlikely(hash == -1)) {
35 hash = PyString_Type.tp_hash((PyObject *)key);
39 PyDictEntry *entry = dict->ma_lookup(dict, (PyObject *)key, hash);
43 assert(entry != NULL);
48NUITKA_MAY_BE_UNUSED
static PyObject *GET_DICT_ENTRY_VALUE(Nuitka_DictEntryHandle handle) {
return handle->me_value; }
50NUITKA_MAY_BE_UNUSED
static void SET_DICT_ENTRY_VALUE(Nuitka_DictEntryHandle handle, PyObject *value) {
51 handle->me_value = value;
54static PyObject *GET_STRING_DICT_VALUE(PyDictObject *dict, Nuitka_StringObject *key) {
55 return GET_STRING_DICT_ENTRY(dict, key)->me_value;
64#if PYTHON_VERSION < 0x3b0
73#if PYTHON_VERSION < 0x360
74typedef PyDictKeyEntry *(*dict_lookup_func)(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr);
75#elif PYTHON_VERSION < 0x370
76typedef Py_ssize_t (*dict_lookup_func)(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr,
79typedef Py_ssize_t (*dict_lookup_func)(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
84#if PYTHON_VERSION < 0x3b0
86#define DK_SIZE(dk) ((dk)->dk_size)
87struct _dictkeysobject {
90 dict_lookup_func dk_lookup;
92#if PYTHON_VERSION < 0x360
93 PyDictKeyEntry dk_entries[1];
95 Py_ssize_t dk_nentries;
96#if PYTHON_VERSION < 0x370
114#if PYTHON_VERSION >= 0x360
116#if PYTHON_VERSION < 0x3b0
118#define DK_IXSIZE(dk) \
119 (DK_SIZE(dk) <= 0xff ? 1 : DK_SIZE(dk) <= 0xffff ? 2 : DK_SIZE(dk) <= 0xffffffff ? 4 : sizeof(int64_t))
121#define DK_IXSIZE(dk) (DK_SIZE(dk) <= 0xff ? 1 : DK_SIZE(dk) <= 0xffff ? 2 : sizeof(int32_t))
124#if PYTHON_VERSION < 0x370
125#define DK_ENTRIES(dk) ((PyDictKeyEntry *)(&(dk)->dk_indices.as_1[DK_SIZE(dk) * DK_IXSIZE(dk)]))
127#define DK_ENTRIES(dk) ((PyDictKeyEntry *)(&((int8_t *)((dk)->dk_indices))[DK_SIZE(dk) * DK_IXSIZE(dk)]))
133#define DK_ENTRIES(dk) (dk->dk_entries)
136#if PYTHON_VERSION < 0x3b0
137#define DK_VALUE(dk, i) dk->ma_values[i]
139#define DK_VALUE(dk, i) dk->ma_values->values[i]
142#define DK_MASK(dk) (DK_SIZE(dk) - 1)
144typedef PyObject **Nuitka_DictEntryHandle;
146#if PYTHON_VERSION >= 0x3b0
147extern Py_ssize_t Nuitka_Py_unicodekeys_lookup_unicode(PyDictKeysObject *dk, PyObject *key, Py_hash_t hash);
149extern Py_ssize_t Nuitka_PyDictLookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr);
150extern Py_ssize_t Nuitka_PyDictLookupStr(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr);
153static inline Py_hash_t Nuitka_Py_unicode_get_hash(PyObject *o) {
154 assert(PyUnicode_CheckExact(o));
156 return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyUnicodeObject *)o)->_base._base.hash);
159static Nuitka_DictEntryHandle GET_STRING_DICT_ENTRY(PyDictObject *dict, Nuitka_StringObject *key) {
160 assert(PyDict_CheckExact(dict));
161 assert(Nuitka_String_CheckExact(key));
163 Py_hash_t hash = Nuitka_Py_unicode_get_hash((PyObject *)key);
168 hash = PyUnicode_Type.tp_hash((PyObject *)key);
171#if PYTHON_VERSION < 0x360
172 PyObject **value_addr;
174 PyDictKeyEntry *entry = dict->ma_keys->dk_lookup(dict, (PyObject *)key, hash, &value_addr);
178 assert(entry != NULL);
182#elif PYTHON_VERSION < 0x370
183 PyObject **value_addr;
186 dict->ma_keys->dk_lookup(dict, (PyObject *)key, hash, &value_addr,
191#elif PYTHON_VERSION < 0x3b0
194 Py_ssize_t ix = dict->ma_keys->dk_lookup(dict, (PyObject *)key, hash, &value);
198 }
else if (_PyDict_HasSplitTable(dict)) {
199 return &dict->ma_values[ix];
201 return &DK_ENTRIES(dict->ma_keys)[ix].me_value;
206 NUITKA_MAY_BE_UNUSED Py_ssize_t found;
210 if (unlikely(dict->ma_keys->dk_kind == DICT_KEYS_GENERAL)) {
211 found = Nuitka_PyDictLookup(dict, (PyObject *)key, hash, &value);
213 found = Nuitka_PyDictLookupStr(dict, (PyObject *)key, hash, &value);
216 assert(found != DKIX_ERROR);
222NUITKA_MAY_BE_UNUSED
static PyObject *GET_DICT_ENTRY_VALUE(Nuitka_DictEntryHandle handle) {
return *handle; }
224NUITKA_MAY_BE_UNUSED
static void SET_DICT_ENTRY_VALUE(Nuitka_DictEntryHandle handle, PyObject *value) {
228NUITKA_MAY_BE_UNUSED
static PyObject *GET_STRING_DICT_VALUE(PyDictObject *dict, Nuitka_StringObject *key) {
229 Nuitka_DictEntryHandle handle = GET_STRING_DICT_ENTRY(dict, key);
231#if PYTHON_VERSION >= 0x360
232 if (handle == NULL) {
237 return GET_DICT_ENTRY_VALUE(handle);
242NUITKA_MAY_BE_UNUSED
static bool DICT_SET_ITEM(PyObject *dict, PyObject *key, PyObject *value) {
244 assert(PyDict_Check(dict));
248 int status = PyDict_SetItem(dict, key, value);
250 if (unlikely(status != 0)) {
257NUITKA_MAY_BE_UNUSED
static bool DICT_REMOVE_ITEM(PyObject *dict, PyObject *key) {
258 int status = PyDict_DelItem(dict, key);
260 if (unlikely(status == -1)) {
268extern PyObject *DICT_GET_ITEM_WITH_ERROR(PyThreadState *tstate, PyObject *dict, PyObject *key);
271extern PyObject *DICT_GET_ITEM_WITH_HASH_ERROR1(PyThreadState *tstate, PyObject *dict, PyObject *key);
272extern PyObject *DICT_GET_ITEM_WITH_HASH_ERROR0(PyThreadState *tstate, PyObject *dict, PyObject *key);
275extern PyObject *DICT_GET_ITEM1(PyThreadState *tstate, PyObject *dict, PyObject *key);
276extern PyObject *DICT_GET_ITEM0(PyThreadState *tstate, PyObject *dict, PyObject *key);
279extern int DICT_HAS_ITEM(PyThreadState *tstate, PyObject *dict, PyObject *key);
282extern PyObject *TO_DICT(PyThreadState *tstate, PyObject *seq_obj, PyObject *dict_obj);
287#if PYTHON_VERSION >= 0x360 && PYTHON_VERSION <= 0x3c0
288#define _NUITKA_MAINTAIN_DICT_VERSION_TAG 1
291#if _NUITKA_MAINTAIN_DICT_VERSION_TAG
292extern uint64_t nuitka_dict_version_tag_counter;
295NUITKA_MAY_BE_UNUSED
static void UPDATE_STRING_DICT0(PyDictObject *dict, Nuitka_StringObject *key, PyObject *value) {
298 Nuitka_DictEntryHandle entry = GET_STRING_DICT_ENTRY(dict, key);
300#if PYTHON_VERSION >= 0x360
302 DICT_SET_ITEM((PyObject *)dict, (PyObject *)key, value);
307 PyObject *old = GET_DICT_ENTRY_VALUE(entry);
314 if (likely(old != NULL)) {
316 SET_DICT_ENTRY_VALUE(entry, value);
318#if _NUITKA_MAINTAIN_DICT_VERSION_TAG
319 dict->ma_version_tag = nuitka_dict_version_tag_counter++;
325 DICT_SET_ITEM((PyObject *)dict, (PyObject *)key, value);
330NUITKA_MAY_BE_UNUSED
static void UPDATE_STRING_DICT_INPLACE(PyDictObject *dict, Nuitka_StringObject *key,
334 Nuitka_DictEntryHandle entry = GET_STRING_DICT_ENTRY(dict, key);
336#if PYTHON_VERSION >= 0x360
338 DICT_SET_ITEM((PyObject *)dict, (PyObject *)key, value);
347 PyObject *old = GET_DICT_ENTRY_VALUE(entry);
352 if (likely(old != NULL)) {
353 SET_DICT_ENTRY_VALUE(entry, value);
355#if _NUITKA_MAINTAIN_DICT_VERSION_TAG
356 dict->ma_version_tag = nuitka_dict_version_tag_counter++;
359 DICT_SET_ITEM((PyObject *)dict, (PyObject *)key, value);
370NUITKA_MAY_BE_UNUSED
static void UPDATE_STRING_DICT1(PyDictObject *dict, Nuitka_StringObject *key, PyObject *value) {
374 Nuitka_DictEntryHandle entry = GET_STRING_DICT_ENTRY(dict, key);
376#if PYTHON_VERSION >= 0x360
378 DICT_SET_ITEM((PyObject *)dict, (PyObject *)key, value);
387 PyObject *old = GET_DICT_ENTRY_VALUE(entry);
393 if (likely(old != NULL)) {
394 SET_DICT_ENTRY_VALUE(entry, value);
396#if _NUITKA_MAINTAIN_DICT_VERSION_TAG
397 dict->ma_version_tag = nuitka_dict_version_tag_counter++;
401 DICT_SET_ITEM((PyObject *)dict, (PyObject *)key, value);
412#if PYTHON_VERSION < 0x300
414extern PyObject *DICT_KEYS(PyObject *dict);
416extern PyObject *DICT_VALUES(PyObject *dict);
418extern PyObject *DICT_ITEMS(PyObject *dict);
422extern PyObject *DICT_ITERKEYS(PyThreadState *tstate, PyObject *dict);
425extern PyObject *DICT_ITERVALUES(PyThreadState *tstate, PyObject *dict);
428extern PyObject *DICT_ITERITEMS(PyThreadState *tstate, PyObject *dict);
431extern PyObject *DICT_VIEWKEYS(PyObject *dict);
434extern PyObject *DICT_VIEWVALUES(PyObject *dict);
437extern PyObject *DICT_VIEWITEMS(PyObject *dict);
440extern PyObject *DICT_COPY(PyThreadState *tstate, PyObject *dict);
443extern void DICT_CLEAR(PyObject *dict);
446extern bool Nuitka_DictNext(PyObject *dict, Py_ssize_t *pos, PyObject **key_ptr, PyObject **value_ptr);
448#if PYTHON_VERSION >= 0x3a0 && !defined(_NUITKA_EXPERIMENTAL_DISABLE_FREELIST_ALL) && \
449 !defined(_NUITKA_EXPERIMENTAL_DISABLE_FREELIST_DICT)
450#define NUITKA_DICT_HAS_FREELIST 1
453extern PyObject *MAKE_DICT_EMPTY(PyThreadState *tstate);
455#define NUITKA_DICT_HAS_FREELIST 0
456#define MAKE_DICT_EMPTY(tstate) PyDict_New()
460extern PyObject *MAKE_DICT(PyObject **pairs, Py_ssize_t size);
462extern PyObject *MAKE_DICT_X(PyObject **pairs, Py_ssize_t size);
464extern PyObject *MAKE_DICT_X_CSTR(
char const **keys, PyObject **values, Py_ssize_t size);