Search code examples
c++cythonxor

XOR operation in Cython within a nogil context for hashing a vector with a hex


I am trying to define a hash for a sorted vector of type size_t. As part of the solution, I use an XOR operation.

cdef size_t vector_hash(const vector[size_t]& v) noexcept nogil:
    """Hash a vector of size_t."""
    cdef size_t seed = v.size()
    cdef size_t i, hash_val
    for i in v:
        seed = seed ^ (i + 0x9e3779b9 + (seed << 6) + (seed >> 2))
    hash_val = seed
    return hash_val

However, I get the following error when trying to compile:

Error compiling Cython file:
------------------------------------------------------------
...
cdef size_t vector_hash(const vector[size_t]& v) noexcept nogil:
    """Hash a vector of size_t."""
    cdef size_t seed = v.size()
    cdef size_t i, hash_val
    for i in v:
        seed = seed ^ (i + 0x9e3779b9 + (seed << 6) + (seed >> 2))
                    ^
------------------------------------------------------------

/Users/adam2392/Documents/scikit-tree/sktree/tree/_utils.pyx:155:20: Coercion from Python not allowed without the GIL

My questions are:

  1. Why can't you use the XOR in a nogil context here?
  2. What is a way to implement XOR in a nogil context then?

Solution

  • There are two problems:

    1. The constant 0x9e3779b9 is treated as a python integer, we should cast it to size_t: <size_t>0x9e3779b9

    2. Cython cannot generate the right code for the loop for i in v when v is const vector[size_t]&, Cython will produce a non-const interator which result in a compiling error. We can drop the const qualifier: size_t vector_hash(vector[size_t]& v) or use an alternative loop method:

        for i in range(v.size()):
            seed = seed ^ (v[i] + <size_t>0x9e3779b9 + (seed << 6) + (seed >> 2))