cityhash 0.5.0 → 0.6.0
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.
- data/.gitignore +7 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -7
- data/README.md +21 -16
- data/Rakefile +12 -46
- data/cityhash.gemspec +15 -69
- data/ext/cityhash/city.cc +229 -70
- data/ext/cityhash/city.h +1 -1
- data/ext/cityhash/cityhash.cc +47 -0
- data/ext/cityhash/extconf.rb +2 -6
- data/lib/cityhash.rb +12 -52
- data/lib/cityhash/version.rb +1 -10
- data/test/cityhash_test.rb +24 -0
- data/test/test_helper.rb +4 -0
- metadata +22 -90
- data/.document +0 -5
- data/Gemfile.lock +0 -23
- data/ext/cityhash/city_ruby_bridge.cpp +0 -19
- data/ext/cityhash/city_ruby_bridge.h +0 -8
- data/test/helper.rb +0 -18
- data/test/test_cityhash.rb +0 -26
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
### cityhash
|
|
1
|
+
### cityhash [](http://travis-ci.org/nashby/cityhash)
|
|
2
2
|
|
|
3
3
|
Ruby wrapper for google's cityhash.
|
|
4
4
|
|
|
5
5
|
### Install
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
gem install cityhash
|
|
8
8
|
|
|
9
9
|
### Usage
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
```ruby
|
|
12
|
+
require 'cityhash'
|
|
13
|
+
|
|
14
|
+
text = "test"
|
|
15
|
+
seed1 = 12345
|
|
16
|
+
seed2 = 54321
|
|
17
|
+
|
|
18
|
+
CityHash.hash64(text) # => 17703940110308125106
|
|
19
|
+
CityHash.hash64(text, seed1) # => 14900027982776226655
|
|
20
|
+
CityHash.hash64(text, seed1, seed2) # => 11136353178704814373
|
|
21
|
+
CityHash.hash128(text) # => 1800071687761605184910580728449884026697
|
|
22
|
+
CityHash.hash128(text, seed1) # => 6087407617808651818174120599816915369
|
|
23
|
+
```
|
|
24
|
+
|
|
23
25
|
### Contributing to cityhash
|
|
24
|
-
|
|
26
|
+
|
|
25
27
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
|
26
28
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
|
27
29
|
* Fork the project
|
|
@@ -34,10 +36,13 @@ Ruby wrapper for google's cityhash.
|
|
|
34
36
|
|
|
35
37
|
#### [Contributors](http://github.com/nashby/cityhash/contributors)
|
|
36
38
|
- [Johannes Holzfuß](http://github.com/DataWraith)
|
|
39
|
+
- [Quin Hoxie](https://github.com/qhoxie)
|
|
40
|
+
- [David Dai](https://github.com/newtonapple)
|
|
41
|
+
- [Sergey Nartimov](https://github.com/lest)
|
|
37
42
|
|
|
38
43
|
[Vasiliy Ermolovich](http://github.com/nashby/)<br/>
|
|
39
44
|
|
|
40
45
|
### Copyright
|
|
41
46
|
|
|
42
|
-
Copyright (c)
|
|
47
|
+
Copyright (c) 2012 Vasiliy Ermolovich. See LICENSE.txt for
|
|
43
48
|
further details.
|
data/Rakefile
CHANGED
|
@@ -1,54 +1,20 @@
|
|
|
1
|
-
require
|
|
2
|
-
require 'bundler'
|
|
3
|
-
begin
|
|
4
|
-
Bundler.setup(:default, :development)
|
|
5
|
-
rescue Bundler::BundlerError => e
|
|
6
|
-
$stderr.puts e.message
|
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
|
8
|
-
exit e.status_code
|
|
9
|
-
end
|
|
10
|
-
require 'rake'
|
|
11
|
-
|
|
12
|
-
$LOAD_PATH.unshift('lib')
|
|
13
|
-
|
|
14
|
-
require 'jeweler'
|
|
15
|
-
require 'cityhash/version'
|
|
16
|
-
Jeweler::Tasks.new do |gem|
|
|
17
|
-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
|
18
|
-
gem.name = "cityhash"
|
|
19
|
-
gem.homepage = "http://github.com/nashby/cityhash"
|
|
20
|
-
gem.license = "MIT"
|
|
21
|
-
gem.version = CityHash::Version::STRING
|
|
22
|
-
gem.summary = "ffi wrapper for google's cityhash"
|
|
23
|
-
gem.description = "ffi wrapper for google's cityhash"
|
|
24
|
-
gem.email = "younash@gmail.com"
|
|
25
|
-
gem.authors = ["nashby"]
|
|
26
|
-
gem.add_runtime_dependency 'ffi'
|
|
27
|
-
end
|
|
28
|
-
Jeweler::RubygemsDotOrgTasks.new
|
|
1
|
+
require "bundler/gem_tasks"
|
|
29
2
|
|
|
30
3
|
require 'rake/testtask'
|
|
31
|
-
|
|
32
|
-
test.libs << 'lib' << 'test'
|
|
33
|
-
test.pattern = 'test/**/test_*.rb'
|
|
34
|
-
test.verbose = true
|
|
35
|
-
end
|
|
4
|
+
require 'rake/clean'
|
|
36
5
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
test.verbose = true
|
|
6
|
+
Rake::TestTask.new do |t|
|
|
7
|
+
t.libs << 'test'
|
|
8
|
+
t.pattern = 'test/*_test.rb'
|
|
9
|
+
t.verbose = true
|
|
42
10
|
end
|
|
43
11
|
|
|
12
|
+
desc "Run tests"
|
|
44
13
|
task :default => :test
|
|
45
14
|
|
|
46
|
-
require 'rake/
|
|
47
|
-
Rake::
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
51
|
-
rdoc.title = "cityhash #{version}"
|
|
52
|
-
rdoc.rdoc_files.include('README*')
|
|
53
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
+
require 'rake/extensiontask'
|
|
16
|
+
Rake::ExtensionTask.new('cityhash') do |ext|
|
|
17
|
+
ext.lib_dir = 'lib/cityhash'
|
|
54
18
|
end
|
|
19
|
+
|
|
20
|
+
Rake::Task[:test].prerequisites << :compile
|
data/cityhash.gemspec
CHANGED
|
@@ -1,75 +1,21 @@
|
|
|
1
|
-
# Generated by jeweler
|
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "cityhash/version"
|
|
5
4
|
|
|
6
5
|
Gem::Specification.new do |s|
|
|
7
|
-
s.name
|
|
8
|
-
s.version
|
|
6
|
+
s.name = "cityhash"
|
|
7
|
+
s.version = CityHash::VERSION
|
|
8
|
+
s.authors = ["Vasiliy Ermolovich"]
|
|
9
|
+
s.email = ["younash@gmail.com"]
|
|
10
|
+
s.homepage = "http://github.com/nashby/cityhash"
|
|
11
|
+
s.summary = %q{ruby bindings for google's cityhash}
|
|
12
|
+
s.description = %q{ruby bindings for google's cityhash}
|
|
9
13
|
|
|
10
|
-
s.
|
|
11
|
-
s.authors = [%q{nashby}]
|
|
12
|
-
s.date = %q{2011-10-28}
|
|
13
|
-
s.description = %q{ffi wrapper for google's cityhash}
|
|
14
|
-
s.email = %q{younash@gmail.com}
|
|
15
|
-
s.extensions = [%q{ext/cityhash/extconf.rb}]
|
|
16
|
-
s.extra_rdoc_files = [
|
|
17
|
-
"LICENSE.txt",
|
|
18
|
-
"README.md"
|
|
19
|
-
]
|
|
20
|
-
s.files = [
|
|
21
|
-
".document",
|
|
22
|
-
"Gemfile",
|
|
23
|
-
"Gemfile.lock",
|
|
24
|
-
"LICENSE.txt",
|
|
25
|
-
"README.md",
|
|
26
|
-
"Rakefile",
|
|
27
|
-
"cityhash.gemspec",
|
|
28
|
-
"ext/cityhash/city.cc",
|
|
29
|
-
"ext/cityhash/city.h",
|
|
30
|
-
"ext/cityhash/city_ruby_bridge.cpp",
|
|
31
|
-
"ext/cityhash/city_ruby_bridge.h",
|
|
32
|
-
"ext/cityhash/extconf.rb",
|
|
33
|
-
"lib/cityhash.rb",
|
|
34
|
-
"lib/cityhash/version.rb",
|
|
35
|
-
"test/helper.rb",
|
|
36
|
-
"test/test_cityhash.rb"
|
|
37
|
-
]
|
|
38
|
-
s.homepage = %q{http://github.com/nashby/cityhash}
|
|
39
|
-
s.licenses = [%q{MIT}]
|
|
40
|
-
s.require_paths = [%q{lib}]
|
|
41
|
-
s.rubygems_version = %q{1.8.6}
|
|
42
|
-
s.summary = %q{ffi wrapper for google's cityhash}
|
|
43
|
-
s.test_files = [
|
|
44
|
-
"test/helper.rb",
|
|
45
|
-
"test/test_cityhash.rb"
|
|
46
|
-
]
|
|
14
|
+
s.rubyforge_project = "cityhash"
|
|
47
15
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
|
54
|
-
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
55
|
-
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
|
56
|
-
s.add_development_dependency(%q<rcov>, [">= 0"])
|
|
57
|
-
s.add_runtime_dependency(%q<ffi>, [">= 0"])
|
|
58
|
-
else
|
|
59
|
-
s.add_dependency(%q<ffi>, [">= 0"])
|
|
60
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
61
|
-
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
62
|
-
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
|
63
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
|
64
|
-
s.add_dependency(%q<ffi>, [">= 0"])
|
|
65
|
-
end
|
|
66
|
-
else
|
|
67
|
-
s.add_dependency(%q<ffi>, [">= 0"])
|
|
68
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
|
69
|
-
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
|
70
|
-
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
|
71
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
|
72
|
-
s.add_dependency(%q<ffi>, [">= 0"])
|
|
73
|
-
end
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ["lib"]
|
|
20
|
+
s.extensions = ["ext/cityhash/extconf.rb"]
|
|
74
21
|
end
|
|
75
|
-
|
data/ext/cityhash/city.cc
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
19
|
// THE SOFTWARE.
|
|
20
20
|
//
|
|
21
|
-
// CityHash
|
|
21
|
+
// CityHash, by Geoff Pike and Jyrki Alakuijala
|
|
22
22
|
//
|
|
23
23
|
// This file provides CityHash64() and related functions.
|
|
24
24
|
//
|
|
@@ -30,20 +30,65 @@
|
|
|
30
30
|
#include "city.h"
|
|
31
31
|
|
|
32
32
|
#include <algorithm>
|
|
33
|
+
#include <string.h> // for memcpy and memset
|
|
33
34
|
|
|
34
35
|
using namespace std;
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
static uint64 UNALIGNED_LOAD64(const char *p) {
|
|
38
|
+
uint64 result;
|
|
39
|
+
memcpy(&result, p, sizeof(result));
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static uint32 UNALIGNED_LOAD32(const char *p) {
|
|
44
|
+
uint32 result;
|
|
45
|
+
memcpy(&result, p, sizeof(result));
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#if !defined(WORDS_BIGENDIAN)
|
|
50
|
+
|
|
51
|
+
#define uint32_in_expected_order(x) (x)
|
|
52
|
+
#define uint64_in_expected_order(x) (x)
|
|
53
|
+
|
|
54
|
+
#else
|
|
55
|
+
|
|
56
|
+
#ifdef _MSC_VER
|
|
57
|
+
#include <stdlib.h>
|
|
58
|
+
#define bswap_32(x) _byteswap_ulong(x)
|
|
59
|
+
#define bswap_64(x) _byteswap_uint64(x)
|
|
60
|
+
|
|
61
|
+
#elif defined(__APPLE__)
|
|
62
|
+
// Mac OS X / Darwin features
|
|
63
|
+
#include <libkern/OSByteOrder.h>
|
|
64
|
+
#define bswap_32(x) OSSwapInt32(x)
|
|
65
|
+
#define bswap_64(x) OSSwapInt64(x)
|
|
66
|
+
|
|
67
|
+
#else
|
|
68
|
+
#include <byteswap.h>
|
|
69
|
+
#endif
|
|
70
|
+
|
|
71
|
+
#define uint32_in_expected_order(x) (bswap_32(x))
|
|
72
|
+
#define uint64_in_expected_order(x) (bswap_64(x))
|
|
73
|
+
|
|
74
|
+
#endif // WORDS_BIGENDIAN
|
|
38
75
|
|
|
39
76
|
#if !defined(LIKELY)
|
|
40
|
-
#if
|
|
77
|
+
#if HAVE_BUILTIN_EXPECT
|
|
41
78
|
#define LIKELY(x) (__builtin_expect(!!(x), 1))
|
|
42
79
|
#else
|
|
43
80
|
#define LIKELY(x) (x)
|
|
44
81
|
#endif
|
|
45
82
|
#endif
|
|
46
83
|
|
|
84
|
+
static uint64 Fetch64(const char *p) {
|
|
85
|
+
return uint64_in_expected_order(UNALIGNED_LOAD64(p));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static uint32 Fetch32(const char *p) {
|
|
89
|
+
return uint32_in_expected_order(UNALIGNED_LOAD32(p));
|
|
90
|
+
}
|
|
91
|
+
|
|
47
92
|
// Some primes between 2^63 and 2^64 for various uses.
|
|
48
93
|
static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
|
|
49
94
|
static const uint64 k1 = 0xb492b66fbe98f273ULL;
|
|
@@ -74,13 +119,13 @@ static uint64 HashLen16(uint64 u, uint64 v) {
|
|
|
74
119
|
|
|
75
120
|
static uint64 HashLen0to16(const char *s, size_t len) {
|
|
76
121
|
if (len > 8) {
|
|
77
|
-
uint64 a =
|
|
78
|
-
uint64 b =
|
|
122
|
+
uint64 a = Fetch64(s);
|
|
123
|
+
uint64 b = Fetch64(s + len - 8);
|
|
79
124
|
return HashLen16(a, RotateByAtLeast1(b + len, len)) ^ b;
|
|
80
125
|
}
|
|
81
126
|
if (len >= 4) {
|
|
82
|
-
uint64 a =
|
|
83
|
-
return HashLen16(len + (a << 3),
|
|
127
|
+
uint64 a = Fetch32(s);
|
|
128
|
+
return HashLen16(len + (a << 3), Fetch32(s + len - 4));
|
|
84
129
|
}
|
|
85
130
|
if (len > 0) {
|
|
86
131
|
uint8 a = s[0];
|
|
@@ -96,10 +141,10 @@ static uint64 HashLen0to16(const char *s, size_t len) {
|
|
|
96
141
|
// This probably works well for 16-byte strings as well, but it may be overkill
|
|
97
142
|
// in that case.
|
|
98
143
|
static uint64 HashLen17to32(const char *s, size_t len) {
|
|
99
|
-
uint64 a =
|
|
100
|
-
uint64 b =
|
|
101
|
-
uint64 c =
|
|
102
|
-
uint64 d =
|
|
144
|
+
uint64 a = Fetch64(s) * k1;
|
|
145
|
+
uint64 b = Fetch64(s + 8);
|
|
146
|
+
uint64 c = Fetch64(s + len - 8) * k2;
|
|
147
|
+
uint64 d = Fetch64(s + len - 16) * k0;
|
|
103
148
|
return HashLen16(Rotate(a - b, 43) + Rotate(c, 30) + d,
|
|
104
149
|
a + Rotate(b ^ k3, 20) - c + len);
|
|
105
150
|
}
|
|
@@ -120,32 +165,32 @@ static pair<uint64, uint64> WeakHashLen32WithSeeds(
|
|
|
120
165
|
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
|
121
166
|
static pair<uint64, uint64> WeakHashLen32WithSeeds(
|
|
122
167
|
const char* s, uint64 a, uint64 b) {
|
|
123
|
-
return WeakHashLen32WithSeeds(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
168
|
+
return WeakHashLen32WithSeeds(Fetch64(s),
|
|
169
|
+
Fetch64(s + 8),
|
|
170
|
+
Fetch64(s + 16),
|
|
171
|
+
Fetch64(s + 24),
|
|
127
172
|
a,
|
|
128
173
|
b);
|
|
129
174
|
}
|
|
130
175
|
|
|
131
176
|
// Return an 8-byte hash for 33 to 64 bytes.
|
|
132
177
|
static uint64 HashLen33to64(const char *s, size_t len) {
|
|
133
|
-
uint64 z =
|
|
134
|
-
uint64 a =
|
|
178
|
+
uint64 z = Fetch64(s + 24);
|
|
179
|
+
uint64 a = Fetch64(s) + (len + Fetch64(s + len - 16)) * k0;
|
|
135
180
|
uint64 b = Rotate(a + z, 52);
|
|
136
181
|
uint64 c = Rotate(a, 37);
|
|
137
|
-
a +=
|
|
182
|
+
a += Fetch64(s + 8);
|
|
138
183
|
c += Rotate(a, 7);
|
|
139
|
-
a +=
|
|
184
|
+
a += Fetch64(s + 16);
|
|
140
185
|
uint64 vf = a + z;
|
|
141
186
|
uint64 vs = b + Rotate(a, 31) + c;
|
|
142
|
-
a =
|
|
143
|
-
z =
|
|
187
|
+
a = Fetch64(s + 16) + Fetch64(s + len - 32);
|
|
188
|
+
z = Fetch64(s + len - 8);
|
|
144
189
|
b = Rotate(a + z, 52);
|
|
145
190
|
c = Rotate(a, 37);
|
|
146
|
-
a +=
|
|
191
|
+
a += Fetch64(s + len - 24);
|
|
147
192
|
c += Rotate(a, 7);
|
|
148
|
-
a +=
|
|
193
|
+
a += Fetch64(s + len - 16);
|
|
149
194
|
uint64 wf = a + z;
|
|
150
195
|
uint64 ws = b + Rotate(a, 31) + c;
|
|
151
196
|
uint64 r = ShiftMix((vf + ws) * k2 + (wf + vs) * k0);
|
|
@@ -165,25 +210,23 @@ uint64 CityHash64(const char *s, size_t len) {
|
|
|
165
210
|
|
|
166
211
|
// For strings over 64 bytes we hash the end first, and then as we
|
|
167
212
|
// loop we keep 56 bytes of state: v, w, x, y, and z.
|
|
168
|
-
uint64 x =
|
|
169
|
-
uint64 y =
|
|
170
|
-
uint64 z =
|
|
171
|
-
pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len,
|
|
172
|
-
pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32,
|
|
173
|
-
|
|
174
|
-
x = Rotate(z + x, 39) * k1;
|
|
175
|
-
y = Rotate(y, 33) * k1;
|
|
213
|
+
uint64 x = Fetch64(s + len - 40);
|
|
214
|
+
uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
|
215
|
+
uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
|
216
|
+
pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
|
217
|
+
pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
|
218
|
+
x = x * k1 + Fetch64(s);
|
|
176
219
|
|
|
177
220
|
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
|
178
221
|
len = (len - 1) & ~static_cast<size_t>(63);
|
|
179
222
|
do {
|
|
180
|
-
x = Rotate(x + y + v.first +
|
|
181
|
-
y = Rotate(y + v.second +
|
|
223
|
+
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
|
|
224
|
+
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
|
|
182
225
|
x ^= w.second;
|
|
183
|
-
y
|
|
184
|
-
z = Rotate(z
|
|
226
|
+
y += v.first + Fetch64(s + 40);
|
|
227
|
+
z = Rotate(z + w.first, 33) * k1;
|
|
185
228
|
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
|
|
186
|
-
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y);
|
|
229
|
+
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
|
187
230
|
std::swap(z, x);
|
|
188
231
|
s += 64;
|
|
189
232
|
len -= 64;
|
|
@@ -202,25 +245,26 @@ uint64 CityHash64WithSeeds(const char *s, size_t len,
|
|
|
202
245
|
}
|
|
203
246
|
|
|
204
247
|
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
|
|
205
|
-
// of any length representable in
|
|
248
|
+
// of any length representable in signed long. Based on City and Murmur.
|
|
206
249
|
static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
|
|
207
250
|
uint64 a = Uint128Low64(seed);
|
|
208
251
|
uint64 b = Uint128High64(seed);
|
|
209
252
|
uint64 c = 0;
|
|
210
253
|
uint64 d = 0;
|
|
211
|
-
|
|
254
|
+
signed long l = len - 16;
|
|
212
255
|
if (l <= 0) { // len <= 16
|
|
256
|
+
a = ShiftMix(a * k1) * k1;
|
|
213
257
|
c = b * k1 + HashLen0to16(s, len);
|
|
214
|
-
d =
|
|
258
|
+
d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
|
|
215
259
|
} else { // len > 16
|
|
216
|
-
c = HashLen16(
|
|
217
|
-
d = HashLen16(b + len, c +
|
|
260
|
+
c = HashLen16(Fetch64(s + len - 8) + k1, a);
|
|
261
|
+
d = HashLen16(b + len, c + Fetch64(s + len - 16));
|
|
218
262
|
a += d;
|
|
219
263
|
do {
|
|
220
|
-
a ^= ShiftMix(
|
|
264
|
+
a ^= ShiftMix(Fetch64(s) * k1) * k1;
|
|
221
265
|
a *= k1;
|
|
222
266
|
b ^= a;
|
|
223
|
-
c ^= ShiftMix(
|
|
267
|
+
c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
|
|
224
268
|
c *= k1;
|
|
225
269
|
d ^= c;
|
|
226
270
|
s += 16;
|
|
@@ -243,49 +287,50 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
|
|
|
243
287
|
uint64 x = Uint128Low64(seed);
|
|
244
288
|
uint64 y = Uint128High64(seed);
|
|
245
289
|
uint64 z = len * k1;
|
|
246
|
-
v.first = Rotate(y ^ k1, 49) * k1 +
|
|
247
|
-
v.second = Rotate(v.first, 42) * k1 +
|
|
290
|
+
v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
|
|
291
|
+
v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
|
|
248
292
|
w.first = Rotate(y + z, 35) * k1 + x;
|
|
249
|
-
w.second = Rotate(x +
|
|
293
|
+
w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
|
|
250
294
|
|
|
251
295
|
// This is the same inner loop as CityHash64(), manually unrolled.
|
|
252
296
|
do {
|
|
253
|
-
x = Rotate(x + y + v.first +
|
|
254
|
-
y = Rotate(y + v.second +
|
|
297
|
+
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
|
|
298
|
+
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
|
|
255
299
|
x ^= w.second;
|
|
256
|
-
y
|
|
257
|
-
z = Rotate(z
|
|
300
|
+
y += v.first + Fetch64(s + 40);
|
|
301
|
+
z = Rotate(z + w.first, 33) * k1;
|
|
258
302
|
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
|
|
259
|
-
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y);
|
|
303
|
+
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
|
260
304
|
std::swap(z, x);
|
|
261
305
|
s += 64;
|
|
262
|
-
x = Rotate(x + y + v.first +
|
|
263
|
-
y = Rotate(y + v.second +
|
|
306
|
+
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
|
|
307
|
+
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
|
|
264
308
|
x ^= w.second;
|
|
265
|
-
y
|
|
266
|
-
z = Rotate(z
|
|
309
|
+
y += v.first + Fetch64(s + 40);
|
|
310
|
+
z = Rotate(z + w.first, 33) * k1;
|
|
267
311
|
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
|
|
268
|
-
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y);
|
|
312
|
+
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
|
269
313
|
std::swap(z, x);
|
|
270
314
|
s += 64;
|
|
271
315
|
len -= 128;
|
|
272
316
|
} while (LIKELY(len >= 128));
|
|
273
|
-
y += Rotate(w.first, 37) * k0 + z;
|
|
274
317
|
x += Rotate(v.first + z, 49) * k0;
|
|
318
|
+
z += Rotate(w.first, 37) * k0;
|
|
275
319
|
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
|
|
276
320
|
for (size_t tail_done = 0; tail_done < len; ) {
|
|
277
321
|
tail_done += 32;
|
|
278
|
-
y = Rotate(
|
|
279
|
-
w.first +=
|
|
280
|
-
x =
|
|
281
|
-
w.
|
|
282
|
-
|
|
322
|
+
y = Rotate(x + y, 42) * k0 + v.second;
|
|
323
|
+
w.first += Fetch64(s + len - tail_done + 16);
|
|
324
|
+
x = x * k0 + w.first;
|
|
325
|
+
z += w.second + Fetch64(s + len - tail_done);
|
|
326
|
+
w.second += v.first;
|
|
327
|
+
v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
|
|
283
328
|
}
|
|
284
|
-
// At this point our
|
|
329
|
+
// At this point our 56 bytes of state should contain more than
|
|
285
330
|
// enough information for a strong 128-bit hash. We use two
|
|
286
|
-
// different
|
|
331
|
+
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
|
|
287
332
|
x = HashLen16(x, v.first);
|
|
288
|
-
y = HashLen16(y, w.first);
|
|
333
|
+
y = HashLen16(y + z, w.first);
|
|
289
334
|
return uint128(HashLen16(x + v.second, w.second) + y,
|
|
290
335
|
HashLen16(x + w.second, y + v.second));
|
|
291
336
|
}
|
|
@@ -294,14 +339,128 @@ uint128 CityHash128(const char *s, size_t len) {
|
|
|
294
339
|
if (len >= 16) {
|
|
295
340
|
return CityHash128WithSeed(s + 16,
|
|
296
341
|
len - 16,
|
|
297
|
-
uint128(
|
|
298
|
-
|
|
342
|
+
uint128(Fetch64(s) ^ k3,
|
|
343
|
+
Fetch64(s + 8)));
|
|
299
344
|
} else if (len >= 8) {
|
|
300
345
|
return CityHash128WithSeed(NULL,
|
|
301
346
|
0,
|
|
302
|
-
uint128(
|
|
303
|
-
|
|
347
|
+
uint128(Fetch64(s) ^ (len * k0),
|
|
348
|
+
Fetch64(s + len - 8) ^ k1));
|
|
304
349
|
} else {
|
|
305
350
|
return CityHash128WithSeed(s, len, uint128(k0, k1));
|
|
306
351
|
}
|
|
307
352
|
}
|
|
353
|
+
|
|
354
|
+
#ifdef __SSE4_2__
|
|
355
|
+
#include <citycrc.h>
|
|
356
|
+
#include <nmmintrin.h>
|
|
357
|
+
|
|
358
|
+
// Requires len >= 240.
|
|
359
|
+
static void CityHashCrc256Long(const char *s, size_t len,
|
|
360
|
+
uint32 seed, uint64 *result) {
|
|
361
|
+
uint64 a = Fetch64(s + 56) + k0;
|
|
362
|
+
uint64 b = Fetch64(s + 96) + k0;
|
|
363
|
+
uint64 c = result[0] = HashLen16(b, len);
|
|
364
|
+
uint64 d = result[1] = Fetch64(s + 120) * k0 + len;
|
|
365
|
+
uint64 e = Fetch64(s + 184) + seed;
|
|
366
|
+
uint64 f = seed;
|
|
367
|
+
uint64 g = 0;
|
|
368
|
+
uint64 h = 0;
|
|
369
|
+
uint64 i = 0;
|
|
370
|
+
uint64 j = 0;
|
|
371
|
+
uint64 t = c + d;
|
|
372
|
+
|
|
373
|
+
// 240 bytes of input per iter.
|
|
374
|
+
size_t iters = len / 240;
|
|
375
|
+
len -= iters * 240;
|
|
376
|
+
do {
|
|
377
|
+
#define CHUNK(multiplier, z) \
|
|
378
|
+
{ \
|
|
379
|
+
uint64 old_a = a; \
|
|
380
|
+
a = Rotate(b, 41 ^ z) * multiplier + Fetch64(s); \
|
|
381
|
+
b = Rotate(c, 27 ^ z) * multiplier + Fetch64(s + 8); \
|
|
382
|
+
c = Rotate(d, 41 ^ z) * multiplier + Fetch64(s + 16); \
|
|
383
|
+
d = Rotate(e, 33 ^ z) * multiplier + Fetch64(s + 24); \
|
|
384
|
+
e = Rotate(t, 25 ^ z) * multiplier + Fetch64(s + 32); \
|
|
385
|
+
t = old_a; \
|
|
386
|
+
} \
|
|
387
|
+
f = _mm_crc32_u64(f, a); \
|
|
388
|
+
g = _mm_crc32_u64(g, b); \
|
|
389
|
+
h = _mm_crc32_u64(h, c); \
|
|
390
|
+
i = _mm_crc32_u64(i, d); \
|
|
391
|
+
j = _mm_crc32_u64(j, e); \
|
|
392
|
+
s += 40
|
|
393
|
+
|
|
394
|
+
CHUNK(1, 1); CHUNK(k0, 0);
|
|
395
|
+
CHUNK(1, 1); CHUNK(k0, 0);
|
|
396
|
+
CHUNK(1, 1); CHUNK(k0, 0);
|
|
397
|
+
} while (--iters > 0);
|
|
398
|
+
|
|
399
|
+
while (len >= 40) {
|
|
400
|
+
CHUNK(k0, 0);
|
|
401
|
+
len -= 40;
|
|
402
|
+
}
|
|
403
|
+
if (len > 0) {
|
|
404
|
+
s = s + len - 40;
|
|
405
|
+
CHUNK(k0, 0);
|
|
406
|
+
}
|
|
407
|
+
j += i << 32;
|
|
408
|
+
a = HashLen16(a, j);
|
|
409
|
+
h += g << 32;
|
|
410
|
+
b += h;
|
|
411
|
+
c = HashLen16(c, f) + i;
|
|
412
|
+
d = HashLen16(d, e + result[0]);
|
|
413
|
+
j += e;
|
|
414
|
+
i += HashLen16(h, t);
|
|
415
|
+
e = HashLen16(a, d) + j;
|
|
416
|
+
f = HashLen16(b, c) + a;
|
|
417
|
+
g = HashLen16(j, i) + c;
|
|
418
|
+
result[0] = e + f + g + h;
|
|
419
|
+
a = ShiftMix((a + g) * k0) * k0 + b;
|
|
420
|
+
result[1] += a + result[0];
|
|
421
|
+
a = ShiftMix(a * k0) * k0 + c;
|
|
422
|
+
result[2] = a + result[1];
|
|
423
|
+
a = ShiftMix((a + e) * k0) * k0;
|
|
424
|
+
result[3] = a + result[2];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Requires len < 240.
|
|
428
|
+
static void CityHashCrc256Short(const char *s, size_t len, uint64 *result) {
|
|
429
|
+
char buf[240];
|
|
430
|
+
memcpy(buf, s, len);
|
|
431
|
+
memset(buf + len, 0, 240 - len);
|
|
432
|
+
CityHashCrc256Long(buf, 240, ~static_cast<uint32>(len), result);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
void CityHashCrc256(const char *s, size_t len, uint64 *result) {
|
|
436
|
+
if (LIKELY(len >= 240)) {
|
|
437
|
+
CityHashCrc256Long(s, len, 0, result);
|
|
438
|
+
} else {
|
|
439
|
+
CityHashCrc256Short(s, len, result);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) {
|
|
444
|
+
if (len <= 900) {
|
|
445
|
+
return CityHash128WithSeed(s, len, seed);
|
|
446
|
+
} else {
|
|
447
|
+
uint64 result[4];
|
|
448
|
+
CityHashCrc256(s, len, result);
|
|
449
|
+
uint64 u = Uint128High64(seed) + result[0];
|
|
450
|
+
uint64 v = Uint128Low64(seed) + result[1];
|
|
451
|
+
return uint128(HashLen16(u, v + result[2]),
|
|
452
|
+
HashLen16(Rotate(v, 32), u * k0 + result[3]));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
uint128 CityHashCrc128(const char *s, size_t len) {
|
|
457
|
+
if (len <= 900) {
|
|
458
|
+
return CityHash128(s, len);
|
|
459
|
+
} else {
|
|
460
|
+
uint64 result[4];
|
|
461
|
+
CityHashCrc256(s, len, result);
|
|
462
|
+
return uint128(result[2], result[3]);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
#endif
|
data/ext/cityhash/city.h
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
19
|
// THE SOFTWARE.
|
|
20
20
|
//
|
|
21
|
-
// CityHash
|
|
21
|
+
// CityHash, by Geoff Pike and Jyrki Alakuijala
|
|
22
22
|
//
|
|
23
23
|
// This file provides a few functions for hashing strings. On x86-64
|
|
24
24
|
// hardware in 2011, CityHash64() is faster than other high-quality
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include "city.h"
|
|
3
|
+
|
|
4
|
+
// Use this typedef to make the compiler happy when
|
|
5
|
+
// calling rb_define_method()
|
|
6
|
+
typedef VALUE (ruby_method)(...);
|
|
7
|
+
|
|
8
|
+
extern "C" VALUE cityhash_hash64(VALUE mod, VALUE input)
|
|
9
|
+
{
|
|
10
|
+
return ULL2NUM(CityHash64(StringValuePtr(input), RSTRING_LEN(input)));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
extern "C" VALUE cityhash_hash64_with_seed(VALUE mod, VALUE input, VALUE seed)
|
|
14
|
+
{
|
|
15
|
+
return ULL2NUM(CityHash64WithSeed(StringValuePtr(input), RSTRING_LEN(input), NUM2ULL(seed)));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
extern "C" VALUE cityhash_hash64_with_seeds(VALUE mod, VALUE input, VALUE seed1, VALUE seed2)
|
|
19
|
+
{
|
|
20
|
+
return ULL2NUM(CityHash64WithSeeds(StringValuePtr(input), RSTRING_LEN(input), NUM2ULL(seed1), NUM2ULL(seed2)));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
extern "C" VALUE cityhash_hash128(VALUE mod, VALUE input)
|
|
24
|
+
{
|
|
25
|
+
uint128 hash = CityHash128(StringValuePtr(input), RSTRING_LEN(input));
|
|
26
|
+
return rb_str_new((char *)&hash, sizeof(hash));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
extern "C" VALUE cityhash_hash128_with_seed(VALUE mod, VALUE input, VALUE seed_string)
|
|
30
|
+
{
|
|
31
|
+
uint128 seed = *(uint128 *)StringValuePtr(seed_string);
|
|
32
|
+
uint128 hash = CityHash128WithSeed(StringValuePtr(input), RSTRING_LEN(input), seed);
|
|
33
|
+
return rb_str_new((char *)&hash, sizeof(hash));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
extern "C" void Init_cityhash()
|
|
37
|
+
{
|
|
38
|
+
VALUE mCityHash = rb_define_module("CityHash");
|
|
39
|
+
VALUE mInternal = rb_define_module_under(mCityHash, "Internal");
|
|
40
|
+
|
|
41
|
+
rb_define_singleton_method(mInternal, "hash64", (ruby_method*) &cityhash_hash64, 1);
|
|
42
|
+
rb_define_singleton_method(mInternal, "hash64_with_seed", (ruby_method*) &cityhash_hash64_with_seed, 2);
|
|
43
|
+
rb_define_singleton_method(mInternal, "hash64_with_seeds", (ruby_method*) &cityhash_hash64_with_seeds, 3);
|
|
44
|
+
|
|
45
|
+
rb_define_singleton_method(mInternal, "hash128", (ruby_method*) &cityhash_hash128, 1);
|
|
46
|
+
rb_define_singleton_method(mInternal, "hash128_with_seed", (ruby_method*) &cityhash_hash128_with_seed, 2);
|
|
47
|
+
}
|
data/ext/cityhash/extconf.rb
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
require 'mkmf'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
%w{g O3 Wall rdynamic}.each do |flag|
|
|
3
|
+
%w{g O3 Wall}.each do |flag|
|
|
6
4
|
flag = "-#{flag}"
|
|
7
5
|
$CPPFLAGS += " #{flag}" unless $CPPFLAGS.split.include? flag
|
|
8
6
|
end
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
create_makefile('cityhash')
|
|
8
|
+
create_makefile('cityhash/cityhash')
|
data/lib/cityhash.rb
CHANGED
|
@@ -1,63 +1,23 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'cityhash/version'
|
|
2
|
+
require 'cityhash/cityhash'
|
|
2
3
|
|
|
3
4
|
module CityHash
|
|
4
|
-
|
|
5
5
|
LOW64_MASK = 0x0000000000000000ffffffffffffffff
|
|
6
6
|
HIGH64_MASK = 0xffffffffffffffff0000000000000000
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
case RUBY_PLATFORM
|
|
13
|
-
when /darwin/
|
|
14
|
-
File.join(File.dirname(__FILE__), '..', 'ext', 'cityhash', 'cityhash.bundle')
|
|
15
|
-
when /mingw|mswin|linux/
|
|
16
|
-
File.join(File.dirname(__FILE__), '..', 'ext', 'cityhash', 'cityhash.so')
|
|
17
|
-
else
|
|
18
|
-
File.join(File.dirname(__FILE__), '..', 'ext', 'cityhash', "cityhash.#{RbConfig::CONFIG['DLEXT']}")
|
|
19
|
-
end
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
attach_function :city_hash64, :CityHash64, [:string, :size_t], :uint64
|
|
23
|
-
attach_function :city_hash64_with_seed, :CityHash64WithSeed, [:string, :size_t, :uint64], :uint64
|
|
24
|
-
attach_function :city_hash64_with_seeds, :CityHash64WithSeeds, [:string, :size_t, :uint64, :uint64], :uint64
|
|
25
|
-
attach_function :city_hash128, :CityHash128String, [:string, :size_t], :string
|
|
26
|
-
attach_function :city_hash128_with_seed, :CityHash128WithSeedString, [:string, :size_t, :uint64, :uint64], :string
|
|
8
|
+
def self.hash64(input, seed1=nil, seed2=nil)
|
|
9
|
+
return Internal.hash64(input) if seed1.nil?
|
|
10
|
+
return Internal.hash64_with_seed(input, seed1.to_i) if seed2.nil?
|
|
11
|
+
Internal.hash64_with_seeds(input, seed1.to_i, seed2.to_i)
|
|
27
12
|
end
|
|
28
13
|
|
|
29
|
-
def self.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if input_str.respond_to?(:bytesize)
|
|
34
|
-
len = input_str.bytesize
|
|
14
|
+
def self.hash128(input, seed=nil)
|
|
15
|
+
if seed
|
|
16
|
+
seed = [seed & LOW64_MASK, seed & HIGH64_MASK >> 64].pack('QQ')
|
|
17
|
+
digest = Internal.hash128_with_seed(input, seed)
|
|
35
18
|
else
|
|
36
|
-
|
|
19
|
+
digest = Internal.hash128(input)
|
|
37
20
|
end
|
|
38
|
-
|
|
39
|
-
return CityHash::Internal.city_hash64(input_str, len) if seed1.nil?
|
|
40
|
-
return CityHash::Internal.city_hash64_with_seed(input_str, len, seed1.to_i & LOW64_MASK) if seed2.nil?
|
|
41
|
-
|
|
42
|
-
CityHash::Internal.city_hash64_with_seeds(input_str, len, seed1.to_i & LOW64_MASK, seed2.to_i & LOW64_MASK)
|
|
21
|
+
[0..7, 8..15].map { |r| digest[r].unpack('Q').first.to_s }.join.to_i
|
|
43
22
|
end
|
|
44
|
-
|
|
45
|
-
def self.hash128(input, seed = nil)
|
|
46
|
-
input_str = input.to_s
|
|
47
|
-
|
|
48
|
-
# Ruby 1.8 compatibility
|
|
49
|
-
if input_str.respond_to?(:bytesize)
|
|
50
|
-
len = input_str.bytesize
|
|
51
|
-
else
|
|
52
|
-
len = input_str.size
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
return CityHash::Internal.city_hash128(input_str, len).to_i if seed.nil?
|
|
56
|
-
|
|
57
|
-
seed_low = seed.to_i & LOW64_MASK
|
|
58
|
-
seed_high = (seed.to_i & HIGH64_MASK) >> 64
|
|
59
|
-
|
|
60
|
-
CityHash::Internal.city_hash128_with_seed(input_str, len, seed_low, seed_high).to_i
|
|
61
|
-
end
|
|
62
|
-
|
|
63
23
|
end
|
data/lib/cityhash/version.rb
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
describe CityHash do
|
|
4
|
+
it 'returns 64bit hash' do
|
|
5
|
+
assert_equal 17703940110308125106, CityHash.hash64("test")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "returns 64bit hash with a seed" do
|
|
9
|
+
assert_equal 14900027982776226655, CityHash.hash64("test", 12345)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "returns 64bit hash with seeds" do
|
|
13
|
+
assert_equal 11136353178704814373, CityHash.hash64("test", 12345, 54321)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "returns 128bit hash" do
|
|
17
|
+
assert_equal 1800071687761605184910580728449884026697, CityHash.hash128("test")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "returns 128bit hash with seed" do
|
|
21
|
+
seed = (123 << 64) | 123
|
|
22
|
+
assert_equal 1631427474705635869517741677842296176559, CityHash.hash128("test", seed)
|
|
23
|
+
end
|
|
24
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
|
@@ -1,110 +1,41 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cityhash
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
|
-
-
|
|
8
|
+
- Vasiliy Ermolovich
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
13
|
-
dependencies:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
none: false
|
|
18
|
-
requirements:
|
|
19
|
-
- - ! '>='
|
|
20
|
-
- !ruby/object:Gem::Version
|
|
21
|
-
version: '0'
|
|
22
|
-
type: :runtime
|
|
23
|
-
prerelease: false
|
|
24
|
-
version_requirements: *24780520
|
|
25
|
-
- !ruby/object:Gem::Dependency
|
|
26
|
-
name: shoulda
|
|
27
|
-
requirement: &24779860 !ruby/object:Gem::Requirement
|
|
28
|
-
none: false
|
|
29
|
-
requirements:
|
|
30
|
-
- - ! '>='
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0'
|
|
33
|
-
type: :development
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: *24779860
|
|
36
|
-
- !ruby/object:Gem::Dependency
|
|
37
|
-
name: bundler
|
|
38
|
-
requirement: &24779220 !ruby/object:Gem::Requirement
|
|
39
|
-
none: false
|
|
40
|
-
requirements:
|
|
41
|
-
- - ~>
|
|
42
|
-
- !ruby/object:Gem::Version
|
|
43
|
-
version: 1.0.0
|
|
44
|
-
type: :development
|
|
45
|
-
prerelease: false
|
|
46
|
-
version_requirements: *24779220
|
|
47
|
-
- !ruby/object:Gem::Dependency
|
|
48
|
-
name: jeweler
|
|
49
|
-
requirement: &24778500 !ruby/object:Gem::Requirement
|
|
50
|
-
none: false
|
|
51
|
-
requirements:
|
|
52
|
-
- - ~>
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: 1.5.2
|
|
55
|
-
type: :development
|
|
56
|
-
prerelease: false
|
|
57
|
-
version_requirements: *24778500
|
|
58
|
-
- !ruby/object:Gem::Dependency
|
|
59
|
-
name: rcov
|
|
60
|
-
requirement: &24777780 !ruby/object:Gem::Requirement
|
|
61
|
-
none: false
|
|
62
|
-
requirements:
|
|
63
|
-
- - ! '>='
|
|
64
|
-
- !ruby/object:Gem::Version
|
|
65
|
-
version: '0'
|
|
66
|
-
type: :development
|
|
67
|
-
prerelease: false
|
|
68
|
-
version_requirements: *24777780
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: ffi
|
|
71
|
-
requirement: &24776560 !ruby/object:Gem::Requirement
|
|
72
|
-
none: false
|
|
73
|
-
requirements:
|
|
74
|
-
- - ! '>='
|
|
75
|
-
- !ruby/object:Gem::Version
|
|
76
|
-
version: '0'
|
|
77
|
-
type: :runtime
|
|
78
|
-
prerelease: false
|
|
79
|
-
version_requirements: *24776560
|
|
80
|
-
description: ffi wrapper for google's cityhash
|
|
81
|
-
email: younash@gmail.com
|
|
12
|
+
date: 2012-04-07 00:00:00.000000000Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: ruby bindings for google's cityhash
|
|
15
|
+
email:
|
|
16
|
+
- younash@gmail.com
|
|
82
17
|
executables: []
|
|
83
18
|
extensions:
|
|
84
19
|
- ext/cityhash/extconf.rb
|
|
85
|
-
extra_rdoc_files:
|
|
86
|
-
- LICENSE.txt
|
|
87
|
-
- README.md
|
|
20
|
+
extra_rdoc_files: []
|
|
88
21
|
files:
|
|
89
|
-
- .
|
|
22
|
+
- .gitignore
|
|
23
|
+
- .travis.yml
|
|
90
24
|
- Gemfile
|
|
91
|
-
- Gemfile.lock
|
|
92
25
|
- LICENSE.txt
|
|
93
26
|
- README.md
|
|
94
27
|
- Rakefile
|
|
95
28
|
- cityhash.gemspec
|
|
96
29
|
- ext/cityhash/city.cc
|
|
97
30
|
- ext/cityhash/city.h
|
|
98
|
-
- ext/cityhash/
|
|
99
|
-
- ext/cityhash/city_ruby_bridge.h
|
|
31
|
+
- ext/cityhash/cityhash.cc
|
|
100
32
|
- ext/cityhash/extconf.rb
|
|
101
33
|
- lib/cityhash.rb
|
|
102
34
|
- lib/cityhash/version.rb
|
|
103
|
-
- test/
|
|
104
|
-
- test/
|
|
35
|
+
- test/cityhash_test.rb
|
|
36
|
+
- test/test_helper.rb
|
|
105
37
|
homepage: http://github.com/nashby/cityhash
|
|
106
|
-
licenses:
|
|
107
|
-
- MIT
|
|
38
|
+
licenses: []
|
|
108
39
|
post_install_message:
|
|
109
40
|
rdoc_options: []
|
|
110
41
|
require_paths:
|
|
@@ -117,19 +48,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
117
48
|
version: '0'
|
|
118
49
|
segments:
|
|
119
50
|
- 0
|
|
120
|
-
hash:
|
|
51
|
+
hash: 268501841747995875
|
|
121
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
53
|
none: false
|
|
123
54
|
requirements:
|
|
124
55
|
- - ! '>='
|
|
125
56
|
- !ruby/object:Gem::Version
|
|
126
57
|
version: '0'
|
|
58
|
+
segments:
|
|
59
|
+
- 0
|
|
60
|
+
hash: 268501841747995875
|
|
127
61
|
requirements: []
|
|
128
|
-
rubyforge_project:
|
|
129
|
-
rubygems_version: 1.8.
|
|
62
|
+
rubyforge_project: cityhash
|
|
63
|
+
rubygems_version: 1.8.19
|
|
130
64
|
signing_key:
|
|
131
65
|
specification_version: 3
|
|
132
|
-
summary:
|
|
133
|
-
test_files:
|
|
134
|
-
- test/helper.rb
|
|
135
|
-
- test/test_cityhash.rb
|
|
66
|
+
summary: ruby bindings for google's cityhash
|
|
67
|
+
test_files: []
|
data/.document
DELETED
data/Gemfile.lock
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
GEM
|
|
2
|
-
remote: http://rubygems.org/
|
|
3
|
-
specs:
|
|
4
|
-
ffi (1.0.7)
|
|
5
|
-
rake (>= 0.8.7)
|
|
6
|
-
git (1.2.5)
|
|
7
|
-
jeweler (1.5.2)
|
|
8
|
-
bundler (~> 1.0.0)
|
|
9
|
-
git (>= 1.2.5)
|
|
10
|
-
rake
|
|
11
|
-
rake (0.8.7)
|
|
12
|
-
rcov (0.9.9)
|
|
13
|
-
shoulda (2.11.3)
|
|
14
|
-
|
|
15
|
-
PLATFORMS
|
|
16
|
-
ruby
|
|
17
|
-
|
|
18
|
-
DEPENDENCIES
|
|
19
|
-
bundler (~> 1.0.0)
|
|
20
|
-
ffi
|
|
21
|
-
jeweler (~> 1.5.2)
|
|
22
|
-
rcov
|
|
23
|
-
shoulda
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#include "city_ruby_bridge.h"
|
|
2
|
-
#include <sstream>
|
|
3
|
-
|
|
4
|
-
const char* CityHash128String(const char *s, size_t len)
|
|
5
|
-
{
|
|
6
|
-
std::ostringstream str;
|
|
7
|
-
str << Uint128Low64(CityHash128(s, len)) << Uint128High64(CityHash128(s, len));
|
|
8
|
-
|
|
9
|
-
return str.str().c_str();
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const char* CityHash128WithSeedString(const char *s, size_t len, uint64 seed1, uint64 seed2)
|
|
13
|
-
{
|
|
14
|
-
uint128 seed(seed1, seed2);
|
|
15
|
-
std::ostringstream str;
|
|
16
|
-
str << Uint128Low64(CityHash128WithSeed(s, len, seed)) << Uint128High64(CityHash128WithSeed(s, len, seed));
|
|
17
|
-
|
|
18
|
-
return str.str().c_str();
|
|
19
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
#include "city.h"
|
|
2
|
-
|
|
3
|
-
typedef uint64_t uint64;
|
|
4
|
-
typedef std::pair<uint64, uint64> uint128;
|
|
5
|
-
|
|
6
|
-
extern "C" const char* CityHash128String(const char *s, size_t len);
|
|
7
|
-
|
|
8
|
-
extern "C" const char* CityHash128WithSeedString(const char *s, size_t len, uint64 seed1, uint64 seed2);
|
data/test/helper.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require 'rubygems'
|
|
2
|
-
require 'bundler'
|
|
3
|
-
begin
|
|
4
|
-
Bundler.setup(:default, :development)
|
|
5
|
-
rescue Bundler::BundlerError => e
|
|
6
|
-
$stderr.puts e.message
|
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
|
8
|
-
exit e.status_code
|
|
9
|
-
end
|
|
10
|
-
require 'test/unit'
|
|
11
|
-
require 'shoulda'
|
|
12
|
-
|
|
13
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
14
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
15
|
-
require 'cityhash'
|
|
16
|
-
|
|
17
|
-
class Test::Unit::TestCase
|
|
18
|
-
end
|
data/test/test_cityhash.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
require 'helper'
|
|
2
|
-
|
|
3
|
-
class TestCityhash < Test::Unit::TestCase
|
|
4
|
-
|
|
5
|
-
should "return 64bit hash" do
|
|
6
|
-
assert_equal 17703940110308125106, CityHash.hash64("test")
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
should "return 64bit hash with a seed" do
|
|
10
|
-
assert_equal 14900027982776226655, CityHash.hash64("test", 12345)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
should "return 64bit hash with seeds" do
|
|
14
|
-
assert_equal 11136353178704814373, CityHash.hash64("test", 12345, 54321)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
should "return 128bit hash" do
|
|
18
|
-
assert_equal 130554790001792308794529643941127319555, CityHash.hash128("test")
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
should "return 128bit hash with seed" do
|
|
22
|
-
seed = (123 << 64) | 123
|
|
23
|
-
assert_equal 183946415266487905135364192266033899899, CityHash.hash128("test", seed)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
end
|