Skip to content

Commit

Permalink
feat: add CityHash128 support (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
XadillaX authored Jun 30, 2018
1 parent bcdd02c commit a42d1ef
Show file tree
Hide file tree
Showing 9 changed files with 462 additions and 20 deletions.
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
language: node_js
node_js:
- "0.10"
- "0.11"
- "0.12"
- "4.0.0"
- "4.1"
- "4"
- "6"
- "8"
install:
- export CXX="g++-4.8" CXX="gcc-4.8"
- $CXX --version
Expand Down
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ There are 8 algorithms so far.
* [ELFHash](http://www.partow.net/programming/hashfunctions/#ELFHashFunction)
* [CityHash](https://github.com/google/cityhash)
- [CityHash32](https://github.com/google/cityhash/blob/master/src/city.cc#L189): returns a 32-bit hash.
- [CityHash64](https://https://github.com/google/cityhash/blob/master/src/city.cc#L366): and similar return a 64-bit hash.
- [CityHash64](https://github.com/google/cityhash/blob/master/src/city.cc#L366): and similar return a 64-bit hash.
- [CityHash128](https://github.com/google/cityhash/blob/master/src/city.cc#L508): and similar return a 128-bit hash.

The benchmark, performance and implementation can be referenced [here (各种字符串Hash函数比较)](https://www.byvoid.com/blog/string-hash-compare/).

Expand All @@ -48,12 +49,24 @@ And then you can pass any string to functions (the same name as algorithms, in l
Eg.

```javascript
var hash = bling.bkdr("Hello world!"); ///< 501511565
var hash1 = bling.bkdr("Hello world!"); ///< 501511565
var hash2 = bling.city32("玉扣"); ///< 887335438
```

## Return Values

+ From `BKDR` to `ELF`, the functions return a `Number` value;
+ `city32` returns a `Number` value too;
+ `city64` returns a `Long` value which may refer [here](https://github.com/dcodeIO/long.js);
+ `city128` returns a `City128Value` value which has properties below:
- `.toString()`: The string value of the 128-bit number;
- `.toLongArray()`: An array that includes two 64-bit `Long` value;
- `.toBuffers()`: An array that includes two `Buffer`s.
- `.toBigNumber()`: A `BigNumber` value which may refer [here](https://github.com/alexbardas/bignumber.js);

## Contribution

Thanks to [ByVoid](https://github.com/byvoid). The C++ implementation code was copied from his blog.
Thanks to [BYVoid](https://github.com/byvoid). The C++ implementation code was copied from his blog.

You're welcome to make pull requests.

Expand Down
12 changes: 12 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
var bling = require("./build/Release/bling");
var Long = require("long");

const City128Value = require('./lib/city128');

/**
* bkdr
* @param {String} str the string will be hashed
Expand Down Expand Up @@ -98,3 +100,13 @@ exports.city64 = function(str) {
_int64 = new Long(_int64.readInt32LE(0), _int64.readInt32LE(4), true);
return _int64;
};

/**
* city128
* @param {String} str the string will be hashed
* @return {City128Value} the hash value
*/
exports.city128 = function(str) {
var _int128 = bling.cityHash128(str);
return new City128Value(_int128);
};
32 changes: 32 additions & 0 deletions lib/city128.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

const BigNumber = require("big-number");
const Long = require("long");

const MAX_UINT64 = '18446744073709551616';

function City128Value(bufs) {
this.bufs = bufs;
this.longs = this.toLongArray();
this.val = (new BigNumber(this.longs[0].toString()))
.multiply(MAX_UINT64)
.plus(this.longs[1].toString());
}

City128Value.prototype.toString = function toString() {
return this.val.toString();
};

City128Value.prototype.toLongArray = function toBufferArray() {
return this.bufs.map(r => new Long(r.readInt32LE(0), r.readInt32LE(4), true));
};

City128Value.prototype.toBuffers = function toBuffers() {
return [ Buffer.from(this.bufs[0]), Buffer.from(this.bufs[1]) ];
};

City128Value.toBigNumber = function toBigNumber() {
return new BigNumber(this.toString());
};

module.exports = City128Value;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
},
"homepage": "https://github.com/XadillaX/bling_hashes#readme",
"dependencies": {
"big-number": "^1.0.0",
"long": "^3.0.1",
"nan": "^2.1.0"
"nan": "^2.7.0"
},
"devDependencies": {
"coveralls": "^2.11.4",
Expand Down
2 changes: 2 additions & 0 deletions src/bling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ NAN_MODULE_INIT(InitAll)
GetFunction(New<FunctionTemplate>(_CityHash32)).ToLocalChecked());
Set(target, New<String>("cityHash64").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(_CityHash64)).ToLocalChecked());
Set(target, New<String>("cityHash128").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(_CityHash128)).ToLocalChecked());
}

NODE_MODULE(bling, InitAll)
38 changes: 35 additions & 3 deletions src/cityhash/entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

void __CityHash64FreeCallback(char* data, void* hint)
{
unsigned long long* hash = (unsigned long long*)data;
uint64* hash = (uint64*)data;
delete hash;
}

Expand Down Expand Up @@ -62,14 +62,46 @@ NAN_METHOD(_CityHash64)
std::string source_string = *v8_source_string;
unsigned int len = source_string.size();

unsigned long long* hash = new unsigned long long(CityHash64(source_string.c_str(), len));
uint64* hash = new uint64(CityHash64(source_string.c_str(), len));
// printf(" %llu\n", *hash);
info.GetReturnValue().Set(
Nan::NewBuffer(
(char*)hash,
sizeof(unsigned long long),
sizeof(uint64),
__CityHash64FreeCallback,
NULL).ToLocalChecked());
}

typedef uint64 (*Extract128Func)(const uint128&);
const Extract128Func Extract128[] = { Uint128Low64, Uint128High64 };

NAN_METHOD(_CityHash128)
{
// argument length...
if(info.Length() < 1)
{
return Nan::ThrowError("invalid argument count");
}

String::Utf8Value v8_source_string(info[0]->ToString());
std::string source_string = *v8_source_string;
unsigned int len = source_string.size();

uint128 hash = CityHash128(source_string.c_str(), len);
v8::Local<v8::Array> array = Nan::New<v8::Array>();
for(int i = 0; i < 2; i++)
{
uint64* _64 = new uint64(Extract128[i](hash));

v8::Local<v8::Value> buf = Nan::NewBuffer(
(char*)_64,
sizeof(uint64),
__CityHash64FreeCallback,
NULL).ToLocalChecked();
Nan::Set(array, i, buf);
}

info.GetReturnValue().Set(array);
}

#endif
Loading

0 comments on commit a42d1ef

Please sign in to comment.