diff --git a/Objects/dict-common.h b/Objects/dict-common.h index 3e524686b4..f97994ea83 100644 --- a/Objects/dict-common.h +++ b/Objects/dict-common.h @@ -45,31 +45,28 @@ struct _dictkeysobject { /* Number of used entries in dk_entries. */ Py_ssize_t dk_nentries; +}; - /* Actual hash table of dk_size entries. It holds indices in dk_entries, - or DKIX_EMPTY(-1) or DKIX_DUMMY(-2). - - Indices must be: 0 <= indice < USABLE_FRACTION(dk_size). +struct _dictkeys_int8 { + struct _dictkeysobject base; + int8_t dk_indices[]; +}; - The size in bytes of an indice depends on dk_size: +struct _dictkeys_int16 { + struct _dictkeysobject base; + int16_t dk_indices[]; +}; - - 1 byte if dk_size <= 0xff (char*) - - 2 bytes if dk_size <= 0xffff (int16_t*) - - 4 bytes if dk_size <= 0xffffffff (int32_t*) - - 8 bytes otherwise (int64_t*) +struct _dictkeys_int32 { + struct _dictkeysobject base; + int32_t dk_indices[]; +}; - Dynamically sized, 8 is minimum. */ - union { - int8_t as_1[8]; - int16_t as_2[4]; - int32_t as_4[2]; #if SIZEOF_VOID_P > 4 - int64_t as_8[1]; +struct _dictkeys_int64 { + struct _dictkeysobject base; + int64_t dk_indices[]; #endif - } dk_indices; - - /* "PyDictKeyEntry dk_entries[dk_usable];" array follows: - see the DK_ENTRIES() macro */ }; #endif diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 01d913bfce..cebabb1df9 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -298,7 +298,7 @@ PyDict_Fini(void) 2 : sizeof(int32_t)) #endif #define DK_ENTRIES(dk) \ - ((PyDictKeyEntry*)(&(dk)->dk_indices.as_1[DK_SIZE(dk) * DK_IXSIZE(dk)])) + ((PyDictKeyEntry*)(&((struct _dictkeys_int8 *)dk)->dk_indices[DK_SIZE(dk) * DK_IXSIZE(dk)])) #define DK_DEBUG_INCREF _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA #define DK_DEBUG_DECREF _Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA @@ -316,21 +316,21 @@ dk_get_index(PyDictKeysObject *keys, Py_ssize_t i) Py_ssize_t ix; if (s <= 0xff) { - int8_t *indices = keys->dk_indices.as_1; + int8_t *indices = ((struct _dictkeys_int8 *)keys)->dk_indices; ix = indices[i]; } else if (s <= 0xffff) { - int16_t *indices = keys->dk_indices.as_2; + int16_t *indices = ((struct _dictkeys_int16 *)keys)->dk_indices; ix = indices[i]; } #if SIZEOF_VOID_P > 4 else if (s > 0xffffffff) { - int64_t *indices = keys->dk_indices.as_8; + int64_t *indices = ((struct _dictkeys_int64 *)keys)->dk_indices; ix = indices[i]; } #endif else { - int32_t *indices = keys->dk_indices.as_4; + int32_t *indices = ((struct _dictkeys_int32 *)keys)->dk_indices; ix = indices[i]; } assert(ix >= DKIX_DUMMY); @@ -346,23 +346,23 @@ dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) assert(ix >= DKIX_DUMMY); if (s <= 0xff) { - int8_t *indices = keys->dk_indices.as_1; + int8_t *indices = ((struct _dictkeys_int8 *)keys)->dk_indices; assert(ix <= 0x7f); indices[i] = (char)ix; } else if (s <= 0xffff) { - int16_t *indices = keys->dk_indices.as_2; + int16_t *indices = ((struct _dictkeys_int16 *)keys)->dk_indices; assert(ix <= 0x7fff); indices[i] = (int16_t)ix; } #if SIZEOF_VOID_P > 4 else if (s > 0xffffffff) { - int64_t *indices = keys->dk_indices.as_8; + int64_t *indices = ((struct _dictkeys_int64 *)keys)->dk_indices; indices[i] = ix; } #endif else { - int32_t *indices = keys->dk_indices.as_4; + int32_t *indices = ((struct _dictkeys_int32 *)keys)->dk_indices; assert(ix <= 0x7fffffff); indices[i] = (int32_t)ix; } @@ -415,19 +415,18 @@ dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) /* This immutable, empty PyDictKeysObject is used for PyDict_Clear() * (which cannot fail and thus can do no allocation). */ -static PyDictKeysObject empty_keys_struct = { +static struct _dictkeys_int8 empty_keys_struct = { { 1, /* dk_refcnt */ 1, /* dk_size */ lookdict_split, /* dk_lookup */ 0, /* dk_usable (immutable) */ - 0, /* dk_nentries */ - .dk_indices = { .as_1 = {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, - DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}}, + 0, /* dk_nentries */}, + {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}, }; static PyObject *empty_values[1] = { NULL }; -#define Py_EMPTY_KEYS &empty_keys_struct +#define Py_EMPTY_KEYS ((PyDictKeysObject *)&empty_keys_struct) /* Uncomment to check the dict content in _PyDict_CheckConsistency() */ /* #define DEBUG_PYDICT */ @@ -530,7 +529,6 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size) } else { dk = PyObject_MALLOC(sizeof(PyDictKeysObject) - - Py_MEMBER_SIZE(PyDictKeysObject, dk_indices) + es * size + sizeof(PyDictKeyEntry) * usable); if (dk == NULL) { @@ -543,7 +541,7 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size) dk->dk_usable = usable; dk->dk_lookup = lookdict_unicode_nodummy; dk->dk_nentries = 0; - memset(&dk->dk_indices.as_1[0], 0xff, es * size); + memset(&((struct _dictkeys_int8 *)dk)->dk_indices, 0xff, es * size); memset(DK_ENTRIES(dk), 0, sizeof(PyDictKeyEntry) * usable); return dk; } @@ -3007,7 +3005,6 @@ _PyDict_SizeOf(PyDictObject *mp) in the type object. */ if (mp->ma_keys->dk_refcnt == 1) res += (sizeof(PyDictKeysObject) - - Py_MEMBER_SIZE(PyDictKeysObject, dk_indices) + DK_IXSIZE(mp->ma_keys) * size + sizeof(PyDictKeyEntry) * usable); return res; @@ -3017,7 +3014,6 @@ Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys) { return (sizeof(PyDictKeysObject) - - Py_MEMBER_SIZE(PyDictKeysObject, dk_indices) + DK_IXSIZE(keys) * DK_SIZE(keys) + USABLE_FRACTION(DK_SIZE(keys)) * sizeof(PyDictKeyEntry)); }