ハッシュ関数FNVの32bitで数件衝突が発生したため、64bitでも生成できるようにしました。
PythonのドキュメントにPy_BuildValueの引数について解説があり、unsigned long long intのフォーマットがKであることが分かりました。
unsigned intのフォーマットはiではなく大文字のIなので、32bitの方も修正しました。これでPython側での変換が不要になります。
#define PY_SSIZE_T_CLEAN
#include <Python.h>
extern uint32_t fnv_1_hash_32(const char*);
extern uint64_t fnv_1_hash_64(const char*);
static PyObject* fnv_32(PyObject* self, PyObject* args)
{
const char* s;
unsigned int hash=2166136261U;
if (!PyArg_ParseTuple(args, "s", &s)){
return NULL;
}
else{
while (*s) {
hash*=16777619U;
hash^=*(s++);
}
return Py_BuildValue("I", hash);
}
}
static PyObject* fnv_64(PyObject* self, PyObject* args)
{
const char* s;
unsigned long long hash=14695981039346656037U;
if (!PyArg_ParseTuple(args, "s", &s)){
return NULL;
}
else{
while (*s) {
hash*=1099511628211LLU;
hash^=*(s++);
}
return Py_BuildValue("K", hash);
}
}
static PyMethodDef fnvmethods[] = {
{"fnv_1_hash_32", fnv_32, METH_VARARGS},
{"fnv_1_hash_64", fnv_64, METH_VARARGS},
{NULL,NULL,0}
};
static struct PyModuleDef fnv = {
PyModuleDef_HEAD_INIT,
"fnv",
"Python3 C API Module(Sample 1)",
-1,
fnvmethods
};
PyMODINIT_FUNC PyInit_fnv(void)
{
return PyModule_Create(&fnv);
}
from c_module import fnv
name_list = ['シャフリヤール']
for name in name_list:
hash = fnv.fnv_1_hash_64(name)
print(hash)
--------------------------------------------------
出力
--------------------------------------------------
7203286604922561048
#include <stdio.h>
#include <stdint.h>
uint32_t fnv_1_hash_32(char *s)
{
unsigned int hash=2166136261U;
while (*s) {
hash*=16777619U;
hash^=*(s++);
}
return hash;
}
uint64_t fnv_1_hash_64(char *s)
{
unsigned long long hash=14695981039346656037U;
while (*s) {
hash*=1099511628211LLU;
hash^=*(s++);
}
return hash;
}
from distutils.core import setup, Extension
setup(name='fnv',
version='1.0',
ext_modules=[Extension('fnv', sources = ['fnv.c','fnv_function.c'])]
)
<セットアップコマンド>
・自作ライブラリに配置するsoファイルを作成するコマンド "from c_module import fnv"
python setup.py build_ext -i
・既存のライブラリにインストールするコマンド "import fnv"
python setup.py install