murmurhash3-0.1.6/0000755000175000017500000000000013563550425012520 5ustar srudsrudmurmurhash3-0.1.6/test/0000755000175000017500000000000013563550425013477 5ustar srudsrudmurmurhash3-0.1.6/test/test_murmur.rb0000644000175000017500000000507113563550425016415 0ustar srudsrudrequire 'minitest/spec' require 'minitest/autorun' shared_examples_128 = proc do it 'should make correct hash for string' do murmur.str_hash('asdfqwer', 0).must_equal [0xd6d7d367, 0xcb41f064, 0x8973cd72, 0xc345e72e] murmur.str_hash('asdfqwerzxcvyui', 0).must_equal [0x007b2172f, 0x64ecae1b, 0x1813b5a5, 0x9c674ee6] murmur.str_hash('asdfqwerzxcvyuio', 0).must_equal [0xf508df57, 0xbb38f3fd, 0xf48c9d98, 0xb65c36cd] murmur.str_hash('asdfqwerzxcvyuio!', 0).must_equal [0x8a011755, 0xb13d463f, 0x8386d32a, 0x0df8884c] end it 'should make correct hash for 32bit integer' do murmur.int32_hash(1717859169).must_equal [0x20b48108, 0x10369ceb, 0x3ad523cc, 0xdacb587f] murmur.int32_hash(1717859169).must_equal murmur.str_hash('asdf') end it 'should make correct hash for 64bit integer' do murmur.int64_hash(0x12345678).must_equal murmur.str_hash("\x78\x56\x34\x12\x00\x00\x00\x00") murmur.int64_hash(0x1234567812345678).must_equal murmur.str_hash("\x78\x56\x34\x12\x78\x56\x34\x12") end it 'should make correct fmix for 64bit integer' do murmur.fmix(1717859169).must_equal 0xbefb9076a3712207 murmur.fmix(12345678912345678).must_equal 0x197ef59146f5221c end end shared_examples_32 = proc do it 'should make correct hash for string' do murmur.str_hash('asdfqwer', 0).must_equal 0xa46b5209 murmur.str_hash('asdfqwerty', 0).must_equal 0xa3cfe04b murmur.str_hash('asd', 0).must_equal 0x14570c6f end it 'should make correct hash for 32bit integer' do murmur.int32_hash(1717859169).must_equal 0x1b20e026 murmur.int32_hash(1717859169).must_equal murmur.str_hash('asdf') end it 'should make correct hash for 64bit integer' do murmur.int64_hash(0x12345678).must_equal murmur.str_hash("\x78\x56\x34\x12\x00\x00\x00\x00") murmur.int64_hash(0x1234567812345678).must_equal murmur.str_hash("\x78\x56\x34\x12\x78\x56\x34\x12") end it 'should make correct fmix for 32bit integer' do murmur.fmix(1717859169).must_equal 0x17561734 end end require 'murmurhash3/pure_ruby' describe "Pure ruby 32" do let(:murmur) { MurmurHash3::PureRuby32 } class_exec &shared_examples_32 end describe "Pure ruby 128" do let(:murmur) { MurmurHash3::PureRuby128 } class_exec &shared_examples_128 end begin require 'murmurhash3/native_murmur' describe "Native 32" do let(:murmur) { MurmurHash3::Native32 } class_exec &shared_examples_32 end describe "Native 128" do let(:murmur) { MurmurHash3::Native128 } class_exec &shared_examples_128 end rescue LoadError => e puts "Could not load native extension: #{e}" end murmurhash3-0.1.6/murmurhash3.gemspec0000644000175000017500000000342113563550425016343 0ustar srudsrud######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: murmurhash3 0.1.6 ruby libext # stub: ext/murmurhash3/extconf.rb Gem::Specification.new do |s| s.name = "murmurhash3".freeze s.version = "0.1.6" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze, "ext".freeze] s.authors = ["Sokolov Yura 'funny-falcon'".freeze] s.date = "2014-12-24" s.description = "implementation of murmur3 hashing function".freeze s.email = ["funny.falcon@gmail.com".freeze] s.extensions = ["ext/murmurhash3/extconf.rb".freeze] s.files = ["ext/murmurhash3/extconf.rb".freeze, "ext/murmurhash3/murmur3.c".freeze, "lib/murmurhash3.rb".freeze, "lib/murmurhash3/aliaser.rb".freeze, "lib/murmurhash3/native_murmur.rb".freeze, "lib/murmurhash3/native_ruby.rb".freeze, "lib/murmurhash3/pure_ruby.rb".freeze, "lib/murmurhash3/version.rb".freeze, "test/test_murmur.rb".freeze] s.homepage = "https://github.com/funny-falcon/murmurhash3-ruby".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 1.9.1".freeze) s.rubygems_version = "2.7.6.2".freeze s.summary = "implements mumur3 hashing function".freeze s.test_files = ["test/test_murmur.rb".freeze] if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q.freeze, ["~> 0.9"]) else s.add_dependency(%q.freeze, ["~> 0.9"]) end else s.add_dependency(%q.freeze, ["~> 0.9"]) end end murmurhash3-0.1.6/lib/0000755000175000017500000000000013563550425013266 5ustar srudsrudmurmurhash3-0.1.6/lib/murmurhash3.rb0000644000175000017500000000054213563550425016072 0ustar srudsrudrequire "murmurhash3/version" module MurmurHash3 begin require 'murmurhash3/native_murmur' V32 = Native32 V128 = Native128 rescue LoadError require 'murmurhash3/pure_ruby' if RUBY_ENGINE == 'ruby' $stderr.puts "Attention: used pure ruby version of MurmurHash3" end V32 = PureRuby32 V128 = PureRuby128 end end murmurhash3-0.1.6/lib/murmurhash3/0000755000175000017500000000000013563550425015544 5ustar srudsrudmurmurhash3-0.1.6/lib/murmurhash3/pure_ruby.rb0000644000175000017500000000772513563550425020120 0ustar srudsrudrequire 'murmurhash3/aliaser' module MurmurHash3 module PureRuby32 MASK32 = 0xffffffff def murmur3_32_rotl(x, r) ((x << r) | (x >> (32 - r))) & MASK32 end def murmur3_32_fmix(h) h &= MASK32 h ^= h >> 16 h = (h * 0x85ebca6b) & MASK32 h ^= h >> 13 h = (h * 0xc2b2ae35) & MASK32 h ^ (h >> 16) end def murmur3_32__mmix(k1) k1 = (k1 * 0xcc9e2d51) & MASK32 k1 = murmur3_32_rotl(k1, 15) (k1 * 0x1b873593) & MASK32 end def murmur3_32_str_hash(str, seed=0) h1 = seed numbers = str.unpack('V*C*') tailn = str.bytesize % 4 tail = numbers.slice!(numbers.size - tailn, tailn) for k1 in numbers h1 ^= murmur3_32__mmix(k1) h1 = murmur3_32_rotl(h1, 13) h1 = (h1*5 + 0xe6546b64) & MASK32 end unless tail.empty? k1 = 0 tail.reverse_each do |c1| k1 = (k1 << 8) | c1 end h1 ^= murmur3_32__mmix(k1) end h1 ^= str.bytesize murmur3_32_fmix(h1) end def murmur3_32_int32_hash(i, seed=0) str_hash([i].pack("V"), seed) end def murmur3_32_int64_hash(i, seed=0) str_hash([i].pack("Q<"), seed) end def murmur3_32_str_digest(str, seed=0) [str_hash(str, seed)].pack("V") end def murmur3_32_str_hexdigest(str, seed=0) [str_hash(str, seed)].pack("V").unpack("H*")[0] end def murmur3_32_str_base64digest(str, seed=0) [[str_hash(str, seed)].pack("V")].pack("m").chomp! end include MurmurHash3::Alias32 end module PureRuby128 MASK64 = 0xffff_ffff_ffff_ffff def murmur3_128_rotl(x, r) ((x << r) | (x >> (64 - r))) & MASK64 end def murmur3_128_fmix(h) h &= MASK64 h ^= h >> 33 h = (h * 0xff51afd7_ed558ccd) & MASK64 h ^= h >> 33 h = (h * 0xc4ceb9fe_1a85ec53) & MASK64 h ^ (h >> 33) end C1_128 = 0x87c37b91_114253d5 C2_128 = 0x4cf5ad43_2745937f def murmur3_128__mmix1(k1) k1 = (k1 * C1_128) & MASK64 k1 = murmur3_128_rotl(k1, 31) (k1 * C2_128) & MASK64 end def murmur3_128__mmix2(k2) k2 = (k2 * C2_128) & MASK64 k2 = murmur3_128_rotl(k2, 33) (k2 * C1_128) & MASK64 end def murmur3_128_str_hash(str, seed=0) h1 = h2 = seed fast_part = ((str.bytesize / 16) * 16) numbers = str.byteslice(0, fast_part).unpack('Q<*') tail = str.byteslice(fast_part, str.bytesize - fast_part).unpack('C*') numbers.each_slice(2) do |k1, k2| h1 ^= murmur3_128__mmix1(k1) h1 = murmur3_128_rotl(h1, 27) h1 = (h1 + h2) & MASK64 h1 = (h1*5 + 0x52dce729) & MASK64 h2 ^= murmur3_128__mmix2(k2) h2 = murmur3_128_rotl(h2, 31) h2 = (h1 + h2) & MASK64 h2 = (h2*5 + 0x38495ab5) & MASK64 end unless tail.empty? if tail.size > 8 k2 = 0 tail[8,8].reverse_each do |c2| k2 = (k2 << 8) | c2 end h2 ^= murmur3_128__mmix2(k2) end k1 = 0 tail[0,8].reverse_each do |c1| k1 = (k1 << 8) | c1 end h1 ^= murmur3_128__mmix1(k1) end h1 ^= str.bytesize h2 ^= str.bytesize h1 = (h1 + h2) & MASK64 h2 = (h1 + h2) & MASK64 h1 = murmur3_128_fmix(h1) h2 = murmur3_128_fmix(h2) h1 = (h1 + h2) & MASK64 h2 = (h1 + h2) & MASK64 [h1 & 0xffffffff, h1 >> 32, h2 & 0xffffffff, h2 >> 32] end def murmur3_128_int32_hash(i, seed=0) str_hash([i].pack("V"), seed) end def murmur3_128_int64_hash(i, seed=0) str_hash([i].pack("Q<"), seed) end def murmur3_128_str_digest(str, seed=0) str_hash(str, seed).pack("V4") end def murmur3_128_str_hexdigest(str, seed=0) str_hash(str, seed).pack("V4").unpack("H*")[0] end def murmur3_128_str_base64digest(str, seed=0) [str_hash(str, seed).pack("V4")].pack('m').chomp! end include MurmurHash3::Alias128 end end murmurhash3-0.1.6/lib/murmurhash3/aliaser.rb0000644000175000017500000000164513563550425017517 0ustar srudsrudmodule MurmurHash3 module Alias32 def self.included(base) base.send(:extend, base) class << base alias fmix murmur3_32_fmix alias str_hash murmur3_32_str_hash alias str_digest murmur3_32_str_digest alias str_hexdigest murmur3_32_str_hexdigest alias str_base64digest murmur3_32_str_base64digest alias int32_hash murmur3_32_int32_hash alias int64_hash murmur3_32_int64_hash end end end module Alias128 def self.included(base) base.send(:extend, base) class << base alias fmix murmur3_128_fmix alias str_hash murmur3_128_str_hash alias str_digest murmur3_128_str_digest alias str_hexdigest murmur3_128_str_hexdigest alias str_base64digest murmur3_128_str_base64digest alias int32_hash murmur3_128_int32_hash alias int64_hash murmur3_128_int64_hash end end end end murmurhash3-0.1.6/lib/murmurhash3/native_ruby.rb0000644000175000017500000000041613563550425020421 0ustar srudsrudrequire 'murmurhash3/aliaser' if RUBY_ENGINE == 'jruby' require 'murmurhash3/native' else require 'murmurhash3/native' end module MurmurHash3 module Native32 include MurmurHash3::Alias32 end #module Native128 # include MurmurHash3::Alias128 #end end murmurhash3-0.1.6/lib/murmurhash3/native_murmur.rb0000644000175000017500000000030713563550425020766 0ustar srudsrudrequire 'murmurhash3/aliaser' require 'murmurhash3/native' module MurmurHash3 module Native32 include MurmurHash3::Alias32 end module Native128 include MurmurHash3::Alias128 end end murmurhash3-0.1.6/lib/murmurhash3/version.rb0000644000175000017500000000005313563550425017554 0ustar srudsrudmodule MurmurHash3 VERSION = "0.1.6" end murmurhash3-0.1.6/ext/0000755000175000017500000000000013563550425013320 5ustar srudsrudmurmurhash3-0.1.6/ext/murmurhash3/0000755000175000017500000000000013563550425015576 5ustar srudsrudmurmurhash3-0.1.6/ext/murmurhash3/murmur3.c0000644000175000017500000004040613563550425017360 0ustar srudsrud#include /*----------------------------------------------------------------------------- * MurmurHash3 was written by Austin Appleby, and is placed in the public * domain. The author hereby disclaims copyright to this source code. * Note - The x86 and x64 versions do _not_ produce the same results, as the * algorithms are optimized for their respective platforms. You can still * compile and run any of them on any platform, but your performance with the * non-native version will be less than optimal. */ typedef unsigned char uint8_t; typedef unsigned int uint32_t; #ifndef HAVE_STDINT_H #if SIZEOF_LONG == 8 typedef unsigned long uint64_t; #else typedef unsigned long long uint64_t; #endif #endif /*----------------------------------------------------------------------------- * Platform-specific functions and macros */ #ifdef __GNUC__ #define FORCE_INLINE __attribute__((always_inline)) #elif defined(_MSC_VER) #define FORCE_INLINE __forceinline #else #define FORCE_INLINE #endif #if defined(_MSC_VER) #define ROTL32(x,y) _rotl(x,y) #define ROTL64(x,y) _rotl64(x,y) #define BIG_CONSTANT(x) (x) #else static inline FORCE_INLINE uint32_t rotl32 ( uint32_t x, int8_t r ) { return (x << r) | (x >> (32 - r)); } static inline FORCE_INLINE uint64_t rotl64 ( uint64_t x, int8_t r ) { return (x << r) | (x >> (64 - r)); } #define ROTL32(x,y) rotl32(x,y) #define ROTL64(x,y) rotl64(x,y) #define BIG_CONSTANT(x) (x##LLU) #endif /* end platform specific */ /* Block read - if your platform needs to do endian-swapping or can only * handle aligned reads, do the conversion here */ #ifdef WORDS_BIGENDIAN #define GCC_VERSION_SINCE(major, minor, patchlevel) \ (defined(__GNUC__) && !defined(__INTEL_COMPILER) && \ ((__GNUC__ > (major)) || \ (__GNUC__ == (major) && __GNUC_MINOR__ > (minor)) || \ (__GNUC__ == (major) && __GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ >= (patchlevel)))) #if GCC_VERSION_SINCE(4,3,0) # define swap32(x) __builtin_bswap32(x) # define swap64(x) __builtin_bswap64(x) #endif #ifndef swap32 # define swap32(x) ((((x)&0xFF)<<24) \ |(((x)>>24)&0xFF) \ |(((x)&0x0000FF00)<<8) \ |(((x)&0x00FF0000)>>8) ) #endif #ifndef swap64 # ifdef HAVE_INT64_T static inline FORCE_INLINE uint64_t swap64(uint64_t x) { x = (x>>32) | (x << 32); x = ((x & BIG_CONSTANT(0xFFFF0000FFFF0000)) >> 16) | ((x & BIG_CONSTANT(0x0000FFFF0000FFFF)) << 16); return ((x & BIG_CONSTANT(0xFF00FF00FF00FF00)) >> 8) | ((x & BIG_CONSTANT(0x00FF00FF00FF00FF)) << 8); } # endif #endif static inline FORCE_INLINE uint32_t getblock32(const uint32_t * p, int i) { return swap32(p[i]); } static inline FORCE_INLINE uint64_t getblock64(const uint64_t * p, int i) { return swap64(p[i]); } #else #define getblock32(p, i) (p[i]) #define getblock64(p, i) (p[i]) #endif static const char hex[] = "000102030405060708090a0b0c0d0e0f" \ "101112131415161718191a1b1c1d1e1f" \ "202122232425262728292a2b2c2d2e2f" \ "303132333435363738393a3b3c3d3e3f" \ "404142434445464748494a4b4c4d4e4f" \ "505152535455565758595a5b5c5d5e5f" \ "606162636465666768696a6b6c6d6e6f" \ "707172737475767778797a7b7c7d7e7f" \ "808182838485868788898a8b8c8d8e8f" \ "909192939495969798999a9b9c9d9e9f" \ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" \ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" \ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" \ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" \ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" \ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* Finalization mix - force all bits of a hash block to avalanche */ static inline FORCE_INLINE uint32_t fmix32 ( uint32_t h ) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } static inline FORCE_INLINE uint64_t fmix64 ( uint64_t k ) { k ^= k >> 33; k *= BIG_CONSTANT(0xff51afd7ed558ccd); k ^= k >> 33; k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); k ^= k >> 33; return k; } static inline FORCE_INLINE uint32_t mmix32(uint32_t k1) { k1 *= 0xcc9e2d51; k1 = ROTL32(k1, 15); return k1 * 0x1b873593; } static uint32_t MurmurHash3_x86_32 ( const void * key, long len, uint32_t seed) { const uint8_t * data = (const uint8_t*)key; const int nblocks = (int)(len / 4); int i; uint32_t h1 = seed; uint32_t k1 = 0; /* body */ const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); for(i = -nblocks; i; i++) { h1 ^= mmix32(getblock32(blocks, i)); h1 = ROTL32(h1,13); h1 = h1*5+0xe6546b64; } /* tail */ data += nblocks*4; switch(len & 3) { case 3: k1 ^= data[2] << 16; case 2: k1 ^= data[1] << 8; case 1: k1 ^= data[0]; h1 ^= mmix32(k1); }; /* finalization */ h1 ^= len; h1 = fmix32(h1); return h1; } #define C1_128 BIG_CONSTANT(0x87c37b91114253d5) #define C2_128 BIG_CONSTANT(0x4cf5ad432745937f) static inline FORCE_INLINE uint64_t mmix128_1(uint64_t k1) { k1 *= C1_128; k1 = ROTL64(k1, 31); return k1 * C2_128; } static inline FORCE_INLINE uint64_t mmix128_2(uint64_t k2) { k2 *= C2_128; k2 = ROTL64(k2, 33); return k2 * C1_128; } static void MurmurHash3_x64_128 ( const void * key, const long len, const uint32_t seed, void * out ) { const uint8_t * data = (const uint8_t*)key; const int nblocks = (int)(len / 16); int i; uint64_t h1 = seed; uint64_t h2 = seed; uint64_t k1 = 0, k2 = 0; /* body */ const uint64_t * blocks = (const uint64_t *)(data); for(i = 0; i < nblocks; i++) { k1 = getblock64(blocks, i*2+0); k2 = getblock64(blocks, i*2+1); h1 ^= mmix128_1(k1); h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; h2 ^= mmix128_2(k2); h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; } /* tail */ data += nblocks*16; k1 = k2 = 0; switch(len & 15) { case 15: k2 ^= (uint64_t)(data[14]) << 48; case 14: k2 ^= (uint64_t)(data[13]) << 40; case 13: k2 ^= (uint64_t)(data[12]) << 32; case 12: k2 ^= (uint64_t)(data[11]) << 24; case 11: k2 ^= (uint64_t)(data[10]) << 16; case 10: k2 ^= (uint64_t)(data[ 9]) << 8; case 9: k2 ^= (uint64_t)(data[ 8]) << 0; h2 ^= mmix128_2(k2); case 8: k1 ^= (uint64_t)(data[ 7]) << 56; case 7: k1 ^= (uint64_t)(data[ 6]) << 48; case 6: k1 ^= (uint64_t)(data[ 5]) << 40; case 5: k1 ^= (uint64_t)(data[ 4]) << 32; case 4: k1 ^= (uint64_t)(data[ 3]) << 24; case 3: k1 ^= (uint64_t)(data[ 2]) << 16; case 2: k1 ^= (uint64_t)(data[ 1]) << 8; case 1: k1 ^= (uint64_t)(data[ 0]) << 0; h1 ^= mmix128_1(k1); }; /* finalization */ h1 ^= len; h2 ^= len; h1 += h2; h2 += h1; h1 = fmix64(h1); h2 = fmix64(h2); h1 += h2; h2 += h1; ((uint64_t*)out)[0] = h1; ((uint64_t*)out)[1] = h2; } /* end of MurmurHash3 algorithm */ static VALUE rb_fmix32(VALUE self, VALUE integer) { uint32_t _int = NUM2UINT(integer); return UINT2NUM(fmix32(_int)); } static VALUE rb_fmix64(VALUE self, VALUE integer) { #if SIZEOF_LONG == 8 uint64_t _int = NUM2ULONG(integer); return ULONG2NUM(fmix64(_int)); #else uint64_t _int = NUM2ULL(integer); return ULL2NUM(fmix64(_int)); #endif } static uint32_t rb_murmur3_32_hash(int argc, VALUE* argv, VALUE self) { VALUE rstr; if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "accept 1 or 2 arguments: (string[, seed])"); } rstr = argv[0]; StringValue(rstr); return MurmurHash3_x86_32(RSTRING_PTR(rstr), RSTRING_LEN(rstr), argc == 1 ? 0 : NUM2UINT(argv[1])); } static VALUE rb_murmur3_32_str_hash(int argc, VALUE* argv, VALUE self) { return UINT2NUM(rb_murmur3_32_hash(argc, argv, self)); } #define SWAP_32_INT(t) do { \ (t) = ((t) >> 24) | (((t) >> 8) & 0xff00) | \ (((t) & 0xff00) << 8) | ((t) << 24); \ } while (0) static VALUE rb_murmur3_32_str_digest(int argc, VALUE* argv, VALUE self) { union { uint32_t result; char res[4]; } r; r.result = rb_murmur3_32_hash(argc, argv, self); #if WORDS_BIGENDIAN SWAP_32_INT(r.result); #endif return rb_str_new(r.res, 4); } static VALUE rb_murmur3_32_str_hexdigest(int argc, VALUE* argv, VALUE self) { union { uint32_t result; unsigned char res[4]; } r; char out[8]; int i; r.result = rb_murmur3_32_hash(argc, argv, self); #if WORDS_BIGENDIAN SWAP_32_INT(r.result); #endif for(i = 0; i<4; i++) { out[i*2] = hex[r.res[i]*2]; out[i*2+1] = hex[r.res[i]*2+1]; } return rb_str_new(out, 8); } static VALUE rb_murmur3_32_str_base64digest(int argc, VALUE *argv, VALUE self) { union { uint32_t result; unsigned char res[6]; } r; char out[8]; int i; r.result = rb_murmur3_32_hash(argc, argv, self); #if WORDS_BIGENDIAN SWAP_32_INT(r.result); #endif r.res[4] = 0; r.res[5] = 0; for(i = 0; i<2; i++) { uint32_t b64 = ((uint32_t)r.res[i*3+0] << 16) | ((uint32_t)r.res[i*3+1] << 8) | (uint32_t)r.res[i*3+2]; out[i*4+0] = base64[(b64 >> 18) & 0x3f]; out[i*4+1] = base64[(b64 >> 12) & 0x3f]; out[i*4+2] = base64[(b64 >> 6) & 0x3f]; out[i*4+3] = base64[(b64 >> 0) & 0x3f]; } out[6] = '='; out[7] = '='; return rb_str_new(out, sizeof(out)); } static VALUE rb_murmur3_32_int32_hash(int argc, VALUE* argv, VALUE self) { uint32_t _int; uint32_t result; if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int32[, seed])"); } _int = NUM2UINT(argv[0]); result = MurmurHash3_x86_32(&_int, 4, argc == 1 ? 0 : NUM2UINT(argv[1])); return UINT2NUM(result); } static VALUE rb_murmur3_32_int64_hash(int argc, VALUE* argv, VALUE self) { uint64_t _int; uint32_t result; if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int64[, seed])"); } #if SIZEOF_LONG == 8 _int = NUM2ULONG(argv[0]); #else _int = NUM2ULL(argv[0]); #endif result = MurmurHash3_x86_32(&_int, 8, argc == 1 ? 0 : NUM2UINT(argv[1])); return UINT2NUM(result); } #define PREPARE_128_BIT() \ VALUE rstr, rseed, ar_result; \ uint32_t result[4]; \ #define SWAP_128_BIT() do { \ uint32_t tmp; \ tmp = result[0]; \ result[0] = result[1]; \ result[1] = tmp; \ tmp = result[2]; \ result[2] = result[3]; \ result[3] = tmp; \ } while (0) #define SWAP_128_BIT_BYTE() do { \ uint32_t tmp; \ tmp = r.result[0]; \ SWAP_32_INT(tmp); \ SWAP_32_INT(r.result[1]); \ r.result[0] = r.result[1]; \ r.result[1] = tmp; \ tmp = r.result[2]; \ SWAP_32_INT(tmp); \ SWAP_32_INT(r.result[3]); \ r.result[2] = r.result[3]; \ r.result[3] = tmp; \ } while (0) #define RETURN_128_BIT() \ ar_result = rb_ary_new2(4); \ rb_ary_push(ar_result, UINT2NUM(result[0])); \ rb_ary_push(ar_result, UINT2NUM(result[1])); \ rb_ary_push(ar_result, UINT2NUM(result[2])); \ rb_ary_push(ar_result, UINT2NUM(result[3])); \ return ar_result static void rb_murmur3_128_hash(int argc, VALUE* argv, VALUE self, uint32_t result[4]) { VALUE rstr; if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "accept 1 or 2 arguments: (string[, seed])"); } rstr = argv[0]; StringValue(rstr); MurmurHash3_x64_128(RSTRING_PTR(rstr), RSTRING_LEN(rstr), argc == 1 ? 0 : NUM2UINT(argv[1]), result); } static VALUE rb_murmur3_128_str_hash(int argc, VALUE* argv, VALUE self) { VALUE ar_result; uint32_t result[4]; rb_murmur3_128_hash(argc, argv, self, result); #if WORDS_BIGENDIAN SWAP_128_BIT(); #endif RETURN_128_BIT(); } static VALUE rb_murmur3_128_str_digest(int argc, VALUE *argv, VALUE self) { union { uint32_t result[4]; char res[16]; } r; rb_murmur3_128_hash(argc, argv, self, r.result); #if WORDS_BIGENDIAN SWAP_128_BIT_BYTE(); #endif return rb_str_new(r.res, sizeof(r.res)); } static VALUE rb_murmur3_128_str_hexdigest(int argc, VALUE *argv, VALUE self) { union { uint32_t result[4]; unsigned char res[16]; } r; char out[32]; int i; rb_murmur3_128_hash(argc, argv, self, r.result); #if WORDS_BIGENDIAN SWAP_128_BIT_BYTE(); #endif for(i = 0; i<16; i++) { out[i*2] = hex[r.res[i]*2]; out[i*2+1] = hex[r.res[i]*2+1]; } return rb_str_new(out, sizeof(out)); } static VALUE rb_murmur3_128_str_base64digest(int argc, VALUE *argv, VALUE self) { union { uint32_t result[4]; unsigned char res[18]; } r; char out[24]; int i; rb_murmur3_128_hash(argc, argv, self, r.result); #if WORDS_BIGENDIAN SWAP_128_BIT_BYTE(); #endif r.res[16] = 0; r.res[17] = 0; for(i = 0; i<6; i++) { uint32_t b64 = ((uint32_t)r.res[i*3+0] << 16) | ((uint32_t)r.res[i*3+1] << 8) | (uint32_t)r.res[i*3+2]; out[i*4+0] = base64[(b64 >> 18) & 0x3f]; out[i*4+1] = base64[(b64 >> 12) & 0x3f]; out[i*4+2] = base64[(b64 >> 6) & 0x3f]; out[i*4+3] = base64[(b64 >> 0) & 0x3f]; } out[22] = '='; out[23] = '='; return rb_str_new(out, sizeof(out)); } static VALUE rb_murmur3_128_int32_hash(int argc, VALUE* argv, VALUE self) { VALUE ar_result; uint32_t result[4], _int; if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int32[, seed])"); } _int = NUM2UINT(argv[0]); MurmurHash3_x64_128(&_int, 4, argc == 1 ? 0 : NUM2UINT(argv[1]), result); #if WORDS_BIGENDIAN SWAP_128_BIT(); #endif RETURN_128_BIT(); } static VALUE rb_murmur3_128_int64_hash(int argc, VALUE* argv, VALUE self) { VALUE ar_result; uint32_t result[4]; uint64_t _int; if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int64[, seed])"); } #if SIZEOF_LONG == 8 _int = NUM2ULONG(argv[0]); #else _int = NUM2ULL(argv[0]); #endif MurmurHash3_x64_128(&_int, 8, argc == 1 ? 0 : NUM2UINT(argv[1]), result); #if WORDS_BIGENDIAN SWAP_128_BIT(); #endif RETURN_128_BIT(); } void Init_native() { VALUE mod_murmur = rb_define_module("MurmurHash3"); VALUE mod_murmur32 = rb_define_module_under(mod_murmur, "Native32"); VALUE mod_murmur128 = rb_define_module_under(mod_murmur, "Native128"); rb_define_method(mod_murmur32, "murmur3_32_fmix", rb_fmix32, 1); rb_define_method(mod_murmur32, "murmur3_32_str_hash", rb_murmur3_32_str_hash, -1); rb_define_method(mod_murmur32, "murmur3_32_str_digest", rb_murmur3_32_str_digest, -1); rb_define_method(mod_murmur32, "murmur3_32_str_hexdigest", rb_murmur3_32_str_hexdigest, -1); rb_define_method(mod_murmur32, "murmur3_32_str_base64digest", rb_murmur3_32_str_base64digest, -1); rb_define_method(mod_murmur32, "murmur3_32_int32_hash", rb_murmur3_32_int32_hash, -1); rb_define_method(mod_murmur32, "murmur3_32_int64_hash", rb_murmur3_32_int64_hash, -1); rb_define_method(mod_murmur128, "murmur3_128_fmix", rb_fmix64, 1); rb_define_method(mod_murmur128, "murmur3_128_str_hash", rb_murmur3_128_str_hash, -1); rb_define_method(mod_murmur128, "murmur3_128_str_digest", rb_murmur3_128_str_digest, -1); rb_define_method(mod_murmur128, "murmur3_128_str_hexdigest", rb_murmur3_128_str_hexdigest, -1); rb_define_method(mod_murmur128, "murmur3_128_str_base64digest", rb_murmur3_128_str_base64digest, -1); rb_define_method(mod_murmur128, "murmur3_128_int32_hash", rb_murmur3_128_int32_hash, -1); rb_define_method(mod_murmur128, "murmur3_128_int64_hash", rb_murmur3_128_int64_hash, -1); } murmurhash3-0.1.6/ext/murmurhash3/extconf.rb0000644000175000017500000000031013563550425017563 0ustar srudsrudif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' require 'mkmf' create_makefile("native") else File.open(File.dirname(__FILE__) + "/Makefile", 'w') do |f| f.write("install:\n\t") end end