From 108950518f428be6fcc8db486e371bfdc0e2e7a9 Mon Sep 17 00:00:00 2001 From: Vasiliy Ermolovich Date: Sat, 27 Apr 2013 17:54:45 +0300 Subject: [PATCH] add crc methods --- CHANGELOG.md | 5 +++++ README.md | 2 ++ ext/cityhash/citycrc.h | 43 ++++++++++++++++++++++++++++++++++++++++ ext/cityhash/cityhash.cc | 24 ++++++++++++++++++++++ ext/cityhash/extconf.rb | 2 +- lib/cityhash.rb | 28 ++++++++++++++++++++++---- test/cityhash_test.rb | 9 +++++++++ 7 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 ext/cityhash/citycrc.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 592ac3b..c793c7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## Unreleased ## + +### enhancements + * add crc methods + ## 0.7.0 (October 25, 2012) ## ### enhancements diff --git a/README.md b/README.md index 13e2054..985a78a 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ CityHash.hash64(text, seed1) # => 9154302171269876511 CityHash.hash64(text, seed1, seed2) # => 4854399283587686019 CityHash.hash128(text) # => 124124989950401219618153994964897029896 CityHash.hash128(text, seed1) # => 101668641288246442316643001405184598611 +CityHash.hash128crc(text) # => 124124989950401219618153994964897029896 +CityHash.hash128crc(text, seed1) # => 101668641288246442316643001405184598611 ``` ### Contributing to cityhash diff --git a/ext/cityhash/citycrc.h b/ext/cityhash/citycrc.h new file mode 100644 index 0000000..318e391 --- /dev/null +++ b/ext/cityhash/citycrc.h @@ -0,0 +1,43 @@ +// Copyright (c) 2011 Google, Inc. +// +// 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. +// +// CityHash, by Geoff Pike and Jyrki Alakuijala +// +// This file declares the subset of the CityHash functions that require +// _mm_crc32_u64(). See the CityHash README for details. +// +// Functions in the CityHash family are not suitable for cryptography. + +#ifndef CITY_HASH_CRC_H_ +#define CITY_HASH_CRC_H_ + +#include + +// Hash function for a byte array. +uint128 CityHashCrc128(const char *s, size_t len); + +// Hash function for a byte array. For convenience, a 128-bit seed is also +// hashed into the result. +uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed); + +// Hash function for a byte array. Sets result[0] ... result[3]. +void CityHashCrc256(const char *s, size_t len, uint64 *result); + +#endif // CITY_HASH_CRC_H_ diff --git a/ext/cityhash/cityhash.cc b/ext/cityhash/cityhash.cc index e0c87e3..aa64333 100644 --- a/ext/cityhash/cityhash.cc +++ b/ext/cityhash/cityhash.cc @@ -1,6 +1,10 @@ #include #include "city.h" +#ifdef __SSE4_2__ +#include "citycrc.h" +#endif + // Use this typedef to make the compiler happy when // calling rb_define_method() typedef VALUE (ruby_method)(...); @@ -38,6 +42,21 @@ extern "C" VALUE cityhash_hash128_with_seed(VALUE mod, VALUE input, VALUE seed_s return rb_str_new((char *)&hash, sizeof(hash)); } +#ifdef __SSE4_2__ +extern "C" VALUE cityhash_hashcrc128(VALUE mod, VALUE input) +{ + uint128 hash = CityHashCrc128(StringValuePtr(input), RSTRING_LEN(input)); + return rb_str_new((char *)&hash, sizeof(hash)); +} + +extern "C" VALUE cityhash_hashcrc128_with_seed(VALUE mod, VALUE input, VALUE seed_string) +{ + uint128 seed = *(uint128 *)StringValuePtr(seed_string); + uint128 hash = CityHashCrc128WithSeed(StringValuePtr(input), RSTRING_LEN(input), seed); + return rb_str_new((char *)&hash, sizeof(hash)); +} +#endif + extern "C" void Init_cityhash() { VALUE mCityHash = rb_define_module("CityHash"); @@ -51,4 +70,9 @@ extern "C" void Init_cityhash() 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); + +#ifdef __SSE4_2__ + rb_define_singleton_method(mInternal, "hash128crc", (ruby_method*) &cityhash_hashcrc128, 1); + rb_define_singleton_method(mInternal, "hash128crc_with_seed", (ruby_method*) &cityhash_hashcrc128_with_seed, 2); +#endif } diff --git a/ext/cityhash/extconf.rb b/ext/cityhash/extconf.rb index 083ecba..0adc64c 100644 --- a/ext/cityhash/extconf.rb +++ b/ext/cityhash/extconf.rb @@ -1,6 +1,6 @@ require 'mkmf' -%w{g O3 Wall}.each do |flag| +%w{g O3 Wall msse4.2}.each do |flag| flag = "-#{flag}" $CPPFLAGS += " #{flag}" unless $CPPFLAGS.split.include? flag end diff --git a/lib/cityhash.rb b/lib/cityhash.rb index 86364c1..c61915e 100644 --- a/lib/cityhash.rb +++ b/lib/cityhash.rb @@ -16,12 +16,32 @@ def self.hash64(input, seed1=nil, seed2=nil) end 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) + digest = if seed + Internal.hash128_with_seed(input, packed_seed(seed)) else - digest = Internal.hash128(input) + Internal.hash128(input) end + + unpacked_digest(digest) + end + + def self.hash128crc(input, seed=nil) + digest = if seed + Internal.hash128crc_with_seed(input, packed_seed(seed)) + else + Internal.hash128crc(input) + end + + unpacked_digest(digest) + end + + private + + def self.packed_seed(seed) + [seed & LOW64_MASK, seed & HIGH64_MASK >> 64].pack('QQ') + end + + def self.unpacked_digest(digest) [0..7, 8..15].map { |r| digest[r].unpack('Q').first.to_s }.join.to_i end end diff --git a/test/cityhash_test.rb b/test/cityhash_test.rb index 091ab4a..26041ff 100644 --- a/test/cityhash_test.rb +++ b/test/cityhash_test.rb @@ -25,4 +25,13 @@ seed = (123 << 64) | 123 assert_equal 1834994000056895780313918994795281207519, CityHash.hash128("test", seed) end + + it "returns 128bit crc hash" do + assert_equal 124124989950401219618153994964897029896, CityHash.hash128crc("test") + end + + it "returns 128bit crc hash with seed" do + seed = (123 << 64) | 123 + assert_equal 1834994000056895780313918994795281207519, CityHash.hash128crc("test", seed) + end end