Permalink
Browse files

ruby extension instead of using ffi

  • Loading branch information...
1 parent 2b1d37a commit 3117801bbb4f83225516db14c6714818dcba13d9 @lest lest committed Feb 1, 2012
Showing with 60 additions and 72 deletions.
  1. +0 −4 cityhash.gemspec
  2. +0 −19 ext/cityhash/city_ruby_bridge.cpp
  3. +0 −8 ext/cityhash/city_ruby_bridge.h
  4. +47 −0 ext/cityhash/cityhash.cc
  5. +13 −41 lib/cityhash.rb
View
@@ -18,8 +18,4 @@ Gem::Specification.new do |s|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
s.extensions = ["ext/cityhash/extconf.rb"]
-
- # specify any dependencies here; for example:
- # s.add_development_dependency "rspec"
- s.add_runtime_dependency "ffi"
end
@@ -1,19 +0,0 @@
-#include "city_ruby_bridge.h"
-#include <sstream>
-
-const char* CityHash128String(const char *s, size_t len)
-{
- std::ostringstream str;
- str << Uint128Low64(CityHash128(s, len)) << Uint128High64(CityHash128(s, len));
-
- return str.str().c_str();
-}
-
-const char* CityHash128WithSeedString(const char *s, size_t len, uint64 seed1, uint64 seed2)
-{
- uint128 seed(seed1, seed2);
- std::ostringstream str;
- str << Uint128Low64(CityHash128WithSeed(s, len, seed)) << Uint128High64(CityHash128WithSeed(s, len, seed));
-
- return str.str().c_str();
-}
@@ -1,8 +0,0 @@
-#include "city.h"
-
-typedef uint64_t uint64;
-typedef std::pair<uint64, uint64> uint128;
-
-extern "C" const char* CityHash128String(const char *s, size_t len);
-
-extern "C" const char* CityHash128WithSeedString(const char *s, size_t len, uint64 seed1, uint64 seed2);
View
@@ -0,0 +1,47 @@
+#include <ruby.h>
+#include "city.h"
+
+// Use this typedef to make the compiler happy when
+// calling rb_define_method()
+typedef VALUE (ruby_method)(...);
+
+extern "C" VALUE cityhash_hash64(VALUE mod, VALUE input)
+{
+ return ULL2NUM(CityHash64(StringValuePtr(input), RSTRING_LEN(input)));
+}
+
+extern "C" VALUE cityhash_hash64_with_seed(VALUE mod, VALUE input, VALUE seed)
+{
+ return ULL2NUM(CityHash64WithSeed(StringValuePtr(input), RSTRING_LEN(input), NUM2ULL(seed)));
+}
+
+extern "C" VALUE cityhash_hash64_with_seeds(VALUE mod, VALUE input, VALUE seed1, VALUE seed2)
+{
+ return ULL2NUM(CityHash64WithSeeds(StringValuePtr(input), RSTRING_LEN(input), NUM2ULL(seed1), NUM2ULL(seed2)));
+}
+
+extern "C" VALUE cityhash_hash128(VALUE mod, VALUE input)
+{
+ uint128 hash = CityHash128(StringValuePtr(input), RSTRING_LEN(input));
+ return rb_str_new((char *)&hash, sizeof(hash));
+}
+
+extern "C" VALUE cityhash_hash128_with_seed(VALUE mod, VALUE input, VALUE seed_string)
+{
+ uint128 seed = *(uint128 *)StringValuePtr(seed_string);
+ uint128 hash = CityHash128WithSeed(StringValuePtr(input), RSTRING_LEN(input), seed);
+ return rb_str_new((char *)&hash, sizeof(hash));
+}
+
+extern "C" void Init_cityhash()
+{
+ VALUE mCityHash = rb_define_module("CityHash");
+ VALUE mInternal = rb_define_module_under(mCityHash, "Internal");
+
+ rb_define_singleton_method(mInternal, "hash64", (ruby_method*) &cityhash_hash64, 1);
+ rb_define_singleton_method(mInternal, "hash64_with_seed", (ruby_method*) &cityhash_hash64_with_seed, 2);
+ rb_define_singleton_method(mInternal, "hash64_with_seeds", (ruby_method*) &cityhash_hash64_with_seeds, 3);
+
+ rb_define_singleton_method(mInternal, "hash128", (ruby_method*) &cityhash_hash128, 1);
+ rb_define_singleton_method(mInternal, "hash128_with_seed", (ruby_method*) &cityhash_hash128_with_seed, 2);
+}
View
@@ -1,51 +1,23 @@
-require 'ffi'
require 'cityhash/version'
+require 'cityhash/cityhash'
module CityHash
-
LOW64_MASK = 0x0000000000000000ffffffffffffffff
HIGH64_MASK = 0xffffffffffffffff0000000000000000
- module Internal
- extend FFI::Library
-
- ffi_lib(
- case RUBY_PLATFORM
- when /darwin/
- File.join(File.dirname(__FILE__), '..', 'ext', 'cityhash', 'cityhash.bundle')
- when /mingw|mswin|linux/
- File.join(File.dirname(__FILE__), '..', 'ext', 'cityhash', 'cityhash.so')
- else
- File.join(File.dirname(__FILE__), '..', 'ext', 'cityhash', "cityhash.#{RbConfig::CONFIG['DLEXT']}")
- end
- )
-
- attach_function :city_hash64, :CityHash64, [:string, :size_t], :uint64
- attach_function :city_hash64_with_seed, :CityHash64WithSeed, [:string, :size_t, :uint64], :uint64
- attach_function :city_hash64_with_seeds, :CityHash64WithSeeds, [:string, :size_t, :uint64, :uint64], :uint64
- attach_function :city_hash128, :CityHash128String, [:string, :size_t], :string
- attach_function :city_hash128_with_seed, :CityHash128WithSeedString, [:string, :size_t, :uint64, :uint64], :string
- end
-
- def self.hash64(input, seed1 = nil, seed2 = nil)
- input = input.to_s
- len = input.bytesize
-
- return CityHash::Internal.city_hash64(input, len) unless seed1
- return CityHash::Internal.city_hash64_with_seed(input, len, seed1.to_i & LOW64_MASK) unless seed2
-
- CityHash::Internal.city_hash64_with_seeds(input, len, seed1.to_i & LOW64_MASK, seed2.to_i & LOW64_MASK)
+ def self.hash64(input, seed1=nil, seed2=nil)
+ return Internal.hash64(input) if seed1.nil?
+ return Internal.hash64_with_seed(input, seed1.to_i) if seed2.nil?
+ Internal.hash64_with_seeds(input, seed1.to_i, seed2.to_i)
end
- def self.hash128(input, seed = nil)
- input = input.to_s
- len = input.bytesize
-
- return CityHash::Internal.city_hash128(input, len).to_i unless seed
-
- seed_low = seed.to_i & LOW64_MASK
- seed_high = (seed.to_i & HIGH64_MASK) >> 64
-
- CityHash::Internal.city_hash128_with_seed(input, len, seed_low, seed_high).to_i
+ def self.hash128(input, seed=nil)
+ if seed
+ seed = [seed & LOW64_MASK, seed & HIGH64_MASK >> 64].pack('QQ')
+ digest = Internal.hash128_with_seed(input, seed)
+ else
+ digest = Internal.hash128(input)
+ end
+ [0..7, 8..15].map { |r| digest[r].unpack('Q').first.to_s }.join.to_i
end
end

0 comments on commit 3117801

Please sign in to comment.