|
14 | 14 | #include "Python.h"
|
15 | 15 | #include "pycore_byteswap.h" // _Py_bswap32()
|
16 | 16 | #include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
|
| 17 | +#include "pycore_hashtable.h" // _Py_hashtable_new() |
17 | 18 | #include "pycore_gc.h" // PyGC_Head
|
18 | 19 |
|
19 | 20 |
|
@@ -62,10 +63,97 @@ test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
|
62 | 63 | }
|
63 | 64 |
|
64 | 65 |
|
| 66 | +#define TO_PTR(ch) ((void*)(uintptr_t)ch) |
| 67 | +#define FROM_PTR(ptr) ((uintptr_t)ptr) |
| 68 | +#define VALUE(key) (1 + ((int)(key) - 'a')) |
| 69 | + |
| 70 | +static Py_uhash_t |
| 71 | +hash_char(const void *key) |
| 72 | +{ |
| 73 | + char ch = (char)FROM_PTR(key); |
| 74 | + return ch; |
| 75 | +} |
| 76 | + |
| 77 | + |
| 78 | +static int |
| 79 | +hashtable_cb(_Py_hashtable_t *table, |
| 80 | + const void *key_ptr, const void *value_ptr, |
| 81 | + void *user_data) |
| 82 | +{ |
| 83 | + int *count = (int *)user_data; |
| 84 | + char key = (char)FROM_PTR(key_ptr); |
| 85 | + int value = (int)FROM_PTR(value_ptr); |
| 86 | + assert(value == VALUE(key)); |
| 87 | + *count += 1; |
| 88 | + return 0; |
| 89 | +} |
| 90 | + |
| 91 | + |
| 92 | +static PyObject* |
| 93 | +test_hashtable(PyObject *self, PyObject *Py_UNUSED(args)) |
| 94 | +{ |
| 95 | + _Py_hashtable_t *table = _Py_hashtable_new(hash_char, |
| 96 | + _Py_hashtable_compare_direct); |
| 97 | + if (table == NULL) { |
| 98 | + return PyErr_NoMemory(); |
| 99 | + } |
| 100 | + |
| 101 | + // Test _Py_hashtable_set() |
| 102 | + char key; |
| 103 | + for (key='a'; key <= 'z'; key++) { |
| 104 | + int value = VALUE(key); |
| 105 | + if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) { |
| 106 | + _Py_hashtable_destroy(table); |
| 107 | + return PyErr_NoMemory(); |
| 108 | + } |
| 109 | + } |
| 110 | + assert(table->nentries == 26); |
| 111 | + assert(table->nbuckets > table->nentries); |
| 112 | + |
| 113 | + // Test _Py_hashtable_get_entry() |
| 114 | + for (key='a'; key <= 'z'; key++) { |
| 115 | + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key)); |
| 116 | + assert(entry != NULL); |
| 117 | + assert(entry->key = TO_PTR(key)); |
| 118 | + assert(entry->value = TO_PTR(VALUE(key))); |
| 119 | + } |
| 120 | + |
| 121 | + // Test _Py_hashtable_get() |
| 122 | + for (key='a'; key <= 'z'; key++) { |
| 123 | + void *value_ptr = _Py_hashtable_get(table, TO_PTR(key)); |
| 124 | + int value = (int)FROM_PTR(value_ptr); |
| 125 | + assert(value == VALUE(key)); |
| 126 | + } |
| 127 | + |
| 128 | + // Test _Py_hashtable_steal() |
| 129 | + key = 'p'; |
| 130 | + void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key)); |
| 131 | + int value = (int)FROM_PTR(value_ptr); |
| 132 | + assert(value == VALUE(key)); |
| 133 | + |
| 134 | + assert(table->nentries == 25); |
| 135 | + |
| 136 | + // Test _Py_hashtable_foreach() |
| 137 | + int count = 0; |
| 138 | + int res = _Py_hashtable_foreach(table, hashtable_cb, &count); |
| 139 | + assert(res == 0); |
| 140 | + assert(count == 25); |
| 141 | + |
| 142 | + // Test _Py_hashtable_clear() |
| 143 | + _Py_hashtable_clear(table); |
| 144 | + assert(table->nentries == 0); |
| 145 | + assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL); |
| 146 | + |
| 147 | + _Py_hashtable_destroy(table); |
| 148 | + Py_RETURN_NONE; |
| 149 | +} |
| 150 | + |
| 151 | + |
65 | 152 | static PyMethodDef TestMethods[] = {
|
66 | 153 | {"get_configs", get_configs, METH_NOARGS},
|
67 | 154 | {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
|
68 | 155 | {"test_bswap", test_bswap, METH_NOARGS},
|
| 156 | + {"test_hashtable", test_hashtable, METH_NOARGS}, |
69 | 157 | {NULL, NULL} /* sentinel */
|
70 | 158 | };
|
71 | 159 |
|
|
0 commit comments