murmurhash3-0.1.7/0000755000004100000410000000000014362544422014033 5ustar www-datawww-datamurmurhash3-0.1.7/test/0000755000004100000410000000000014362544422015012 5ustar www-datawww-datamurmurhash3-0.1.7/test/test_murmur.rb0000644000004100000410000000507114362544422017730 0ustar www-datawww-datarequire '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.7/LICENSE0000644000004100000410000000207314362544422015042 0ustar www-datawww-dataCopyright (c) 2012 Sokolov Yura 'funny-falcon' MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.murmurhash3-0.1.7/lib/0000755000004100000410000000000014362544422014601 5ustar www-datawww-datamurmurhash3-0.1.7/lib/murmurhash3/0000755000004100000410000000000014362544422017057 5ustar www-datawww-datamurmurhash3-0.1.7/lib/murmurhash3/version.rb0000644000004100000410000000005314362544422021067 0ustar www-datawww-datamodule MurmurHash3 VERSION = "0.1.7" end murmurhash3-0.1.7/lib/murmurhash3/aliaser.rb0000644000004100000410000000164514362544422021032 0ustar www-datawww-datamodule 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.7/lib/murmurhash3/native_murmur.rb0000644000004100000410000000030714362544422022301 0ustar www-datawww-datarequire 'murmurhash3/aliaser' require 'murmurhash3/native' module MurmurHash3 module Native32 include MurmurHash3::Alias32 end module Native128 include MurmurHash3::Alias128 end end murmurhash3-0.1.7/lib/murmurhash3/pure_ruby.rb0000644000004100000410000000772514362544422021433 0ustar www-datawww-datarequire '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.7/lib/murmurhash3.rb0000644000004100000410000000054214362544422017405 0ustar www-datawww-datarequire "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.7/ext/0000755000004100000410000000000014362544422014633 5ustar www-datawww-datamurmurhash3-0.1.7/ext/murmurhash3/0000755000004100000410000000000014362544422017111 5ustar www-datawww-datamurmurhash3-0.1.7/ext/murmurhash3/extconf.rb0000644000004100000410000000032414362544422021103 0ustar www-datawww-dataif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' require 'mkmf' create_makefile("murmurhash3/native") else File.open(File.dirname(__FILE__) + "/Makefile", 'w') do |f| f.write("install:\n\t") end end murmurhash3-0.1.7/ext/murmurhash3/murmur3.c0000644000004100000410000004040614362544422020673 0ustar www-datawww-data#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.7/murmurhash3.gemspec0000644000004100000410000000322614362544422017661 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: murmurhash3 0.1.7 ruby libext # stub: ext/murmurhash3/extconf.rb Gem::Specification.new do |s| s.name = "murmurhash3".freeze s.version = "0.1.7" 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 = "2023-01-05" s.description = "implementation of murmur3 hashing function".freeze s.email = ["funny.falcon@gmail.com".freeze] s.extensions = ["ext/murmurhash3/extconf.rb".freeze] s.files = ["LICENSE".freeze, "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/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 = "3.2.5".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 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 0.9"]) else s.add_dependency(%q.freeze, ["~> 0.9"]) end end