spookyhash 2.0.2__tar.gz → 2.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Alen Buhanec
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1 +1 @@
1
- include src/*.pyx src/*.pxd src/*.cpp src/*.h
1
+ include src/*.pyx src/*.pxd src/*.cpp src/*.h
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: spookyhash
3
+ Version: 2.1.1
4
+ Summary: A Python wrapper for SpookyHash version 2
5
+ Author-email: Alen Buhanec <alen.buhanec@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/buhanec/spookyhash
8
+ Project-URL: Repository, https://github.com/buhanec/spookyhash
9
+ Project-URL: Issues, https://github.com/buhanec/spookyhash/issues
10
+ Keywords: SpookyHash,hashlib
11
+ Classifier: Topic :: Software Development :: Libraries
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: License :: OSI Approved :: MIT License
23
+ Classifier: Operating System :: OS Independent
24
+ Classifier: Typing :: Typed
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: test
28
+ Requires-Dist: pytest; extra == "test"
29
+ Requires-Dist: hypothesis; extra == "test"
30
+ Dynamic: license-file
31
+
32
+ # spookyhash
33
+
34
+ A Python wrapper of Bob Jenkins' [SpookyHash version 2](http://burtleburtle.net/bob/hash/spooky.html). Offers 32- 64- and 128-bit oneshot and incremental hashes.
35
+
36
+ # License
37
+
38
+ > Licensed under the MIT license. See the LICENSE file in the repository root for more details.
39
+
40
+ # Usage
41
+
42
+ ## Installation
43
+
44
+ Available through [spookyhash - PyPI](https://pypi.org/project/spookyhash/) using `pip install spookyhash`.
45
+
46
+ ## Oneshot Hashes
47
+
48
+ ```python
49
+ >>> import spookyhash
50
+
51
+ >>> spookyhash.hash32(b'hello world')
52
+ 2617184861
53
+ >>> spookyhash.hash32(b'hello world', seed=0x12345678)
54
+ 3380090220
55
+
56
+ >>> spookyhash.hash64(b'hello world')
57
+ 14865987102431973981
58
+ >>> spookyhash.hash64(b'hello world', seed=123)
59
+ 5719863273689036421
60
+
61
+ >>> spookyhash.hash128(b'hello world')
62
+ 185933735475381961281710998418114941533
63
+ >>> spookyhash.hash128(b'hello world', seed1=123_000, seed2=456_000)
64
+ 144121310386202441278894605216246194925
65
+
66
+ >>> # For a more comparable result to other libraries
67
+ >>> spookyhash.hash128_pair(b'hello world')
68
+ (14865987102431973981, 10079487997037711397)
69
+ >>> spookyhash.hash128_pair(b'hello world', seed1=123_000, seed2=456_000)
70
+ (12678109464562819821, 7812831891108919044)
71
+ ```
72
+
73
+ ## Incremental Hashes
74
+
75
+ ```python
76
+ >>> import spookyhash
77
+
78
+ >>> sh = spookyhash.Hash32()
79
+ >>> sh.update(b'hello')
80
+ >>> sh.update(b' ')
81
+ >>> sh.update(b'world')
82
+ >>> sh.final()
83
+ 2617184861
84
+ >>> sh.hexdigest()
85
+ '5d12ff9b'
86
+
87
+ >>> spookyhash.Hash64(b'hello ', seed=123).update(b'world').final()
88
+ 5719863273689036421
89
+
90
+ >>> spookyhash.Hash64(b'hello ', seed=123).update(b'world').hexdigest()
91
+ '85b609a05709614f'
92
+
93
+ >>> sh = spookyhash.Hash128(seed1=123_000, seed2=456_000)
94
+ >>> sh.update(b'hello world')
95
+ >>> sh.final()
96
+ 144121310386202441278894605216246194925
97
+ >>> sh.final_pair()
98
+ (12678109464562819821, 7812831891108919044)
99
+ >>> sh.hexdigest()
100
+ 'ede2c8f262b1f1af04f763f735c16c6c'
101
+ ```
102
+
103
+ ## `memoryview` Support
104
+
105
+ Includes `memoryview` compatible types, such as NumPy arrays.
106
+
107
+ ```python
108
+ >>> import spookyhash
109
+ >>> import numpy as np
110
+
111
+ >>> spookyhash.Hash64(np.arange(100)).hexdigest()
112
+ '43ab5363ad362c74'
113
+
114
+ >>> spookyhash.Hash64(memoryview(b'hello world')).hexdigest()
115
+ '5d12ff9b81984ece'
116
+ ```
117
+
118
+ # Platform Independence
119
+
120
+ If run on a big-endian system, the code would produce different hashes, but of equal quality.
@@ -1,4 +1,4 @@
1
- # spookyhash [<img src="https://img.shields.io/gitlab/pipeline/alen/spookyhash/main?gitlab_url=https%3A%2F%2Fgitlab.home.alen.sh%2F&label=Gitlab%20CI&style=flat-square" align="right">](https://gitlab.home.alen.sh/alen/spookyhash) [<img src="https://img.shields.io/travis/buhanec/spookyhash/main.svg?label=Travis+CI&style=flat-square" align="right">](https://travis-ci.org/buhanec/spookyhash) [<img src="https://img.shields.io/azure-devops/build/buhanec/aa771e37-5a75-4d92-8d99-d27975af994e/2/main?label=Azure%20DevOps&style=flat-square" align="right">](https://dev.azure.com/buhanec/spookyhash/_build)
1
+ # spookyhash
2
2
 
3
3
  A Python wrapper of Bob Jenkins' [SpookyHash version 2](http://burtleburtle.net/bob/hash/spooky.html). Offers 32- 64- and 128-bit oneshot and incremental hashes.
4
4
 
@@ -50,16 +50,38 @@ Available through [spookyhash - PyPI](https://pypi.org/project/spookyhash/) usin
50
50
  >>> sh.update(b'world')
51
51
  >>> sh.final()
52
52
  2617184861
53
+ >>> sh.hexdigest()
54
+ '5d12ff9b'
53
55
 
54
56
  >>> spookyhash.Hash64(b'hello ', seed=123).update(b'world').final()
55
57
  5719863273689036421
56
58
 
59
+ >>> spookyhash.Hash64(b'hello ', seed=123).update(b'world').hexdigest()
60
+ '85b609a05709614f'
61
+
57
62
  >>> sh = spookyhash.Hash128(seed1=123_000, seed2=456_000)
58
63
  >>> sh.update(b'hello world')
59
64
  >>> sh.final()
60
65
  144121310386202441278894605216246194925
61
66
  >>> sh.final_pair()
62
67
  (12678109464562819821, 7812831891108919044)
68
+ >>> sh.hexdigest()
69
+ 'ede2c8f262b1f1af04f763f735c16c6c'
70
+ ```
71
+
72
+ ## `memoryview` Support
73
+
74
+ Includes `memoryview` compatible types, such as NumPy arrays.
75
+
76
+ ```python
77
+ >>> import spookyhash
78
+ >>> import numpy as np
79
+
80
+ >>> spookyhash.Hash64(np.arange(100)).hexdigest()
81
+ '43ab5363ad362c74'
82
+
83
+ >>> spookyhash.Hash64(memoryview(b'hello world')).hexdigest()
84
+ '5d12ff9b81984ece'
63
85
  ```
64
86
 
65
87
  # Platform Independence
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=42",
4
+ "wheel",
5
+ "cython"
6
+ ]
7
+ build-backend = "setuptools.build_meta"
8
+
9
+ [project]
10
+ authors = [{name = "Alen Buhanec", email = "alen.buhanec@gmail.com"}]
11
+ name = "spookyhash"
12
+ description = "A Python wrapper for SpookyHash version 2"
13
+ readme = "README.md"
14
+ keywords = ["SpookyHash", "hashlib"]
15
+ license = {text = "MIT"}
16
+ classifiers = [
17
+ "Topic :: Software Development :: Libraries",
18
+ "Development Status :: 5 - Production/Stable",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.7",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Operating System :: OS Independent",
30
+ "Typing :: Typed",
31
+ ]
32
+ dynamic = ["version"]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/buhanec/spookyhash"
36
+ Repository = "https://github.com/buhanec/spookyhash"
37
+ Issues = "https://github.com/buhanec/spookyhash/issues"
38
+
39
+ [project.optional-dependencies]
40
+ test = ["pytest", "hypothesis"]
41
+
42
+ [tool.setuptools]
43
+ py-modules = ["spookyhash"]
44
+
45
+ [tool.setuptools.dynamic]
46
+ version = {attr = "spookyhash.__version__"}
@@ -1,4 +1,4 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,22 @@
1
+ from Cython.Build import cythonize
2
+ from setuptools import Extension, setup
3
+
4
+
5
+ setup(
6
+ ext_modules=cythonize(
7
+ [
8
+ Extension(
9
+ "_spookyhash",
10
+ ["src/spookyhash.pyx", "src/SpookyV2.cpp"],
11
+ language="c++",
12
+ ),
13
+ ],
14
+ compiler_directives={
15
+ "cdivision": True,
16
+ "boundscheck": False,
17
+ "wraparound": False,
18
+ "embedsignature": True,
19
+ "language_level": 3,
20
+ },
21
+ ),
22
+ )
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: spookyhash
3
+ Version: 2.1.1
4
+ Summary: A Python wrapper for SpookyHash version 2
5
+ Author-email: Alen Buhanec <alen.buhanec@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/buhanec/spookyhash
8
+ Project-URL: Repository, https://github.com/buhanec/spookyhash
9
+ Project-URL: Issues, https://github.com/buhanec/spookyhash/issues
10
+ Keywords: SpookyHash,hashlib
11
+ Classifier: Topic :: Software Development :: Libraries
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: License :: OSI Approved :: MIT License
23
+ Classifier: Operating System :: OS Independent
24
+ Classifier: Typing :: Typed
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: test
28
+ Requires-Dist: pytest; extra == "test"
29
+ Requires-Dist: hypothesis; extra == "test"
30
+ Dynamic: license-file
31
+
32
+ # spookyhash
33
+
34
+ A Python wrapper of Bob Jenkins' [SpookyHash version 2](http://burtleburtle.net/bob/hash/spooky.html). Offers 32- 64- and 128-bit oneshot and incremental hashes.
35
+
36
+ # License
37
+
38
+ > Licensed under the MIT license. See the LICENSE file in the repository root for more details.
39
+
40
+ # Usage
41
+
42
+ ## Installation
43
+
44
+ Available through [spookyhash - PyPI](https://pypi.org/project/spookyhash/) using `pip install spookyhash`.
45
+
46
+ ## Oneshot Hashes
47
+
48
+ ```python
49
+ >>> import spookyhash
50
+
51
+ >>> spookyhash.hash32(b'hello world')
52
+ 2617184861
53
+ >>> spookyhash.hash32(b'hello world', seed=0x12345678)
54
+ 3380090220
55
+
56
+ >>> spookyhash.hash64(b'hello world')
57
+ 14865987102431973981
58
+ >>> spookyhash.hash64(b'hello world', seed=123)
59
+ 5719863273689036421
60
+
61
+ >>> spookyhash.hash128(b'hello world')
62
+ 185933735475381961281710998418114941533
63
+ >>> spookyhash.hash128(b'hello world', seed1=123_000, seed2=456_000)
64
+ 144121310386202441278894605216246194925
65
+
66
+ >>> # For a more comparable result to other libraries
67
+ >>> spookyhash.hash128_pair(b'hello world')
68
+ (14865987102431973981, 10079487997037711397)
69
+ >>> spookyhash.hash128_pair(b'hello world', seed1=123_000, seed2=456_000)
70
+ (12678109464562819821, 7812831891108919044)
71
+ ```
72
+
73
+ ## Incremental Hashes
74
+
75
+ ```python
76
+ >>> import spookyhash
77
+
78
+ >>> sh = spookyhash.Hash32()
79
+ >>> sh.update(b'hello')
80
+ >>> sh.update(b' ')
81
+ >>> sh.update(b'world')
82
+ >>> sh.final()
83
+ 2617184861
84
+ >>> sh.hexdigest()
85
+ '5d12ff9b'
86
+
87
+ >>> spookyhash.Hash64(b'hello ', seed=123).update(b'world').final()
88
+ 5719863273689036421
89
+
90
+ >>> spookyhash.Hash64(b'hello ', seed=123).update(b'world').hexdigest()
91
+ '85b609a05709614f'
92
+
93
+ >>> sh = spookyhash.Hash128(seed1=123_000, seed2=456_000)
94
+ >>> sh.update(b'hello world')
95
+ >>> sh.final()
96
+ 144121310386202441278894605216246194925
97
+ >>> sh.final_pair()
98
+ (12678109464562819821, 7812831891108919044)
99
+ >>> sh.hexdigest()
100
+ 'ede2c8f262b1f1af04f763f735c16c6c'
101
+ ```
102
+
103
+ ## `memoryview` Support
104
+
105
+ Includes `memoryview` compatible types, such as NumPy arrays.
106
+
107
+ ```python
108
+ >>> import spookyhash
109
+ >>> import numpy as np
110
+
111
+ >>> spookyhash.Hash64(np.arange(100)).hexdigest()
112
+ '43ab5363ad362c74'
113
+
114
+ >>> spookyhash.Hash64(memoryview(b'hello world')).hexdigest()
115
+ '5d12ff9b81984ece'
116
+ ```
117
+
118
+ # Platform Independence
119
+
120
+ If run on a big-endian system, the code would produce different hashes, but of equal quality.
@@ -1,15 +1,18 @@
1
+ LICENSE
1
2
  MANIFEST.in
2
3
  README.md
3
4
  pyproject.toml
4
5
  setup.py
6
+ spookyhash.py
5
7
  spookyhash.egg-info/PKG-INFO
6
8
  spookyhash.egg-info/SOURCES.txt
7
9
  spookyhash.egg-info/dependency_links.txt
10
+ spookyhash.egg-info/requires.txt
8
11
  spookyhash.egg-info/top_level.txt
9
12
  src/SpookyV2.cpp
10
13
  src/SpookyV2.h
11
14
  src/SpookyV2.pxd
12
15
  src/spookyhash.cpp
13
16
  src/spookyhash.pyx
14
- tests/__init__.py
17
+ tests/test_readme.py
15
18
  tests/test_spooky_hash.py
@@ -0,0 +1,4 @@
1
+
2
+ [test]
3
+ pytest
4
+ hypothesis
@@ -0,0 +1,2 @@
1
+ _spookyhash
2
+ spookyhash
@@ -0,0 +1,240 @@
1
+ """A Python wrapper for SpookyHash version 2."""
2
+
3
+ import struct
4
+ from abc import ABC, abstractmethod
5
+ from binascii import hexlify
6
+ from typing import ClassVar, TYPE_CHECKING, Tuple, Type, Union, cast
7
+
8
+ import _spookyhash
9
+
10
+ if TYPE_CHECKING:
11
+ from typing import Self
12
+
13
+ __all__ = ('hash32', 'hash64', 'hash128', 'Hash32', 'Hash64', 'Hash128')
14
+ __version__ = '2.1.1'
15
+
16
+
17
+ # Utility function for homogenising data
18
+
19
+ def _char_arr(message: Union[bytes, memoryview, None]) -> memoryview:
20
+ if message is None:
21
+ return memoryview(b'').cast('c')
22
+ if not isinstance(message, memoryview):
23
+ try:
24
+ message = memoryview(message)
25
+ except TypeError as e:
26
+ raise TypeError(
27
+ f"Expecting message to be bytes, memoryview, None, or a type "
28
+ f"that can be interpreted as memoryview (e.g. NumPy "
29
+ f"arrays); instead found "
30
+ f"{type(message).__module__}.{type(message).__name__}"
31
+ ) from e
32
+ if message.format != 'c' or not message.contiguous:
33
+ message = message.cast('c')
34
+ return message
35
+
36
+
37
+ # Oneshot hash functions
38
+
39
+ def hash32(message: Union[bytes, memoryview], seed: int = 0) -> int:
40
+ """
41
+ Hash a single message in one call, produce 32-bit output.
42
+
43
+ :param message: message to hash
44
+ :param seed: 32-bit seed
45
+ :return: 32-bit hash
46
+ """
47
+ return _spookyhash.hash32(_char_arr(message), seed)
48
+
49
+
50
+ def hash64(message: Union[bytes, memoryview], seed: int = 0) -> int:
51
+ """
52
+ Hash a single message in one call, produce 64-bit output.
53
+
54
+ :param message: message to hash
55
+ :param seed: 64-bit seed
56
+ :return: 64-bit hash
57
+ """
58
+ return _spookyhash.hash64(_char_arr(message), seed)
59
+
60
+
61
+ def hash128_pair(
62
+ message: Union[bytes, memoryview],
63
+ seed1: int = 0,
64
+ seed2: int = 0,
65
+ ) -> Tuple[int, int]:
66
+ """
67
+ Hash a single message in one call, produce 128-bit output.
68
+
69
+ :param message: message to hash
70
+ :param seed1: 64-bit seed 1
71
+ :param seed2: 64-bit seed 2
72
+ :return: Pair of 64-bit hash values
73
+ """
74
+ digest = _spookyhash.hash128(_char_arr(message), seed1=seed1, seed2=seed2)
75
+ return cast(Tuple[int, int], struct.unpack('=QQ', digest))
76
+
77
+
78
+ def hash128(
79
+ message: Union[bytes, memoryview],
80
+ seed1: int = 0,
81
+ seed2: int = 0,
82
+ ) -> int:
83
+ """
84
+ Hash a single message in one call, produce 128-bit output.
85
+
86
+ :param message: message to hash
87
+ :param seed1: 64-bit seed 1
88
+ :param seed2: 64-bit seed 2
89
+ :return: 128-bit hash
90
+ """
91
+ val1, val2 = hash128_pair(message, seed1=seed1, seed2=seed2)
92
+ return val2 << 64 | val1
93
+
94
+
95
+ # Incremental hash builders
96
+
97
+ class Hash(ABC):
98
+ """Base class for incremental hash builders."""
99
+
100
+ digest_size: ClassVar[int]
101
+ _hash_cls: ClassVar[Type[_spookyhash.Hash]]
102
+
103
+ def __init__(
104
+ self,
105
+ message: Union[bytes, memoryview, None] = None,
106
+ seed1: int = 0,
107
+ seed2: int = 0,
108
+ ) -> None:
109
+ """
110
+ Initialise hash.
111
+
112
+ :param message: Optional initial message fragment
113
+ :param seed1: first seed
114
+ :param seed2: second seed
115
+ """
116
+ self._hash = self._hash_cls(seed1, seed2)
117
+ if message is not None:
118
+ self.update(message)
119
+
120
+ @property
121
+ def digest_size(self) -> int:
122
+ """
123
+ Digest size.
124
+
125
+ :return: Digest size
126
+ """
127
+ return self._hash.digest_size
128
+
129
+ def update(self, message: Union[bytes, memoryview, None]) -> 'Self':
130
+ """
131
+ Incrementally update hash with message fragment.
132
+
133
+ :param message: Message fragment
134
+ :return: Self
135
+ """
136
+ if message is not None:
137
+ self._hash.update(_char_arr(message))
138
+ return self
139
+
140
+ def digest(self) -> bytes:
141
+ """
142
+ Compute digest.
143
+
144
+ :return: Digest
145
+ """
146
+ return self._hash.digest()
147
+
148
+ def hexdigest(self) -> str:
149
+ """
150
+ Compute hex digest.
151
+
152
+ :return: Hex digest
153
+ """
154
+ return hexlify(self.digest()).decode('utf-8')
155
+
156
+ @abstractmethod
157
+ def final(self) -> int:
158
+ """
159
+ Compute the hash for the concatenation of all message fragments.
160
+
161
+ :return: Hash
162
+ """
163
+ return NotImplemented
164
+
165
+
166
+ class Hash32(Hash):
167
+ """32-bit incremental hash builder."""
168
+
169
+ _hash_cls = _spookyhash.Hash32
170
+
171
+ def __init__(
172
+ self,
173
+ message: Union[bytes, memoryview, None] = None,
174
+ seed: int = 0,
175
+ ) -> None:
176
+ """
177
+ Initialise 32-bit hash.
178
+
179
+ :param message: Optional initial message fragment
180
+ :param seed: 32-bit seed
181
+ """
182
+ super().__init__(message, seed, seed)
183
+
184
+ def final(self) -> int:
185
+ """
186
+ Compute the hash for the concatenation of all message fragments.
187
+
188
+ :return: Hash
189
+ """
190
+ return struct.unpack('=L', self.digest())[0]
191
+
192
+
193
+ class Hash64(Hash):
194
+
195
+ _hash_cls = _spookyhash.Hash64
196
+
197
+ def __init__(
198
+ self,
199
+ message: Union[bytes, memoryview, None] = None,
200
+ seed: int = 0,
201
+ ) -> None:
202
+ """
203
+ Initialise 64-bit hash.
204
+
205
+ :param message: Optional initial message fragment
206
+ :param seed: 64-bit seed
207
+ """
208
+ super().__init__(message, seed, seed)
209
+
210
+ def final(self) -> int:
211
+ """
212
+ Compute the hash for the concatenation of all message fragments.
213
+
214
+ :return: Hash
215
+ """
216
+ return struct.unpack('=Q', self.digest())[0]
217
+
218
+
219
+ class Hash128(Hash):
220
+
221
+ _hash_cls = _spookyhash.Hash128
222
+
223
+ def final_pair(self) -> Tuple[int, int]:
224
+ """
225
+ Compute the hash for the concatenation of all message fragments.
226
+
227
+ Returns a pair of 64-bit integer to match other common implementations.
228
+
229
+ :return: Pair of 64-bit integers representing the hash
230
+ """
231
+ return cast(Tuple[int, int], struct.unpack('=QQ', self.digest()))
232
+
233
+ def final(self) -> int:
234
+ """
235
+ Compute the hash for the concatenation of all message fragments.
236
+
237
+ :return: Hash
238
+ """
239
+ hash1, hash2 = self.final_pair()
240
+ return hash2 << 64 | hash1
@@ -1,12 +1,12 @@
1
1
  from libc.stdint cimport uint32_t, uint64_t
2
2
 
3
- cdef extern from 'SpookyV2.h':
3
+ cdef extern from 'SpookyV2.h' nogil:
4
4
  cdef cppclass SpookyHash:
5
5
  void Init(uint64_t seed1, uint64_t seed2)
6
6
  void Update(const char *message, size_t length)
7
7
  void Final(uint64_t *hash1, uint64_t *hash2)
8
8
 
9
- cdef extern from 'SpookyV2.h' namespace 'SpookyHash':
9
+ cdef extern from 'SpookyV2.h' namespace 'SpookyHash' nogil:
10
10
  void Hash128(const char *message, size_t length, uint64_t *hash1, uint64_t *hash2)
11
11
  uint64_t Hash64(const char *message, size_t length, uint64_t seed)
12
12
  uint32_t Hash32(const char *message, size_t length, uint32_t seed)