Skip to content

Commit 5b0a303

Browse files
authored
bpo-40609: _Py_hashtable_t values become void* (GH-20065)
_Py_hashtable_t values become regular "void *" pointers. * Add _Py_hashtable_entry_t.data member * Remove _Py_hashtable_t.data_size member * Remove _Py_hashtable_t.get_func member. It is no longer needed to specialize _Py_hashtable_get() for a specific value size, since all entries now have the same size (void*). * Remove the following macros: * _Py_HASHTABLE_GET() * _Py_HASHTABLE_SET() * _Py_HASHTABLE_SET_NODATA() * _Py_HASHTABLE_POP() * Rename _Py_hashtable_pop() to _Py_hashtable_steal() * _Py_hashtable_foreach() callback now gets key and value rather than entry. * Remove _Py_hashtable_value_destroy_func type. value_destroy_func callback now only has a single parameter: data (void*).
1 parent d95bd42 commit 5b0a303

File tree

4 files changed

+140
-303
lines changed

4 files changed

+140
-303
lines changed

Include/internal/pycore_hashtable.h

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,9 @@ typedef struct {
3131

3232
Py_uhash_t key_hash;
3333
void *key;
34-
/* data (data_size bytes) follows */
34+
void *value;
3535
} _Py_hashtable_entry_t;
3636

37-
#define _Py_HASHTABLE_ENTRY_PDATA(ENTRY) \
38-
((const void *)((char *)(ENTRY) \
39-
+ sizeof(_Py_hashtable_entry_t)))
40-
41-
#define _Py_HASHTABLE_ENTRY_READ_DATA(TABLE, ENTRY, DATA) \
42-
do { \
43-
assert(sizeof(DATA) == (TABLE)->data_size); \
44-
memcpy(&(DATA), _Py_HASHTABLE_ENTRY_PDATA((ENTRY)), \
45-
sizeof(DATA)); \
46-
} while (0)
47-
4837

4938
/* _Py_hashtable: prototypes */
5039

@@ -55,12 +44,8 @@ typedef struct _Py_hashtable_t _Py_hashtable_t;
5544
typedef Py_uhash_t (*_Py_hashtable_hash_func) (const void *key);
5645
typedef int (*_Py_hashtable_compare_func) (const void *key1, const void *key2);
5746
typedef void (*_Py_hashtable_destroy_func) (void *key);
58-
typedef void (*_Py_hashtable_value_destroy_func) (_Py_hashtable_t *ht,
59-
_Py_hashtable_entry_t *entry);
6047
typedef _Py_hashtable_entry_t* (*_Py_hashtable_get_entry_func)(_Py_hashtable_t *ht,
6148
const void *key);
62-
typedef int (*_Py_hashtable_get_func) (_Py_hashtable_t *ht,
63-
const void *key, void *data);
6449

6550
typedef struct {
6651
/* allocate a memory block */
@@ -76,14 +61,12 @@ struct _Py_hashtable_t {
7661
size_t num_buckets;
7762
size_t entries; /* Total number of entries in the table. */
7863
_Py_slist_t *buckets;
79-
size_t data_size;
8064

81-
_Py_hashtable_get_func get_func;
8265
_Py_hashtable_get_entry_func get_entry_func;
8366
_Py_hashtable_hash_func hash_func;
8467
_Py_hashtable_compare_func compare_func;
8568
_Py_hashtable_destroy_func key_destroy_func;
86-
_Py_hashtable_value_destroy_func value_destroy_func;
69+
_Py_hashtable_destroy_func value_destroy_func;
8770
_Py_hashtable_allocator_t alloc;
8871
};
8972

@@ -96,95 +79,66 @@ PyAPI_FUNC(int) _Py_hashtable_compare_direct(
9679
const void *key2);
9780

9881
PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new(
99-
size_t data_size,
10082
_Py_hashtable_hash_func hash_func,
10183
_Py_hashtable_compare_func compare_func);
10284

10385
PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new_full(
104-
size_t data_size,
105-
size_t init_size,
10686
_Py_hashtable_hash_func hash_func,
10787
_Py_hashtable_compare_func compare_func,
10888
_Py_hashtable_destroy_func key_destroy_func,
109-
_Py_hashtable_value_destroy_func value_destroy_func,
89+
_Py_hashtable_destroy_func value_destroy_func,
11090
_Py_hashtable_allocator_t *allocator);
11191

11292
PyAPI_FUNC(void) _Py_hashtable_destroy(_Py_hashtable_t *ht);
11393

11494
PyAPI_FUNC(void) _Py_hashtable_clear(_Py_hashtable_t *ht);
11595

11696
typedef int (*_Py_hashtable_foreach_func) (_Py_hashtable_t *ht,
117-
_Py_hashtable_entry_t *entry,
118-
void *arg);
97+
const void *key, const void *value,
98+
void *user_data);
11999

