mirror of https://github.com/python/cpython
Simplify implementation of hashtable.c
Issue #26588: Remove copy_data, free_data and get_data_size callbacks from hashtable.h. These callbacks are not used in Python and makes the code more complex. Remove also the _Py_HASHTABLE_ENTRY_DATA_AS_VOID_P() macro which uses an unsafe pointer dereference (can cause memory alignment issue). Replace the macro usage with _Py_HASHTABLE_ENTRY_READ_DATA() which is implemented with the safe memcpy() function.
This commit is contained in:
parent
0b2d71bc70
commit
c9553876ae
|
@ -220,16 +220,15 @@ hashtable_compare_unicode(size_t key_size, const void *pkey,
|
||||||
return key == entry_key;
|
return key == entry_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
|
|
||||||
|
|
||||||
static _Py_hashtable_t *
|
static _Py_hashtable_t *
|
||||||
hashtable_new(size_t key_size, size_t data_size,
|
hashtable_new(size_t key_size, size_t data_size,
|
||||||
_Py_hashtable_hash_func hash_func,
|
_Py_hashtable_hash_func hash_func,
|
||||||
_Py_hashtable_compare_func compare_func)
|
_Py_hashtable_compare_func compare_func)
|
||||||
{
|
{
|
||||||
|
_Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
|
||||||
return _Py_hashtable_new_full(key_size, data_size, 0,
|
return _Py_hashtable_new_full(key_size, data_size, 0,
|
||||||
hash_func, compare_func,
|
hash_func, compare_func,
|
||||||
NULL, NULL, NULL, &hashtable_alloc);
|
&hashtable_alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
|
@ -1120,7 +1119,8 @@ tracemalloc_pyobject_decref_cb(_Py_hashtable_t *tracebacks,
|
||||||
_Py_hashtable_entry_t *entry,
|
_Py_hashtable_entry_t *entry,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
PyObject *obj = (PyObject *)_Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(tracebacks, entry);
|
PyObject *obj;
|
||||||
|
_Py_HASHTABLE_ENTRY_READ_DATA(tracebacks, entry, sizeof(obj), &obj);
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1151,7 +1151,8 @@ py_tracemalloc_get_traces(PyObject *self, PyObject *obj)
|
||||||
|
|
||||||
/* the traceback hash table is used temporarily to intern traceback tuple
|
/* the traceback hash table is used temporarily to intern traceback tuple
|
||||||
of (filename, lineno) tuples */
|
of (filename, lineno) tuples */
|
||||||
get_traces.tracebacks = hashtable_new(sizeof(traceback_t *), sizeof(PyObject *),
|
get_traces.tracebacks = hashtable_new(sizeof(traceback_t *),
|
||||||
|
sizeof(PyObject *),
|
||||||
_Py_hashtable_hash_ptr,
|
_Py_hashtable_hash_ptr,
|
||||||
_Py_hashtable_compare_direct);
|
_Py_hashtable_compare_direct);
|
||||||
if (get_traces.tracebacks == NULL) {
|
if (get_traces.tracebacks == NULL) {
|
||||||
|
@ -1186,8 +1187,9 @@ finally:
|
||||||
tracemalloc_pyobject_decref_cb, NULL);
|
tracemalloc_pyobject_decref_cb, NULL);
|
||||||
_Py_hashtable_destroy(get_traces.tracebacks);
|
_Py_hashtable_destroy(get_traces.tracebacks);
|
||||||
}
|
}
|
||||||
if (get_traces.traces != NULL)
|
if (get_traces.traces != NULL) {
|
||||||
_Py_hashtable_destroy(get_traces.traces);
|
_Py_hashtable_destroy(get_traces.traces);
|
||||||
|
}
|
||||||
|
|
||||||
return get_traces.list;
|
return get_traces.list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,9 +128,6 @@ _Py_hashtable_new_full(size_t key_size, size_t data_size,
|
||||||
size_t init_size,
|
size_t init_size,
|
||||||
_Py_hashtable_hash_func hash_func,
|
_Py_hashtable_hash_func hash_func,
|
||||||
_Py_hashtable_compare_func compare_func,
|
_Py_hashtable_compare_func compare_func,
|
||||||
_Py_hashtable_copy_data_func copy_data_func,
|
|
||||||
_Py_hashtable_free_data_func free_data_func,
|
|
||||||
_Py_hashtable_get_data_size_func get_data_size_func,
|
|
||||||
_Py_hashtable_allocator_t *allocator)
|
_Py_hashtable_allocator_t *allocator)
|
||||||
{
|
{
|
||||||
_Py_hashtable_t *ht;
|
_Py_hashtable_t *ht;
|
||||||
|
@ -163,9 +160,6 @@ _Py_hashtable_new_full(size_t key_size, size_t data_size,
|
||||||
|
|
||||||
ht->hash_func = hash_func;
|
ht->hash_func = hash_func;
|
||||||
ht->compare_func = compare_func;
|
ht->compare_func = compare_func;
|
||||||
ht->copy_data_func = copy_data_func;
|
|
||||||
ht->free_data_func = free_data_func;
|
|
||||||
ht->get_data_size_func = get_data_size_func;
|
|
||||||
ht->alloc = alloc;
|
ht->alloc = alloc;
|
||||||
return ht;
|
return ht;
|
||||||
}
|
}
|
||||||
|
@ -179,7 +173,7 @@ _Py_hashtable_new(size_t key_size, size_t data_size,
|
||||||
return _Py_hashtable_new_full(key_size, data_size,
|
return _Py_hashtable_new_full(key_size, data_size,
|
||||||
HASHTABLE_MIN_SIZE,
|
HASHTABLE_MIN_SIZE,
|
||||||
hash_func, compare_func,
|
hash_func, compare_func,
|
||||||
NULL, NULL, NULL, NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,7 +181,6 @@ size_t
|
||||||
_Py_hashtable_size(_Py_hashtable_t *ht)
|
_Py_hashtable_size(_Py_hashtable_t *ht)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t hv;
|
|
||||||
|
|
||||||
size = sizeof(_Py_hashtable_t);
|
size = sizeof(_Py_hashtable_t);
|
||||||
|
|
||||||
|
@ -197,19 +190,6 @@ _Py_hashtable_size(_Py_hashtable_t *ht)
|
||||||
/* entries */
|
/* entries */
|
||||||
size += ht->entries * HASHTABLE_ITEM_SIZE(ht);
|
size += ht->entries * HASHTABLE_ITEM_SIZE(ht);
|
||||||
|
|
||||||
/* data linked from entries */
|
|
||||||
if (ht->get_data_size_func) {
|
|
||||||
for (hv = 0; hv < ht->num_buckets; hv++) {
|
|
||||||
_Py_hashtable_entry_t *entry;
|
|
||||||
|
|
||||||
for (entry = TABLE_HEAD(ht, hv); entry; entry = ENTRY_NEXT(entry)) {
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
data = _Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(ht, entry);
|
|
||||||
size += ht->get_data_size_func(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +298,7 @@ _Py_hashtable_pop_entry(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
|
||||||
|
|
||||||
int
|
int
|
||||||
_Py_hashtable_set(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
|
_Py_hashtable_set(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
|
||||||
size_t data_size, void *data)
|
size_t data_size, const void *data)
|
||||||
{
|
{
|
||||||
Py_uhash_t key_hash;
|
Py_uhash_t key_hash;
|
||||||
size_t index;
|
size_t index;
|
||||||
|
@ -380,7 +360,6 @@ _Py_hashtable_pop(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
|
||||||
size_t data_size, void *data)
|
size_t data_size, void *data)
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
assert(ht->free_data_func == NULL);
|
|
||||||
return _Py_hashtable_pop_entry(ht, key_size, pkey, data, data_size);
|
return _Py_hashtable_pop_entry(ht, key_size, pkey, data, data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,8 +449,6 @@ _Py_hashtable_clear(_Py_hashtable_t *ht)
|
||||||
for (i=0; i < ht->num_buckets; i++) {
|
for (i=0; i < ht->num_buckets; i++) {
|
||||||
for (entry = TABLE_HEAD(ht, i); entry != NULL; entry = next) {
|
for (entry = TABLE_HEAD(ht, i); entry != NULL; entry = next) {
|
||||||
next = ENTRY_NEXT(entry);
|
next = ENTRY_NEXT(entry);
|
||||||
if (ht->free_data_func)
|
|
||||||
ht->free_data_func(_Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(ht, entry));
|
|
||||||
ht->alloc.free(entry);
|
ht->alloc.free(entry);
|
||||||
}
|
}
|
||||||
_Py_slist_init(&ht->buckets[i]);
|
_Py_slist_init(&ht->buckets[i]);
|
||||||
|
@ -490,8 +467,6 @@ _Py_hashtable_destroy(_Py_hashtable_t *ht)
|
||||||
_Py_slist_item_t *entry = ht->buckets[i].head;
|
_Py_slist_item_t *entry = ht->buckets[i].head;
|
||||||
while (entry) {
|
while (entry) {
|
||||||
_Py_slist_item_t *entry_next = entry->next;
|
_Py_slist_item_t *entry_next = entry->next;
|
||||||
if (ht->free_data_func)
|
|
||||||
ht->free_data_func(_Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(ht, entry));
|
|
||||||
ht->alloc.free(entry);
|
ht->alloc.free(entry);
|
||||||
entry = entry_next;
|
entry = entry_next;
|
||||||
}
|
}
|
||||||
|
@ -511,35 +486,21 @@ _Py_hashtable_copy(_Py_hashtable_t *src)
|
||||||
_Py_hashtable_entry_t *entry;
|
_Py_hashtable_entry_t *entry;
|
||||||
size_t bucket;
|
size_t bucket;
|
||||||
int err;
|
int err;
|
||||||
void *data, *new_data;
|
|
||||||
|
|
||||||
dst = _Py_hashtable_new_full(key_size, data_size,
|
dst = _Py_hashtable_new_full(key_size, data_size,
|
||||||
src->num_buckets,
|
src->num_buckets,
|
||||||
src->hash_func, src->compare_func,
|
src->hash_func,
|
||||||
src->copy_data_func, src->free_data_func,
|
src->compare_func,
|
||||||
src->get_data_size_func, &src->alloc);
|
&src->alloc);
|
||||||
if (dst == NULL)
|
if (dst == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (bucket=0; bucket < src->num_buckets; bucket++) {
|
for (bucket=0; bucket < src->num_buckets; bucket++) {
|
||||||
entry = TABLE_HEAD(src, bucket);
|
entry = TABLE_HEAD(src, bucket);
|
||||||
for (; entry; entry = ENTRY_NEXT(entry)) {
|
for (; entry; entry = ENTRY_NEXT(entry)) {
|
||||||
if (src->copy_data_func) {
|
const void *pkey = _Py_HASHTABLE_ENTRY_KEY(entry);
|
||||||
data = _Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(src, entry);
|
const void *data = _Py_HASHTABLE_ENTRY_DATA(src, entry);
|
||||||
new_data = src->copy_data_func(data);
|
err = _Py_hashtable_set(dst, key_size, pkey, data_size, data);
|
||||||
if (new_data != NULL)
|
|
||||||
err = _Py_hashtable_set(dst, key_size,
|
|
||||||
_Py_HASHTABLE_ENTRY_KEY(entry),
|
|
||||||
data_size, &new_data);
|
|
||||||
else
|
|
||||||
err = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data = _Py_HASHTABLE_ENTRY_DATA(src, entry);
|
|
||||||
err = _Py_hashtable_set(dst, key_size,
|
|
||||||
_Py_HASHTABLE_ENTRY_KEY(entry),
|
|
||||||
data_size, data);
|
|
||||||
}
|
|
||||||
if (err) {
|
if (err) {
|
||||||
_Py_hashtable_destroy(dst);
|
_Py_hashtable_destroy(dst);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -35,9 +35,6 @@ typedef struct {
|
||||||
#define _Py_HASHTABLE_ENTRY_DATA(TABLE, ENTRY) \
|
#define _Py_HASHTABLE_ENTRY_DATA(TABLE, ENTRY) \
|
||||||
((char *)(ENTRY) + sizeof(_Py_hashtable_entry_t) + (TABLE)->key_size)
|
((char *)(ENTRY) + sizeof(_Py_hashtable_entry_t) + (TABLE)->key_size)
|
||||||
|
|
||||||
#define _Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(TABLE, ENTRY) \
|
|
||||||
(*(void **)_Py_HASHTABLE_ENTRY_DATA(TABLE, ENTRY))
|
|
||||||
|
|
||||||
/* Get a key value from pkey: use memcpy() rather than a pointer dereference
|
/* Get a key value from pkey: use memcpy() rather than a pointer dereference
|
||||||
to avoid memory alignment issues. */
|
to avoid memory alignment issues. */
|
||||||
#define _Py_HASHTABLE_READ_KEY(KEY_SIZE, PKEY, DST_KEY) \
|
#define _Py_HASHTABLE_READ_KEY(KEY_SIZE, PKEY, DST_KEY) \
|
||||||
|
@ -66,9 +63,6 @@ typedef Py_uhash_t (*_Py_hashtable_hash_func) (size_t key_size,
|
||||||
typedef int (*_Py_hashtable_compare_func) (size_t key_size,
|
typedef int (*_Py_hashtable_compare_func) (size_t key_size,
|
||||||
const void *pkey,
|
const void *pkey,
|
||||||
const _Py_hashtable_entry_t *he);
|
const _Py_hashtable_entry_t *he);
|
||||||
typedef void* (*_Py_hashtable_copy_data_func)(void *data);
|
|
||||||
typedef void (*_Py_hashtable_free_data_func)(void *data);
|
|
||||||
typedef size_t (*_Py_hashtable_get_data_size_func)(void *data);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* allocate a memory block */
|
/* allocate a memory block */
|
||||||
|
@ -90,9 +84,6 @@ typedef struct {
|
||||||
|
|
||||||
_Py_hashtable_hash_func hash_func;
|
_Py_hashtable_hash_func hash_func;
|
||||||
_Py_hashtable_compare_func compare_func;
|
_Py_hashtable_compare_func compare_func;
|
||||||
_Py_hashtable_copy_data_func copy_data_func;
|
|
||||||
_Py_hashtable_free_data_func free_data_func;
|
|
||||||
_Py_hashtable_get_data_size_func get_data_size_func;
|
|
||||||
_Py_hashtable_allocator_t alloc;
|
_Py_hashtable_allocator_t alloc;
|
||||||
} _Py_hashtable_t;
|
} _Py_hashtable_t;
|
||||||
|
|
||||||
|
@ -119,9 +110,6 @@ PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new_full(
|
||||||
size_t init_size,
|
size_t init_size,
|
||||||
_Py_hashtable_hash_func hash_func,
|
_Py_hashtable_hash_func hash_func,
|
||||||
_Py_hashtable_compare_func compare_func,
|
_Py_hashtable_compare_func compare_func,
|
||||||
_Py_hashtable_copy_data_func copy_data_func,
|
|
||||||
_Py_hashtable_free_data_func free_data_func,
|
|
||||||
_Py_hashtable_get_data_size_func get_data_size_func,
|
|
||||||
_Py_hashtable_allocator_t *allocator);
|
_Py_hashtable_allocator_t *allocator);
|
||||||
|
|
||||||
PyAPI_FUNC(void) _Py_hashtable_destroy(_Py_hashtable_t *ht);
|
PyAPI_FUNC(void) _Py_hashtable_destroy(_Py_hashtable_t *ht);
|
||||||
|
@ -155,7 +143,7 @@ PyAPI_FUNC(int) _Py_hashtable_set(
|
||||||
size_t key_size,
|
size_t key_size,
|
||||||
const void *pkey,
|
const void *pkey,
|
||||||
size_t data_size,
|
size_t data_size,
|
||||||
void *data);
|
const void *data);
|
||||||
|
|
||||||
#define _Py_HASHTABLE_SET(TABLE, KEY, DATA) \
|
#define _Py_HASHTABLE_SET(TABLE, KEY, DATA) \
|
||||||
_Py_hashtable_set(TABLE, sizeof(KEY), &KEY, sizeof(DATA), &(DATA))
|
_Py_hashtable_set(TABLE, sizeof(KEY), &KEY, sizeof(DATA), &(DATA))
|
||||||
|
|
Loading…
Reference in New Issue