diff --git a/src/lua/digest.lua b/src/lua/digest.lua index 96a86e3d386e9b35223bd779aced21b522be3b91..2955caa4dc9ed6b370c61c7bbc143da6038fd2b5 100644 --- a/src/lua/digest.lua +++ b/src/lua/digest.lua @@ -1,7 +1,5 @@ -- digest.lua (internal file) -do - local ffi = require 'ffi' ffi.cdef[[ @@ -26,13 +24,18 @@ ffi.cdef[[ extern int32_t guava(int64_t state, int32_t buckets); extern crc32_func crc32_calc; - /* base64 */ - int base64_bufsize(int binsize); - int base64_decode(const char *in_base64, int in_len, char *out_bin, int out_len); - int base64_encode(const char *in_bin, int in_len, char *out_base64, int out_len); + /* base64 */ + int base64_bufsize(int binsize); + int base64_decode(const char *in_base64, int in_len, char *out_bin, int out_len); + int base64_encode(const char *in_bin, int in_len, char *out_base64, int out_len); + + /* random */ + void random_bytes(char *, size_t); - /* random */ - void random_bytes(char *, size_t); + /* from third_party/PMurHash.h */ + void PMurHash32_Process(uint32_t *ph1, uint32_t *pcarry, const void *key, int len); + uint32_t PMurHash32_Result(uint32_t h1, uint32_t carry, uint32_t total_length); + uint32_t PMurHash32(uint32_t seed, const void *key, int len); ]] local ssl @@ -53,7 +56,6 @@ if ssl == nil then end end - local def = { sha = { 'SHA', 20 }, sha224 = { 'SHA224', 28 }, @@ -74,6 +76,94 @@ local function tohex(r, size) return ffi.string(hexres, size * 2) end +local PMurHash +local PMurHash_methods = { + + update = function(self, str) + str = tostring(str or '') + ffi.C.PMurHash32_Process(self.seed, self.value, str, string.len(str)) + self.total_length = self.total_length + string.len(str) + end, + + result = function(self) + return ffi.C.PMurHash32_Result(self.seed[0], self.value[0], self.total_length) + end, + + clear = function(self) + self.seed[0] = self.default_seed + self.total_length = 0 + self.value[0] = 0 + end, + + copy = function(self) + local new_self = PMurHash.new() + new_self.seed[0] = self.seed[0] + new_self.value[0] = self.value[0] + new_self.total_length = self.total_length + return new_self + end +} + +PMurHash = { + default_seed = 13, + + new = function(opts) + opts = opts or {} + local self = setmetatable({}, { __index = PMurHash_methods }) + self.default_seed = (opts.seed or PMurHash.default_seed) + self.seed = ffi.new("int[1]", self.default_seed) + self.value = ffi.new("int[1]", 0) + self.total_length = 0 + return self + end +} + +setmetatable(PMurHash, { + __call = function(self, str) + str = tostring(str or '') + return ffi.C.PMurHash32(PMurHash.default_seed, str, string.len(str)) + end +}) + +local CRC32 +local CRC32_methods = { + update = function(self, str) + str = tostring(str or '') + self.value = ffi.C.crc32_calc(self.value, str, string.len(str)) + end, + + result = function(self) + return self.value + end, + + clear = function(self) + self.value = CRC32.crc_begin + end, + + copy = function(self) + local new_self = CRC32.new() + new_self.value = self.value + return new_self + end +} + +CRC32 = { + crc_begin = 4294967295, + + new = function() + local self = setmetatable({}, { __index = CRC32_methods }) + self.value = CRC32.crc_begin + return self + end +} + +setmetatable(CRC32, { + __call = function(self, str) + str = tostring(str or '') + return ffi.C.crc32_calc(CRC32.crc_begin, str, string.len(str)) + end +}) + local m = { base64_encode = function(bin) if type(bin) ~= 'string' then @@ -97,21 +187,10 @@ local m = { return ffi.string(bin, len) end, - crc32 = function(str) - if str == nil then - str = '' - else - str = tostring(str) - end - return ffi.C.crc32_calc(4294967295, str, string.len(str)) - end, + crc32 = CRC32, crc32_update = function(crc, str) - if str == nil then - str = '' - else - str = tostring(str) - end + str = tostring(str or '') return ffi.C.crc32_calc(tonumber(crc), str, string.len(str)) end, @@ -146,7 +225,9 @@ local m = { local buf = ffi.new('char[?]', n) ffi.C.random_bytes(buf, n) return ffi.string(buf, n) - end + end, + + murmur = PMurHash } if ssl ~= nil then @@ -186,5 +267,3 @@ else end return m - -end diff --git a/test/box/digest.result b/test/box/digest.result index a087ba03bc84b072e1645cd7ea5c2c2f7676fc69..8bf68f6bdc5514fb211acb2ef24f14f01c8467e5 100644 --- a/test/box/digest.result +++ b/test/box/digest.result @@ -149,6 +149,32 @@ digest.crc32_update(digest.crc32('abc'), 'cde') --- - 3628146660 ... +crc = digest.crc32.new() +--- +... +crc:update('abc') +--- +... +crc2 = crc:copy() +--- +... +crc:update('cde') +--- +... +crc:result() == digest.crc32('abccde') +--- +- true +... +crc2:update('def') +--- +... +crc2:result() == digest.crc32('abcdef') +--- +- true +... +crc, crc2 = nil, nil +--- +... digest.base64_encode('12345') --- - MTIzNDU= @@ -193,19 +219,19 @@ digest.base64_decode(b) == s ... digest.base64_decode(nil) --- -- error: 'builtin/digest.lua:91: Usage: digest.base64_decode(string)' +- error: 'builtin/digest.lua:181: Usage: digest.base64_decode(string)' ... digest.base64_encode(nil) --- -- error: 'builtin/digest.lua:80: Usage: digest.base64_encode(string)' +- error: 'builtin/digest.lua:170: Usage: digest.base64_encode(string)' ... digest.base64_encode(123) --- -- error: 'builtin/digest.lua:80: Usage: digest.base64_encode(string)' +- error: 'builtin/digest.lua:170: Usage: digest.base64_encode(string)' ... digest.base64_decode(123) --- -- error: 'builtin/digest.lua:91: Usage: digest.base64_decode(string)' +- error: 'builtin/digest.lua:181: Usage: digest.base64_decode(string)' ... digest.guava('hello', 0) --- @@ -229,7 +255,7 @@ digest.guava(1673758223894951030, 11) ... digest.urandom() --- -- error: 'builtin/digest.lua:144: Usage: digest.urandom(len)' +- error: 'builtin/digest.lua:223: Usage: digest.urandom(len)' ... #digest.urandom(0) --- @@ -243,6 +269,53 @@ digest.urandom() --- - 16 ... +digest.murmur('1234') +--- +- 1859914009 +... +mur = digest.murmur.new{seed=13} +--- +... +nulldigest = mur:result() +--- +... +mur:update('1234') +--- +... +mur:result() +--- +- 1859914009 +... +mur_new = mur:copy() +--- +... +mur_new:update('1234') +--- +... +mur_new:result() ~= mur:result() +--- +- true +... +mur:clear() +--- +... +nulldigest == mur:result() +--- +- true +... +mur = digest.murmur.new{seed=14} +--- +... +mur:update('1234') +--- +... +mur:result() +--- +- 1689834281 +... +mur, mur_new, nulldigest = nil, nil, nil +--- +... digest = nil --- ... diff --git a/test/box/digest.test.lua b/test/box/digest.test.lua index 5c1b8b00f22f1000802b36c3fa8eeeda11cb0959..979f911c4041f6866ae74abb98d0f88b8f9c15d3 100644 --- a/test/box/digest.test.lua +++ b/test/box/digest.test.lua @@ -44,6 +44,15 @@ digest.crc32_update(4294967295, 'abc') digest.crc32('abccde') digest.crc32_update(digest.crc32('abc'), 'cde') +crc = digest.crc32.new() +crc:update('abc') +crc2 = crc:copy() +crc:update('cde') +crc:result() == digest.crc32('abccde') +crc2:update('def') +crc2:result() == digest.crc32('abcdef') +crc, crc2 = nil, nil + digest.base64_encode('12345') digest.base64_decode('MTIzNDU=') digest.base64_encode('asdfl asdf adfa zxc vzxcvz llll') @@ -70,4 +79,19 @@ digest.urandom() #digest.urandom(1) #digest.urandom(16) +digest.murmur('1234') +mur = digest.murmur.new{seed=13} +nulldigest = mur:result() +mur:update('1234') +mur:result() +mur_new = mur:copy() +mur_new:update('1234') +mur_new:result() ~= mur:result() +mur:clear() +nulldigest == mur:result() +mur = digest.murmur.new{seed=14} +mur:update('1234') +mur:result() +mur, mur_new, nulldigest = nil, nil, nil + digest = nil