120100
/* Call func() on each entry of the hashtable.
121101
Iteration stops if func() result is non-zero, in this case it's the result
122102
of the call. Otherwise, the function returns 0. */
123103
PyAPI_FUNC(int) _Py_hashtable_foreach(
124104
_Py_hashtable_t *ht,
125105
_Py_hashtable_foreach_func func,
126-
void *arg);
106+
void *user_data);
127107

128-
PyAPI_FUNC(size_t) _Py_hashtable_size(_Py_hashtable_t *ht);
108+
PyAPI_FUNC(size_t) _Py_hashtable_size(const _Py_hashtable_t *ht);
129109

130110
/* Add a new entry to the hash. The key must not be present in the hash table.
131-
Return 0 on success, -1 on memory error.
132-
133-
Don't call directly this function,
134-
but use _Py_HASHTABLE_SET() and _Py_HASHTABLE_SET_NODATA() macros */
111+
Return 0 on success, -1 on memory error. */
135112
PyAPI_FUNC(int) _Py_hashtable_set(
136113
_Py_hashtable_t *ht,
137114
const void *key,
138-
size_t data_size,
139-
const void *data);
140-
141-
#define _Py_HASHTABLE_SET(TABLE, KEY, DATA) \
142-
_Py_hashtable_set(TABLE, (KEY), sizeof(DATA), &(DATA))
143-
144-
#define _Py_HASHTABLE_SET_NODATA(TABLE, KEY) \
145-
_Py_hashtable_set(TABLE, (KEY), 0, NULL)
115+
void *value);
146116

147117

148118
/* Get an entry.
149-
Return NULL if the key does not exist.
150-
151-
Don't call directly this function, but use _Py_HASHTABLE_GET_ENTRY()
152-
macro */
119+
Return NULL if the key does not exist. */
153120
static inline _Py_hashtable_entry_t *
154121
_Py_hashtable_get_entry(_Py_hashtable_t *ht, const void *key)
155122
{
156123
return ht->get_entry_func(ht, key);
157124
}
158125

159-
#define _Py_HASHTABLE_GET_ENTRY(TABLE, KEY) \
160-
_Py_hashtable_get_entry(TABLE, (const void *)(KEY))
161126

127+
/* Get value from an entry.
128+
Return NULL if the entry is not found.
162129
163-
/* Get data from an entry. Copy entry data into data and return 1 if the entry
164-
exists, return 0 if the entry does not exist.
130+
Use _Py_hashtable_get_entry() to distinguish entry value equal to NULL
131+
and entry not found. */
132+
extern void *_Py_hashtable_get(_Py_hashtable_t *ht, const void *key);
165133

166-
Don't call directly this function, but use _Py_HASHTABLE_GET() macro */
167-
static inline int
168-
_Py_hashtable_get(_Py_hashtable_t *ht, const void *key,
169-
size_t data_size, void *data)
170-
{
171-
assert(data_size == ht->data_size);
172-
return ht->get_func(ht, key, data);
173-
}
174-
175-
#define _Py_HASHTABLE_GET(TABLE, KEY, DATA) \
176-
_Py_hashtable_get(TABLE, (KEY), sizeof(DATA), &(DATA))
177134

178-
179-
/* Don't call directly this function, but use _Py_HASHTABLE_POP() macro */
180-
PyAPI_FUNC(int) _Py_hashtable_pop(
135+
// Remove a key and its associated value without calling key and value destroy
136+
// functions.
137+
// Return the removed value if the key was found.
138+
// Return NULL if the key was not found.
139+
PyAPI_FUNC(void*) _Py_hashtable_steal(
181140
_Py_hashtable_t *ht,
182-
const void *key,
183-
size_t data_size,
184-
void *data);
185-
186-
#define _Py_HASHTABLE_POP(TABLE, KEY, DATA) \
187-
_Py_hashtable_pop(TABLE, (KEY), sizeof(DATA), &(DATA))
141+
const void *key);
188142

189143

190144
#ifdef __cplusplus

0 commit comments

Comments
 (0)