@@ -52,7 +52,6 @@ Py_ssize_t _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyOb
52
52
int _PyDict_SetItem_Take2 (PyDictObject * op , PyObject * key , PyObject * value );
53
53
54
54
#define DKIX_EMPTY (-1)
55
- #define DKIX_DUMMY (-2) /* Used internally */
56
55
#define DKIX_ERROR (-3)
57
56
58
57
typedef enum {
@@ -61,6 +60,39 @@ typedef enum {
61
60
DICT_KEYS_SPLIT = 2
62
61
} DictKeysKind ;
63
62
63
+ // Currently, we support only 8-wide.
64
+ // But it is possible to use 16-wide when SSE2 is available, but NEON can not optimize it.
65
+ #define GROUP_WIDTH (8)
66
+
67
+ typedef union {
68
+ char c [GROUP_WIDTH ];
69
+ uint64_t u64 ;
70
+ } group_control ;
71
+
72
+ typedef struct {
73
+ group_control control ;
74
+ uint8_t index [GROUP_WIDTH ];
75
+ } group8 ; // 16byte
76
+
77
+ typedef struct {
78
+ group_control control ;
79
+ uint16_t index [GROUP_WIDTH ];
80
+ } group16 ; // 24byte
81
+
82
+ typedef struct {
83
+ group_control control ;
84
+ uint32_t index [GROUP_WIDTH ];
85
+ } group32 ; // 40byte
86
+
87
+ typedef struct {
88
+ group_control control ;
89
+ uint64_t index [GROUP_WIDTH ];
90
+ } group64 ; // 72byte
91
+
92
+ // todo: group64 can use uint8_t index[7*GROUP_WIDTH] instead.
93
+ // Then sizeof(group64) become 64byte. It is friendly to cache line.
94
+
95
+
64
96
/* See dictobject.c for actual layout of DictKeysObject */
65
97
struct _dictkeysobject {
66
98
Py_ssize_t dk_refcnt ;
@@ -80,20 +112,7 @@ struct _dictkeysobject {
80
112
/* Number of used entries in dk_entries. */
81
113
Py_ssize_t dk_nentries ;
82
114
83
- /* Actual hash table of dk_size entries. It holds indices in dk_entries,
84
- or DKIX_EMPTY(-1) or DKIX_DUMMY(-2).
85
-
86
- Indices must be: 0 <= indice < USABLE_FRACTION(dk_size).
87
-
88
- The size in bytes of an indice depends on dk_size:
89
-
90
- - 1 byte if dk_size <= 0xff (char*)
91
- - 2 bytes if dk_size <= 0xffff (int16_t*)
92
- - 4 bytes if dk_size <= 0xffffffff (int32_t*)
93
- - 8 bytes otherwise (int64_t*)
94
-
95
- Dynamically sized, SIZEOF_VOID_P is minimum. */
96
- char dk_indices []; /* char is required to avoid strict aliasing. */
115
+ unsigned char dk_groups []; /* char is required to avoid strict aliasing. */
97
116
98
117
/* "PyDictKeyEntry dk_entries[dk_usable];" array follows:
99
118
see the DK_ENTRIES() macro */
@@ -113,23 +132,19 @@ struct _dictvalues {
113
132
PyObject * values [1 ];
114
133
};
115
134
116
- #define DK_LOG_SIZE (dk ) ((dk)->dk_log2_size)
117
- #if SIZEOF_VOID_P > 4
135
+ #define DK_LOG_SIZE (dk ) ((dk)->dk_log2_size+3 )
136
+
118
137
#define DK_SIZE (dk ) (((int64_t)1)<<DK_LOG_SIZE(dk))
119
- #define DK_IXSIZE (dk ) \
120
- (DK_LOG_SIZE(dk) <= 7 ? \
121
- 1 : DK_LOG_SIZE(dk) <= 15 ? \
122
- 2 : DK_LOG_SIZE(dk) <= 31 ? \
123
- 4 : sizeof(int64_t))
124
- #else
125
- #define DK_SIZE (dk ) (1<<DK_LOG_SIZE(dk))
126
- #define DK_IXSIZE (dk ) \
127
- (DK_LOG_SIZE(dk) <= 7 ? \
128
- 1 : DK_LOG_SIZE(dk) <= 15 ? \
129
- 2 : sizeof(int32_t))
130
- #endif
138
+ #define DK_GROUPS (dk ) (((int64_t)1)<<((dk)->dk_log2_size))
139
+
140
+ #define DK_GROUP_SIZE (dk ) \
141
+ (DK_LOG_SIZE(dk) <= 8 ? sizeof(group8) \
142
+ : DK_LOG_SIZE(dk) <= 16 ? sizeof(group16) \
143
+ : DK_LOG_SIZE(dk) <= 32 ? sizeof(group32) \
144
+ : sizeof(group64))
145
+
131
146
#define DK_ENTRIES (dk ) \
132
- ((PyDictKeyEntry*)(&((int8_t*)(( dk)->dk_indices))[DK_SIZE (dk) * DK_IXSIZE(dk )]))
147
+ ((PyDictKeyEntry*)(&((dk)->dk_groups)[DK_GROUP_SIZE (dk) << ((dk)->dk_log2_size )]))
133
148
134
149
extern uint64_t _pydict_global_version ;
135
150
0 commit comments