├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .prebuildrc ├── LICENSE ├── README.md ├── bench ├── bench.js └── package.json ├── binding.gyp ├── index.d.ts ├── index.js ├── index.test-d.ts ├── package.json ├── src ├── bindings.cc └── upstream │ ├── farmhash.cc │ └── farmhash.h └── test └── unit.js /.gitattributes: -------------------------------------------------------------------------------- 1 | src/upstream/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI (GitHub) 2 | on: 3 | - push 4 | - pull_request 5 | permissions: {} 6 | jobs: 7 | CI: 8 | permissions: 9 | contents: write 10 | name: ${{ matrix.container || matrix.os }} - Node.js ${{ matrix.nodejs_version }} ${{ matrix.nodejs_arch }} ${{ matrix.prebuild && '- prebuild' }} 11 | runs-on: ${{ matrix.os }} 12 | container: ${{ matrix.container }} 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | include: 17 | - os: ubuntu-24.04 18 | container: rockylinux:8 19 | nodejs_version: 16 20 | prebuild: true 21 | - os: ubuntu-24.04 22 | container: rockylinux:8 23 | nodejs_version: 18 24 | - os: ubuntu-24.04 25 | container: rockylinux:8 26 | nodejs_version: 20 27 | - os: ubuntu-24.04 28 | container: rockylinux:8 29 | nodejs_version: 22 30 | - os: ubuntu-24.04 31 | container: node:16-alpine3.12 32 | prebuild: true 33 | - os: ubuntu-24.04 34 | container: node:18-alpine3.14 35 | - os: ubuntu-24.04 36 | container: node:20-alpine3.18 37 | - os: ubuntu-24.04 38 | container: node:22-alpine3.20 39 | - os: macos-12 40 | nodejs_version: 16 41 | nodejs_arch: x64 42 | prebuild: true 43 | - os: macos-12 44 | nodejs_version: 18 45 | nodejs_arch: x64 46 | - os: macos-12 47 | nodejs_version: 20 48 | nodejs_arch: x64 49 | - os: macos-12 50 | nodejs_version: 22 51 | nodejs_arch: x64 52 | - os: macos-14 53 | nodejs_version: 18 54 | nodejs_arch: arm64 55 | prebuild: true 56 | - os: macos-14 57 | nodejs_version: 20 58 | nodejs_arch: arm64 59 | - os: macos-14 60 | nodejs_version: 22 61 | nodejs_arch: arm64 62 | - os: windows-2019 63 | nodejs_version: 16 64 | nodejs_arch: x86 65 | prebuild: true 66 | - os: windows-2019 67 | nodejs_version: 18 68 | nodejs_arch: x86 69 | - os: windows-2019 70 | nodejs_version: 20 71 | nodejs_arch: x86 72 | - os: windows-2019 73 | nodejs_version: 22 74 | nodejs_arch: x86 75 | - os: windows-2019 76 | nodejs_version: 16 77 | nodejs_arch: x64 78 | prebuild: true 79 | - os: windows-2019 80 | nodejs_version: 18 81 | nodejs_arch: x64 82 | - os: windows-2019 83 | nodejs_version: 20 84 | nodejs_arch: x64 85 | - os: windows-2019 86 | nodejs_version: 22 87 | nodejs_arch: x64 88 | steps: 89 | - name: Dependencies (Rocky Linux glibc) 90 | if: contains(matrix.container, 'rockylinux') 91 | run: | 92 | curl -sL https://rpm.nodesource.com/setup_${{ matrix.nodejs_version }}.x | bash - 93 | dnf install -y gcc-toolset-11-gcc-c++ make git python3.12 nodejs 94 | echo "/opt/rh/gcc-toolset-11/root/usr/bin" >> $GITHUB_PATH 95 | echo "PYTHON=/usr/bin/python3.12" >> $GITHUB_ENV 96 | - name: Dependencies (Linux musl) 97 | if: contains(matrix.container, 'alpine') 98 | run: apk add build-base git python3 --update-cache 99 | - name: Dependencies (Python - macOS, Windows) 100 | if: contains(matrix.os, 'macos') || contains(matrix.os, 'windows') 101 | uses: actions/setup-python@v5 102 | with: 103 | python-version: "3.12" 104 | - name: Dependencies (Node.js - macOS, Windows) 105 | if: contains(matrix.os, 'macos') || contains(matrix.os, 'windows') 106 | uses: actions/setup-node@v4 107 | with: 108 | node-version: ${{ matrix.nodejs_version }} 109 | architecture: ${{ matrix.nodejs_arch }} 110 | - name: Add compiler flags 111 | if: matrix.os != 'macos-14' 112 | run: echo "CXXFLAGS=-march=nehalem" >> $GITHUB_ENV 113 | - name: Checkout 114 | uses: actions/checkout@v4 115 | - name: Install 116 | run: npm install --build-from-source --unsafe-perm 117 | - name: Test 118 | run: npm test 119 | - name: Prebuild 120 | if: matrix.prebuild && startsWith(github.ref, 'refs/tags/') 121 | env: 122 | prebuild_upload: ${{ secrets.GITHUB_TOKEN }} 123 | run: npx prebuild --runtime napi --target 8 124 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | build 3 | node_modules 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.prebuildrc: -------------------------------------------------------------------------------- 1 | {"strip":true} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # farmhash 2 | 3 | Node.js implementation of Google's 4 | [FarmHash](https://github.com/google/farmhash) 5 | family of very fast hash functions. 6 | 7 | FarmHash is the successor to CityHash. 8 | Functions in the FarmHash family are not suitable for cryptography. 9 | A fast, cryptographically-secure alternative is 10 | [HighwayHash](https://github.com/lovell/highwayhash). 11 | 12 | The 32-bit methods return a `Number`, 13 | the 64-bit methods return a `BigInt` 14 | and the 128-bit methods are not implemented. 15 | 16 | This module uses FarmHash v1.1.0 (2015-03-01). 17 | It has been tested with Node.js 16, 18, 20 and 22 18 | on Linux (glibc, musl), 19 | macOS (x64, arm64) and 20 | Windows (x86, x64). 21 | 22 | Pre-compiled binaries are provided for 23 | Intel CPUs with SSE4.2 intrinsics 24 | and Apple ARM64 CPUs. 25 | Use the `npm install --build-from-source` flag to gain performance benefits 26 | on more modern CPUs such as those with AVX intrinsics. 27 | 28 | ## Installation 29 | 30 | ```sh 31 | npm install farmhash 32 | ``` 33 | 34 | ```sh 35 | yarn add farmhash 36 | ``` 37 | 38 | ```sh 39 | pnpm add farmhash 40 | ``` 41 | 42 | ## Usage 43 | 44 | ```javascript 45 | const farmhash = require('farmhash'); 46 | ``` 47 | 48 | ```javascript 49 | const hash = farmhash.hash32('test'); 50 | console.log(typeof hash); // 'number' 51 | ``` 52 | 53 | ```javascript 54 | const hash = farmhash.hash64(new Buffer('test')); 55 | console.log(typeof hash); // 'bigint' 56 | ``` 57 | 58 | ```javascript 59 | const hash = farmhash.hash64WithSeed('test', 123); 60 | console.log(typeof hash); // 'bigint' 61 | ``` 62 | 63 | ```javascript 64 | const hash = farmhash.fingerprint32(new Buffer('test')); 65 | console.log(typeof hash); // 'number' 66 | ``` 67 | 68 | ```javascript 69 | const hash = farmhash.fingerprint64('test'); 70 | console.log(typeof hash); // 'bigint' 71 | ``` 72 | 73 | ```javascript 74 | const hash = farmhash.fingerprint64signed('test'); 75 | console.log(typeof hash); // 'bigint' 76 | ``` 77 | 78 | ## API 79 | 80 | ### Hash 81 | 82 | The hash methods are platform dependent. 83 | Different CPU architectures, for example 32-bit vs 64-bit, Intel vs ARM, SSE4.2 vs AVX 84 | might produce different results for a given input. 85 | 86 | #### hash32(input) 87 | 88 | * `input` is the `Buffer` or `String` to hash. 89 | 90 | Returns a `Number` containing the 32-bit unsigned integer hash value of `input`. 91 | 92 | #### hash32WithSeed(input, seed) 93 | 94 | * `input` is the `Buffer` or `String` to hash. 95 | * `seed` is an integer Number to use as a seed. 96 | 97 | Returns a `Number` containing the 32-bit unsigned integer hash value of `input`. 98 | 99 | #### hash64(input) 100 | 101 | * `input` is the `Buffer` or `String` to hash. 102 | 103 | Returns a `BigInt` containing the 64-bit unsigned integer hash value of `input`. 104 | 105 | #### hash64WithSeed(input, seed) 106 | 107 | * `input` is the `Buffer` or `String` to hash. 108 | * `seed` is an integer `Number` to use as a seed. 109 | 110 | Returns a `BigInt` containing the 64-bit unsigned integer hash value of `input`. 111 | 112 | #### hash64WithSeeds(input, seed1, seed2) 113 | 114 | * `input` is the `Buffer` or `String` to hash. 115 | * `seed1` and `seed2` are both an integer `Number` to use as seeds. 116 | 117 | Returns a `BigInt` containing the 64-bit unsigned integer hash value of `input`. 118 | 119 | ### Fingerprint 120 | 121 | The fingerprint methods are platform independent, producing the same results for a given input on any machine. 122 | 123 | #### fingerprint32(input) 124 | 125 | * `input` is the `Buffer` or `String` to fingerprint. 126 | 127 | Returns a `Number` containing the 32-bit unsigned integer fingerprint value of `input`. 128 | 129 | #### fingerprint64(input) 130 | 131 | * `input` is the `Buffer` or `String` to fingerprint. 132 | 133 | Returns a `BigInt` containing the 64-bit unsigned integer fingerprint value of `input`. 134 | 135 | #### fingerprint64signed(input) 136 | 137 | * `input` is the `Buffer` or `String` to fingerprint. 138 | 139 | Returns a `BigInt` containing the 64-bit signed integer fingerprint value of `input`. 140 | 141 | This matches the signed behaviour of Google BigQuery's 142 | [FARM_FINGERPRINT](https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#farm_fingerprint) 143 | function. 144 | 145 | ## Testing 146 | 147 | ```sh 148 | npm test 149 | ``` 150 | 151 | ## Licence 152 | 153 | Copyright 2014 Lovell Fuller and contributors. 154 | 155 | Licensed under the Apache License, Version 2.0 (the "License"); 156 | you may not use this file except in compliance with the License. 157 | You may obtain a copy of the License at 158 | 159 | https://www.apache.org/licenses/LICENSE-2.0 160 | 161 | Unless required by applicable law or agreed to in writing, software 162 | distributed under the License is distributed on an "AS IS" BASIS, 163 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 164 | See the License for the specific language governing permissions and 165 | limitations under the License. 166 | 167 | Copyright 2014, 2015, 2016, 2017 Google, Inc. 168 | 169 | Permission is hereby granted, free of charge, to any person obtaining a copy 170 | of this software and associated documentation files (the "Software"), to deal 171 | in the Software without restriction, including without limitation the rights 172 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 173 | copies of the Software, and to permit persons to whom the Software is 174 | furnished to do so, subject to the following conditions: 175 | 176 | The above copyright notice and this permission notice shall be included in 177 | all copies or substantial portions of the Software. 178 | 179 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 180 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 182 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 183 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 184 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 185 | THE SOFTWARE. 186 | -------------------------------------------------------------------------------- /bench/bench.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Benchmark = require('benchmark'); 4 | const murmurhash3 = require('murmurhash3'); 5 | const xxhash = require('xxhash'); 6 | const farmhash = require('../index'); 7 | 8 | function randomInteger () { 9 | return Math.floor(Math.random() * 2147483647); 10 | } 11 | 12 | function randomStringOfLength (length) { 13 | let str = ''; 14 | while (str.length < length) { 15 | str = str + Math.random().toString(36).slice(2); 16 | } 17 | return str.slice(0, length); 18 | } 19 | 20 | // Test 1 21 | 22 | (function () { 23 | console.log('Test seed collisions (same key, different seeds)'); 24 | 25 | const input = randomStringOfLength(100); 26 | const inputBuffer = Buffer.from(input); // xxhash 27 | console.log('Using input of length ' + input.length); 28 | const iterations = 1000000; 29 | console.log('Using ' + iterations + ' iterations'); 30 | 31 | const hashes = { 32 | murmurhash3: {}, 33 | xxhash: {}, 34 | farmhash: {} 35 | }; 36 | const collisions = { 37 | murmurhash3: 0, 38 | xxhash: 0, 39 | farmhash: 0 40 | }; 41 | for (let seed = 0; seed < iterations; seed++) { 42 | const murmur = murmurhash3.murmur32Sync(input, seed); 43 | if (murmur in hashes.murmurhash3) { 44 | collisions.murmurhash3++; 45 | } else { 46 | hashes.murmurhash3[murmur] = true; 47 | } 48 | const xx = xxhash.hash(inputBuffer, seed); 49 | if (xx in hashes.xxhash) { 50 | collisions.xxhash++; 51 | } else { 52 | hashes.xxhash[xx] = true; 53 | } 54 | const farm = farmhash.hash32WithSeed(input, seed); 55 | if (farm in hashes.farmhash) { 56 | collisions.farmhash++; 57 | } else { 58 | hashes.farmhash[farm] = true; 59 | } 60 | } 61 | console.log('Collisions:'); 62 | console.dir(collisions); 63 | console.log(); 64 | })(); 65 | 66 | // Test 2 67 | 68 | (function () { 69 | console.log('Test key collisions (same seed, different keys)'); 70 | 71 | const seed = randomInteger(); 72 | console.log('Using seed ' + seed); 73 | const keyLength = 100; 74 | console.log('Using key length of ' + keyLength); 75 | const iterations = 1000000; 76 | console.log('Using ' + iterations + ' iterations'); 77 | 78 | const hashes = { 79 | murmurhash3: {}, 80 | xxhash: {}, 81 | farmhash: {} 82 | }; 83 | const collisions = { 84 | murmurhash3: 0, 85 | xxhash: 0, 86 | farmhash: 0 87 | }; 88 | for (let i = 0; i < iterations; i++) { 89 | const input = randomStringOfLength(keyLength); 90 | const inputBuffer = Buffer.from(input); // xxhash 91 | 92 | const murmur = murmurhash3.murmur32Sync(input, seed); 93 | if (murmur in hashes.murmurhash3) { 94 | collisions.murmurhash3++; 95 | } else { 96 | hashes.murmurhash3[murmur] = true; 97 | } 98 | const xx = xxhash.hash(inputBuffer, seed); 99 | if (xx in hashes.xxhash) { 100 | collisions.xxhash++; 101 | } else { 102 | hashes.xxhash[xx] = true; 103 | } 104 | const farm = farmhash.hash32WithSeed(input, seed); 105 | if (farm in hashes.farmhash) { 106 | collisions.farmhash++; 107 | } else { 108 | hashes.farmhash[farm] = true; 109 | } 110 | } 111 | console.log('Collisions:'); 112 | console.dir(collisions); 113 | console.log(); 114 | })(); 115 | 116 | // Test 3 117 | 118 | (function () { 119 | console.log('Test key length performance'); 120 | 121 | const seed = randomInteger(); 122 | const seed2 = randomInteger(); 123 | console.log('Using seed ' + seed); 124 | 125 | [100, 1000, 10000].forEach(function (length) { 126 | const input = randomStringOfLength(length); 127 | const inputBuffer = Buffer.from(input); // xxhash 128 | console.log('Using key of length ' + length); 129 | 130 | (new Benchmark.Suite()) 131 | .add('murmurhash3', function () { 132 | murmurhash3.murmur32Sync(input); 133 | }) 134 | .add('murmurhash3+seed', function () { 135 | murmurhash3.murmur32Sync(input, seed); 136 | }) 137 | .add('farmhash-hash32-string', function () { 138 | farmhash.hash32(input); 139 | }) 140 | .add('farmhash-hash32-buffer', function () { 141 | farmhash.hash32(inputBuffer); 142 | }) 143 | .add('farmhash-hash32+seed-string', function () { 144 | farmhash.hash32WithSeed(input, seed); 145 | }) 146 | .add('farmhash-hash32+seed-buffer', function () { 147 | farmhash.hash32WithSeed(inputBuffer, seed); 148 | }) 149 | .add('farmhash-fingerprint32-string', function () { 150 | farmhash.fingerprint32(input); 151 | }) 152 | .add('farmhash-fingerprint32-buffer', function () { 153 | farmhash.fingerprint32(inputBuffer); 154 | }) 155 | .add('farmhash-fingerprint64-string', function () { 156 | farmhash.fingerprint64(input); 157 | }) 158 | .add('farmhash-fingerprint64-buffer', function () { 159 | farmhash.fingerprint64(inputBuffer); 160 | }) 161 | .add('farmhash-hash64-string', function () { 162 | farmhash.hash64(input); 163 | }) 164 | .add('farmhash-hash64-buffer', function () { 165 | farmhash.hash64(inputBuffer); 166 | }) 167 | .add('farmhash-hash64+seed-string', function () { 168 | farmhash.hash64WithSeed(input, seed); 169 | }) 170 | .add('farmhash-hash64+seed-buffer', function () { 171 | farmhash.hash64WithSeed(inputBuffer, seed); 172 | }) 173 | .add('farmhash-hash64+seeds-string', function () { 174 | farmhash.hash64WithSeeds(input, seed, seed2); 175 | }) 176 | .add('farmhash-hash64+seeds-buffer', function () { 177 | farmhash.hash64WithSeeds(inputBuffer, seed, seed2); 178 | }) 179 | .add('xxhash+seed', function () { 180 | xxhash.hash(inputBuffer, seed); 181 | }) 182 | .on('cycle', function (event) { 183 | console.log(String(event.target)); 184 | }).run(); 185 | }); 186 | })(); 187 | -------------------------------------------------------------------------------- /bench/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "farmhash-bench", 3 | "version": "0.0.1", 4 | "author": "Lovell Fuller ", 5 | "private": true, 6 | "scripts": { 7 | "test": "node bench" 8 | }, 9 | "dependencies": { 10 | "benchmark": "^2.1.4", 11 | "murmurhash3": "^0.5.0", 12 | "xxhash": "^0.3.0" 13 | }, 14 | "license": "Apache-2.0", 15 | "engines": { 16 | "node": ">=4.5.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [{ 3 | 'target_name': 'farmhash', 4 | 'sources': [ 5 | 'src/upstream/farmhash.cc', 6 | 'src/bindings.cc' 7 | ], 8 | 'include_dirs' : [ 9 | "", 5 | "contributors": [ 6 | "Matt Ranney ", 7 | "Jonas Hermsmeier (https://jhermsmeier.de)" 8 | ], 9 | "description": "Node.js implementation of FarmHash, Google's family of very fast hash functions", 10 | "scripts": { 11 | "install": "prebuild-install || node-gyp rebuild", 12 | "test": "semistandard && cpplint && node test/unit && tsd" 13 | }, 14 | "main": "index.js", 15 | "files": [ 16 | "binding.gyp", 17 | "index.d.ts", 18 | "src/" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "git://github.com/lovell/farmhash" 23 | }, 24 | "keywords": [ 25 | "farmhash", 26 | "hash", 27 | "cityhash", 28 | "murmurhash", 29 | "fingerprint" 30 | ], 31 | "dependencies": { 32 | "node-addon-api": "^8.1.0", 33 | "prebuild-install": "^7.1.2" 34 | }, 35 | "devDependencies": { 36 | "@types/node": "*", 37 | "cc": "^3.0.1", 38 | "node-gyp": "^10.2.0", 39 | "prebuild": "^13.0.1", 40 | "semistandard": "^17.0.0", 41 | "tsd": "^0.31.2" 42 | }, 43 | "license": "Apache-2.0", 44 | "engines": { 45 | "node": ">=16" 46 | }, 47 | "binary": { 48 | "napi_versions": [ 49 | 8 50 | ] 51 | }, 52 | "config": { 53 | "runtime": "napi", 54 | "target": 8 55 | }, 56 | "cc": { 57 | "linelength": "120", 58 | "ignore": [ 59 | "node_modules", 60 | "src/upstream" 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/bindings.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014, 2015, 2016, 2017 Lovell Fuller and contributors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include "upstream/farmhash.h" 17 | 18 | // Hash methods - platform dependent 19 | 20 | Napi::Value Hash32Buffer(const Napi::CallbackInfo& info) { 21 | Napi::Env env = info.Env(); 22 | Napi::Buffer buffer = info[size_t(0)].As>(); 23 | uint32_t hash = util::Hash32(buffer.Data(), buffer.ByteLength()); 24 | return Napi::Number::New(env, hash); 25 | } 26 | 27 | Napi::Value Hash32String(const Napi::CallbackInfo& info) { 28 | Napi::Env env = info.Env(); 29 | std::string input = info[size_t(0)].As().Utf8Value(); 30 | uint32_t hash = util::Hash32(input); 31 | return Napi::Number::New(env, hash); 32 | } 33 | 34 | Napi::Value Hash32WithSeedBuffer(const Napi::CallbackInfo& info) { 35 | Napi::Env env = info.Env(); 36 | Napi::Buffer buffer = info[size_t(0)].As>(); 37 | uint32_t seed = info[size_t(1)].As().Uint32Value(); 38 | uint32_t hash = util::Hash32WithSeed(buffer.Data(), buffer.ByteLength(), seed); 39 | return Napi::Number::New(env, hash); 40 | } 41 | 42 | Napi::Value Hash32WithSeedString(const Napi::CallbackInfo& info) { 43 | Napi::Env env = info.Env(); 44 | std::string input = info[size_t(0)].As().Utf8Value(); 45 | uint32_t seed = info[size_t(1)].As().Uint32Value(); 46 | uint32_t hash = util::Hash32WithSeed(input, seed); 47 | return Napi::Number::New(env, hash); 48 | } 49 | 50 | Napi::Value Hash64Buffer(const Napi::CallbackInfo& info) { 51 | Napi::Env env = info.Env(); 52 | Napi::Buffer buffer = info[size_t(0)].As>(); 53 | uint64_t hash = util::Hash64(buffer.Data(), buffer.ByteLength()); 54 | return Napi::BigInt::New(env, hash); 55 | } 56 | 57 | Napi::Value Hash64String(const Napi::CallbackInfo& info) { 58 | Napi::Env env = info.Env(); 59 | std::string input = info[size_t(0)].As().Utf8Value(); 60 | uint64_t hash = util::Hash64(input); 61 | return Napi::BigInt::New(env, hash); 62 | } 63 | 64 | Napi::Value Hash64WithSeedBuffer(const Napi::CallbackInfo& info) { 65 | Napi::Env env = info.Env(); 66 | Napi::Buffer buffer = info[size_t(0)].As>(); 67 | uint64_t seed = static_cast(info[size_t(1)].As().Uint32Value()); 68 | uint64_t hash = util::Hash64WithSeed(buffer.Data(), buffer.ByteLength(), seed); 69 | return Napi::BigInt::New(env, hash); 70 | } 71 | 72 | Napi::Value Hash64WithSeedString(const Napi::CallbackInfo& info) { 73 | Napi::Env env = info.Env(); 74 | std::string input = info[size_t(0)].As().Utf8Value(); 75 | uint64_t seed = static_cast(info[size_t(1)].As().Uint32Value()); 76 | uint64_t hash = util::Hash64WithSeed(input, seed); 77 | return Napi::BigInt::New(env, hash); 78 | } 79 | 80 | Napi::Value Hash64WithSeedsBuffer(const Napi::CallbackInfo& info) { 81 | Napi::Env env = info.Env(); 82 | Napi::Buffer buffer = info[size_t(0)].As>(); 83 | uint64_t seed1 = static_cast(info[size_t(1)].As().Uint32Value()); 84 | uint64_t seed2 = static_cast(info[size_t(2)].As().Uint32Value()); 85 | uint64_t hash = util::Hash64WithSeeds(buffer.Data(), buffer.ByteLength(), seed1, seed2); 86 | return Napi::BigInt::New(env, hash); 87 | } 88 | 89 | Napi::Value Hash64WithSeedsString(const Napi::CallbackInfo& info) { 90 | Napi::Env env = info.Env(); 91 | std::string input = info[size_t(0)].As().Utf8Value(); 92 | uint64_t seed1 = static_cast(info[size_t(1)].As().Uint32Value()); 93 | uint64_t seed2 = static_cast(info[size_t(2)].As().Uint32Value()); 94 | uint64_t hash = util::Hash64WithSeeds(input, seed1, seed2); 95 | return Napi::BigInt::New(env, hash); 96 | } 97 | 98 | // Fingerprint methods - platform independent 99 | 100 | Napi::Value Fingerprint32Buffer(const Napi::CallbackInfo& info) { 101 | Napi::Env env = info.Env(); 102 | Napi::Buffer buffer = info[size_t(0)].As>(); 103 | uint32_t hash = util::Fingerprint32(buffer.Data(), buffer.ByteLength()); 104 | return Napi::Number::New(env, hash); 105 | } 106 | 107 | Napi::Value Fingerprint32String(const Napi::CallbackInfo& info) { 108 | Napi::Env env = info.Env(); 109 | std::string input = info[size_t(0)].As().Utf8Value(); 110 | uint32_t hash = util::Fingerprint32(input); 111 | return Napi::Number::New(env, hash); 112 | } 113 | 114 | Napi::Value Fingerprint64Buffer(const Napi::CallbackInfo& info) { 115 | Napi::Env env = info.Env(); 116 | Napi::Buffer buffer = info[size_t(0)].As>(); 117 | uint64_t hash = util::Fingerprint64(buffer.Data(), buffer.ByteLength()); 118 | return Napi::BigInt::New(env, hash); 119 | } 120 | 121 | Napi::Value Fingerprint64String(const Napi::CallbackInfo& info) { 122 | Napi::Env env = info.Env(); 123 | std::string input = info[size_t(0)].As().Utf8Value(); 124 | uint64_t hash = util::Fingerprint64(input); 125 | return Napi::BigInt::New(env, hash); 126 | } 127 | 128 | // Init 129 | 130 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 131 | exports.Set(Napi::String::New(env, "Hash32Buffer"), Napi::Function::New(env, Hash32Buffer)); 132 | exports.Set(Napi::String::New(env, "Hash32String"), Napi::Function::New(env, Hash32String)); 133 | exports.Set(Napi::String::New(env, "Hash32WithSeedBuffer"), Napi::Function::New(env, Hash32WithSeedBuffer)); 134 | exports.Set(Napi::String::New(env, "Hash32WithSeedString"), Napi::Function::New(env, Hash32WithSeedString)); 135 | exports.Set(Napi::String::New(env, "Hash64Buffer"), Napi::Function::New(env, Hash64Buffer)); 136 | exports.Set(Napi::String::New(env, "Hash64String"), Napi::Function::New(env, Hash64String)); 137 | exports.Set(Napi::String::New(env, "Hash64WithSeedBuffer"), Napi::Function::New(env, Hash64WithSeedBuffer)); 138 | exports.Set(Napi::String::New(env, "Hash64WithSeedString"), Napi::Function::New(env, Hash64WithSeedString)); 139 | exports.Set(Napi::String::New(env, "Hash64WithSeedsBuffer"), Napi::Function::New(env, Hash64WithSeedsBuffer)); 140 | exports.Set(Napi::String::New(env, "Hash64WithSeedsString"), Napi::Function::New(env, Hash64WithSeedsString)); 141 | exports.Set(Napi::String::New(env, "Fingerprint32Buffer"), Napi::Function::New(env, Fingerprint32Buffer)); 142 | exports.Set(Napi::String::New(env, "Fingerprint32String"), Napi::Function::New(env, Fingerprint32String)); 143 | exports.Set(Napi::String::New(env, "Fingerprint64Buffer"), Napi::Function::New(env, Fingerprint64Buffer)); 144 | exports.Set(Napi::String::New(env, "Fingerprint64String"), Napi::Function::New(env, Fingerprint64String)); 145 | return exports; 146 | } 147 | 148 | NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) 149 | -------------------------------------------------------------------------------- /src/upstream/farmhash.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Google, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | // 21 | // FarmHash, by Geoff Pike 22 | 23 | // 24 | // http://code.google.com/p/farmhash/ 25 | // 26 | // This file provides a few functions for hashing strings and other 27 | // data. All of them are high-quality functions in the sense that 28 | // they do well on standard tests such as Austin Appleby's SMHasher. 29 | // They're also fast. FarmHash is the successor to CityHash. 30 | // 31 | // Functions in the FarmHash family are not suitable for cryptography. 32 | // 33 | // WARNING: This code has been only lightly tested on big-endian platforms! 34 | // It is known to work well on little-endian platforms that have a small penalty 35 | // for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs. 36 | // It should work on all 32-bit and 64-bit platforms that allow unaligned reads; 37 | // bug reports are welcome. 38 | // 39 | // By the way, for some hash functions, given strings a and b, the hash 40 | // of a+b is easily derived from the hashes of a and b. This property 41 | // doesn't hold for any hash functions in this file. 42 | 43 | #ifndef FARM_HASH_H_ 44 | #define FARM_HASH_H_ 45 | 46 | #include 47 | #include 48 | #include 49 | #include // for memcpy and memset 50 | #include 51 | 52 | #ifndef NAMESPACE_FOR_HASH_FUNCTIONS 53 | #define NAMESPACE_FOR_HASH_FUNCTIONS util 54 | #endif 55 | 56 | namespace NAMESPACE_FOR_HASH_FUNCTIONS { 57 | 58 | #if defined(FARMHASH_UINT128_T_DEFINED) 59 | #if defined(__clang__) 60 | #if !defined(uint128_t) 61 | #define uint128_t __uint128_t 62 | #endif 63 | #endif 64 | inline uint64_t Uint128Low64(const uint128_t x) { 65 | return static_cast(x); 66 | } 67 | inline uint64_t Uint128High64(const uint128_t x) { 68 | return static_cast(x >> 64); 69 | } 70 | inline uint128_t Uint128(uint64_t lo, uint64_t hi) { 71 | return lo + (((uint128_t)hi) << 64); 72 | } 73 | #else 74 | typedef std::pair uint128_t; 75 | inline uint64_t Uint128Low64(const uint128_t x) { return x.first; } 76 | inline uint64_t Uint128High64(const uint128_t x) { return x.second; } 77 | inline uint128_t Uint128(uint64_t lo, uint64_t hi) { return uint128_t(lo, hi); } 78 | #endif 79 | 80 | 81 | // BASIC STRING HASHING 82 | 83 | // Hash function for a byte array. 84 | // May change from time to time, may differ on different platforms, may differ 85 | // depending on NDEBUG. 86 | size_t Hash(const char* s, size_t len); 87 | 88 | // Hash function for a byte array. Most useful in 32-bit binaries. 89 | // May change from time to time, may differ on different platforms, may differ 90 | // depending on NDEBUG. 91 | uint32_t Hash32(const char* s, size_t len); 92 | 93 | // Hash function for a byte array. For convenience, a 32-bit seed is also 94 | // hashed into the result. 95 | // May change from time to time, may differ on different platforms, may differ 96 | // depending on NDEBUG. 97 | uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed); 98 | 99 | // Hash function for a byte array. 100 | // May change from time to time, may differ on different platforms, may differ 101 | // depending on NDEBUG. 102 | uint64_t Hash64(const char* s, size_t len); 103 | 104 | // Hash function for a byte array. For convenience, a 64-bit seed is also 105 | // hashed into the result. 106 | // May change from time to time, may differ on different platforms, may differ 107 | // depending on NDEBUG. 108 | uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed); 109 | 110 | // Hash function for a byte array. For convenience, two seeds are also 111 | // hashed into the result. 112 | // May change from time to time, may differ on different platforms, may differ 113 | // depending on NDEBUG. 114 | uint64_t Hash64WithSeeds(const char* s, size_t len, 115 | uint64_t seed0, uint64_t seed1); 116 | 117 | // Hash function for a byte array. 118 | // May change from time to time, may differ on different platforms, may differ 119 | // depending on NDEBUG. 120 | uint128_t Hash128(const char* s, size_t len); 121 | 122 | // Hash function for a byte array. For convenience, a 128-bit seed is also 123 | // hashed into the result. 124 | // May change from time to time, may differ on different platforms, may differ 125 | // depending on NDEBUG. 126 | uint128_t Hash128WithSeed(const char* s, size_t len, uint128_t seed); 127 | 128 | // BASIC NON-STRING HASHING 129 | 130 | // Hash 128 input bits down to 64 bits of output. 131 | // This is intended to be a reasonably good hash function. 132 | // May change from time to time, may differ on different platforms, may differ 133 | // depending on NDEBUG. 134 | inline uint64_t Hash128to64(uint128_t x) { 135 | // Murmur-inspired hashing. 136 | const uint64_t kMul = 0x9ddfea08eb382d69ULL; 137 | uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; 138 | a ^= (a >> 47); 139 | uint64_t b = (Uint128High64(x) ^ a) * kMul; 140 | b ^= (b >> 47); 141 | b *= kMul; 142 | return b; 143 | } 144 | 145 | // FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) 146 | 147 | // Fingerprint function for a byte array. Most useful in 32-bit binaries. 148 | uint32_t Fingerprint32(const char* s, size_t len); 149 | 150 | // Fingerprint function for a byte array. 151 | uint64_t Fingerprint64(const char* s, size_t len); 152 | 153 | // Fingerprint function for a byte array. 154 | uint128_t Fingerprint128(const char* s, size_t len); 155 | 156 | // This is intended to be a good fingerprinting primitive. 157 | // See below for more overloads. 158 | inline uint64_t Fingerprint(uint128_t x) { 159 | // Murmur-inspired hashing. 160 | const uint64_t kMul = 0x9ddfea08eb382d69ULL; 161 | uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; 162 | a ^= (a >> 47); 163 | uint64_t b = (Uint128High64(x) ^ a) * kMul; 164 | b ^= (b >> 44); 165 | b *= kMul; 166 | b ^= (b >> 41); 167 | b *= kMul; 168 | return b; 169 | } 170 | 171 | // This is intended to be a good fingerprinting primitive. 172 | inline uint64_t Fingerprint(uint64_t x) { 173 | // Murmur-inspired hashing. 174 | const uint64_t kMul = 0x9ddfea08eb382d69ULL; 175 | uint64_t b = x * kMul; 176 | b ^= (b >> 44); 177 | b *= kMul; 178 | b ^= (b >> 41); 179 | b *= kMul; 180 | return b; 181 | } 182 | 183 | #ifndef FARMHASH_NO_CXX_STRING 184 | 185 | // Convenience functions to hash or fingerprint C++ strings. 186 | // These require that Str::data() return a pointer to the first char 187 | // (as a const char*) and that Str::length() return the string's length; 188 | // they work with std::string, for example. 189 | 190 | // Hash function for a byte array. 191 | // May change from time to time, may differ on different platforms, may differ 192 | // depending on NDEBUG. 193 | template 194 | inline size_t Hash(const Str& s) { 195 | assert(sizeof(s[0]) == 1); 196 | return Hash(s.data(), s.length()); 197 | } 198 | 199 | // Hash function for a byte array. Most useful in 32-bit binaries. 200 | // May change from time to time, may differ on different platforms, may differ 201 | // depending on NDEBUG. 202 | template 203 | inline uint32_t Hash32(const Str& s) { 204 | assert(sizeof(s[0]) == 1); 205 | return Hash32(s.data(), s.length()); 206 | } 207 | 208 | // Hash function for a byte array. For convenience, a 32-bit seed is also 209 | // hashed into the result. 210 | // May change from time to time, may differ on different platforms, may differ 211 | // depending on NDEBUG. 212 | template 213 | inline uint32_t Hash32WithSeed(const Str& s, uint32_t seed) { 214 | assert(sizeof(s[0]) == 1); 215 | return Hash32WithSeed(s.data(), s.length(), seed); 216 | } 217 | 218 | // Hash 128 input bits down to 64 bits of output. 219 | // Hash function for a byte array. 220 | // May change from time to time, may differ on different platforms, may differ 221 | // depending on NDEBUG. 222 | template 223 | inline uint64_t Hash64(const Str& s) { 224 | assert(sizeof(s[0]) == 1); 225 | return Hash64(s.data(), s.length()); 226 | } 227 | 228 | // Hash function for a byte array. For convenience, a 64-bit seed is also 229 | // hashed into the result. 230 | // May change from time to time, may differ on different platforms, may differ 231 | // depending on NDEBUG. 232 | template 233 | inline uint64_t Hash64WithSeed(const Str& s, uint64_t seed) { 234 | assert(sizeof(s[0]) == 1); 235 | return Hash64WithSeed(s.data(), s.length(), seed); 236 | } 237 | 238 | // Hash function for a byte array. For convenience, two seeds are also 239 | // hashed into the result. 240 | // May change from time to time, may differ on different platforms, may differ 241 | // depending on NDEBUG. 242 | template 243 | inline uint64_t Hash64WithSeeds(const Str& s, uint64_t seed0, uint64_t seed1) { 244 | assert(sizeof(s[0]) == 1); 245 | return Hash64WithSeeds(s.data(), s.length(), seed0, seed1); 246 | } 247 | 248 | // Hash function for a byte array. 249 | // May change from time to time, may differ on different platforms, may differ 250 | // depending on NDEBUG. 251 | template 252 | inline uint128_t Hash128(const Str& s) { 253 | assert(sizeof(s[0]) == 1); 254 | return Hash128(s.data(), s.length()); 255 | } 256 | 257 | // Hash function for a byte array. For convenience, a 128-bit seed is also 258 | // hashed into the result. 259 | // May change from time to time, may differ on different platforms, may differ 260 | // depending on NDEBUG. 261 | template 262 | inline uint128_t Hash128WithSeed(const Str& s, uint128_t seed) { 263 | assert(sizeof(s[0]) == 1); 264 | return Hash128(s.data(), s.length(), seed); 265 | } 266 | 267 | // FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) 268 | 269 | // Fingerprint function for a byte array. Most useful in 32-bit binaries. 270 | template 271 | inline uint32_t Fingerprint32(const Str& s) { 272 | assert(sizeof(s[0]) == 1); 273 | return Fingerprint32(s.data(), s.length()); 274 | } 275 | 276 | // Fingerprint 128 input bits down to 64 bits of output. 277 | // Fingerprint function for a byte array. 278 | template 279 | inline uint64_t Fingerprint64(const Str& s) { 280 | assert(sizeof(s[0]) == 1); 281 | return Fingerprint64(s.data(), s.length()); 282 | } 283 | 284 | // Fingerprint function for a byte array. 285 | template 286 | inline uint128_t Fingerprint128(const Str& s) { 287 | assert(sizeof(s[0]) == 1); 288 | return Fingerprint128(s.data(), s.length()); 289 | } 290 | 291 | #endif 292 | 293 | } // namespace NAMESPACE_FOR_HASH_FUNCTIONS 294 | 295 | /* gently define FARMHASH_BIG_ENDIAN when detected big-endian machine */ 296 | #if defined(__BIG_ENDIAN__) 297 | #if !defined(FARMHASH_BIG_ENDIAN) 298 | #define FARMHASH_BIG_ENDIAN 299 | #endif 300 | #elif defined(__LITTLE_ENDIAN__) 301 | // nothing for little-endian 302 | #elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER == __ORDER_LITTLE_ENDIAN__) 303 | // nothing for little-endian 304 | #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER == __ORDER_BIG_ENDIAN__) 305 | #if !defined(FARMHASH_BIG_ENDIAN) 306 | #define FARMHASH_BIG_ENDIAN 307 | #endif 308 | #elif defined(__linux__) || defined(__CYGWIN__) || defined( __GNUC__ ) && !defined(_WIN32) || defined( __GNU_LIBRARY__ ) 309 | #include // libc6-dev, GLIBC 310 | #if BYTE_ORDER == BIG_ENDIAN 311 | #if !defined(FARMHASH_BIG_ENDIAN) 312 | #define FARMHASH_BIG_ENDIAN 313 | #endif 314 | #endif 315 | #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__s390x__) 316 | #include 317 | #if BYTE_ORDER == BIG_ENDIAN 318 | #if !defined(FARMHASH_BIG_ENDIAN) 319 | #define FARMHASH_BIG_ENDIAN 320 | #endif 321 | #endif 322 | #elif defined(_WIN32) 323 | // Windows is (currently) little-endian 324 | #else 325 | #error "Unable to determine endianness!" 326 | #endif /* __BIG_ENDIAN__ */ 327 | 328 | #endif // FARM_HASH_H_ 329 | -------------------------------------------------------------------------------- /test/unit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const farmhash = require('../index'); 5 | 6 | const input = 'The quick brown fox jumped over the lazy sleeping dog'; 7 | const seed = 123; 8 | 9 | // hash32 - valid 10 | const hash32 = farmhash.hash32(input); 11 | assert.strictEqual('number', typeof hash32); 12 | assert.strictEqual(true, hash32 > 0); 13 | 14 | // hash32 - invalid 15 | assert.throws(function () { 16 | farmhash.hash32(seed); 17 | }); 18 | 19 | // hash32WithSeed - valid 20 | const hash32WithSeed = farmhash.hash32WithSeed(input, seed); 21 | assert.strictEqual('number', typeof hash32WithSeed); 22 | assert.strictEqual(true, hash32WithSeed > 0); 23 | 24 | // hash32WithSeed - invalid 25 | assert.throws(function () { 26 | farmhash.hash32WithSeed(input); 27 | }); 28 | assert.throws(function () { 29 | farmhash.hash32WithSeed(seed, seed); 30 | }); 31 | assert.throws(function () { 32 | farmhash.hash32WithSeed(input, input); 33 | }); 34 | 35 | // hash64 - valid 36 | const hash64 = farmhash.hash64(input); 37 | assert.strictEqual('bigint', typeof hash64); 38 | assert.strictEqual(true, /^[0-9]{1,20}$/.test(hash64.toString())); 39 | 40 | // hash64 - invalid 41 | assert.throws(function () { 42 | farmhash.hash64(seed); 43 | }); 44 | 45 | // hash64WithSeed - valid 46 | const hash64WithSeed = farmhash.hash64WithSeed(input, seed); 47 | assert.strictEqual('bigint', typeof hash64WithSeed); 48 | assert.strictEqual(true, /^[0-9]{1,20}$/.test(hash64WithSeed.toString())); 49 | 50 | // hash64WithSeed - invalid 51 | assert.throws(function () { 52 | farmhash.hash64WithSeed(input); 53 | }); 54 | assert.throws(function () { 55 | farmhash.hash64WithSeed(seed, seed); 56 | }); 57 | assert.throws(function () { 58 | farmhash.hash32WithSeed(input, input); 59 | }); 60 | 61 | // hash64WithSeeds - valid 62 | const hash64WithSeeds = farmhash.hash64WithSeeds(input, seed, seed); 63 | assert.strictEqual('bigint', typeof hash64WithSeeds); 64 | assert.strictEqual(true, /^[0-9]{1,20}$/.test(hash64WithSeeds.toString())); 65 | 66 | // hash64WithSeeds - invalid 67 | assert.throws(function () { 68 | farmhash.hash64WithSeeds(input); 69 | }); 70 | assert.throws(function () { 71 | farmhash.hash64WithSeeds(input, seed); 72 | }); 73 | assert.throws(function () { 74 | farmhash.hash64WithSeeds(input, input, input); 75 | }); 76 | assert.throws(function () { 77 | farmhash.hash64WithSeeds(seed, seed, seed); 78 | }); 79 | 80 | // fingerprint32 - valid 81 | const fingerprint32 = farmhash.fingerprint32(input); 82 | assert.strictEqual('number', typeof fingerprint32); 83 | assert.strictEqual(2280764877, fingerprint32); 84 | 85 | // fingerprint32 - invalid 86 | assert.throws(function () { 87 | farmhash.fingerprint32(seed); 88 | }); 89 | 90 | // fingerprint64 - valid 91 | const fingerprint64 = farmhash.fingerprint64(input); 92 | assert.strictEqual('bigint', typeof fingerprint64); 93 | assert.strictEqual('17097846426514660294', fingerprint64.toString()); 94 | 95 | // https://github.com/lovell/farmhash/issues/26 96 | assert.strictEqual('16905089972579912905', farmhash.fingerprint64('1footrue').toString()); 97 | assert.strictEqual('-1541654101129638711', farmhash.fingerprint64signed('1footrue').toString()); 98 | 99 | // fingerprint64 - invalid 100 | assert.throws(function () { 101 | farmhash.fingerprint64(seed); 102 | }); 103 | --------------------------------------------------------------------------------