|
5 | 5 | #include "PyCallable.h" |
6 | 6 |
|
7 | 7 | // Standard |
| 8 | +#include <cstdint> |
8 | 9 | #include <map> |
9 | 10 | #include <string> |
10 | 11 | #include <utility> |
|
14 | 15 | namespace CPyCppyy { |
15 | 16 |
|
16 | 17 | // signature hashes are also used by TemplateProxy |
| 18 | +// Forward declare for use in HashSignature before class definition |
| 19 | +CPYCPPYY_IMPORT PyTypeObject CPPOverload_Type; |
| 20 | +CPYCPPYY_IMPORT PyTypeObject TemplateProxy_Type; |
| 21 | + |
17 | 22 | inline uint64_t HashSignature(CPyCppyy_PyArgs_t args, size_t nargsf) |
18 | 23 | { |
19 | 24 | // Build a hash from the types of the given python function arguments. |
20 | 25 | uint64_t hash = 0; |
21 | 26 |
|
22 | 27 | Py_ssize_t nargs = CPyCppyy_PyArgs_GET_SIZE(args, nargsf); |
23 | 28 | for (Py_ssize_t i = 0; i < nargs; ++i) { |
24 | | - // TODO: hashing in the ref-count is for moves; resolve this together with the |
25 | | - // improved overloads for implicit conversions |
26 | 29 | PyObject* pyobj = CPyCppyy_PyArgs_GET_ITEM(args, i); |
27 | | - hash += (uint64_t)Py_TYPE(pyobj); |
| 30 | + |
| 31 | + // For CPPOverload and TemplateProxy, mix in object identity (pointer address) |
| 32 | + // to distinguish different C++ callables with same Python type |
| 33 | + if (Py_TYPE(pyobj) == &CPPOverload_Type || Py_TYPE(pyobj) == &TemplateProxy_Type) { |
| 34 | + // Use golden ratio mixing: shift by 3 (pointers are 8-byte aligned), |
| 35 | + // then apply proper bit mixing with golden ratio constant |
| 36 | + hash ^= ((uint64_t)(uintptr_t)pyobj >> 3) + 0x9e3779b9ULL + (hash << 6) + (hash >> 2); |
| 37 | + } else { |
| 38 | + // Standard type-based hashing for other objects |
| 39 | + hash += (uint64_t)Py_TYPE(pyobj); |
28 | 40 | #if PY_VERSION_HEX >= 0x030e0000 |
29 | | - hash += (uint64_t)(PyUnstable_Object_IsUniqueReferencedTemporary(pyobj) ? 1 : 0); |
| 41 | + hash += (uint64_t)(PyUnstable_Object_IsUniqueReferencedTemporary(pyobj) ? 1 : 0); |
30 | 42 | #else |
31 | | - hash += (uint64_t)(Py_REFCNT(pyobj) == 1 ? 1 : 0); |
| 43 | + hash += (uint64_t)(Py_REFCNT(pyobj) == 1 ? 1 : 0); |
32 | 44 | #endif |
| 45 | + } |
33 | 46 | hash += (hash << 10); hash ^= (hash >> 6); |
34 | 47 | } |
35 | 48 |
|
|
0 commit comments