diff options
Diffstat (limited to 'ext/hash/hash_xxhash.c')
-rw-r--r-- | ext/hash/hash_xxhash.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c new file mode 100644 index 0000000000..8ce5fcfc7f --- /dev/null +++ b/ext/hash/hash_xxhash.c @@ -0,0 +1,288 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php_hash.h" +#include "php_hash_xxhash.h" + +static int php_hash_xxh32_unserialize( + php_hashcontext_object *hash, zend_long magic, const zval *zv); +static int php_hash_xxh64_unserialize( + php_hashcontext_object *hash, zend_long magic, const zval *zv); + +const php_hash_ops php_hash_xxh32_ops = { + "xxh32", + (php_hash_init_func_t) PHP_XXH32Init, + (php_hash_update_func_t) PHP_XXH32Update, + (php_hash_final_func_t) PHP_XXH32Final, + (php_hash_copy_func_t) PHP_XXH32Copy, + php_hash_serialize, + php_hash_xxh32_unserialize, + PHP_XXH32_SPEC, + 4, + 4, + sizeof(PHP_XXH32_CTX), + 0 +}; + +PHP_HASH_API void PHP_XXH32Init(PHP_XXH32_CTX *ctx, HashTable *args) +{ + /* XXH32_createState() is not used intentionally. */ + memset(&ctx->s, 0, sizeof ctx->s); + + if (args) { + zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1); + /* This might be a bit too restrictive, but thinking that a seed might be set + once and for all, it should be done a clean way. */ + if (seed && IS_LONG == Z_TYPE_P(seed)) { + XXH32_reset(&ctx->s, (XXH32_hash_t)Z_LVAL_P(seed)); + } else { + XXH32_reset(&ctx->s, 0); + } + } else { + XXH32_reset(&ctx->s, 0); + } +} + +PHP_HASH_API void PHP_XXH32Update(PHP_XXH32_CTX *ctx, const unsigned char *in, size_t len) +{ + XXH32_update(&ctx->s, in, len); +} + +PHP_HASH_API void PHP_XXH32Final(unsigned char digest[4], PHP_XXH32_CTX *ctx) +{ + XXH32_hash_t const h = XXH32_digest(&ctx->s); + + digest[0] = (unsigned char)((h >> 24) & 0xff); + digest[1] = (unsigned char)((h >> 16) & 0xff); + digest[2] = (unsigned char)((h >> 8) & 0xff); + digest[3] = (unsigned char)(h & 0xff); +} + +PHP_HASH_API int PHP_XXH32Copy(const php_hash_ops *ops, PHP_XXH32_CTX *orig_context, PHP_XXH32_CTX *copy_context) +{ + copy_context->s = orig_context->s; + return SUCCESS; +} + +static int php_hash_xxh32_unserialize( + php_hashcontext_object *hash, zend_long magic, const zval *zv) +{ + PHP_XXH32_CTX *ctx = (PHP_XXH32_CTX *) hash->context; + int r = FAILURE; + if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC + && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH32_SPEC)) == SUCCESS + && ctx->s.memsize < 16) { + return SUCCESS; + } else { + return r != SUCCESS ? r : -2000; + } +} + +const php_hash_ops php_hash_xxh64_ops = { + "xxh64", + (php_hash_init_func_t) PHP_XXH64Init, + (php_hash_update_func_t) PHP_XXH64Update, + (php_hash_final_func_t) PHP_XXH64Final, + (php_hash_copy_func_t) PHP_XXH64Copy, + php_hash_serialize, + php_hash_xxh64_unserialize, + PHP_XXH64_SPEC, + 8, + 8, + sizeof(PHP_XXH64_CTX), + 0 +}; + +PHP_HASH_API void PHP_XXH64Init(PHP_XXH64_CTX *ctx, HashTable *args) +{ + /* XXH64_createState() is not used intentionally. */ + memset(&ctx->s, 0, sizeof ctx->s); + + if (args) { + zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1); + /* This might be a bit too restrictive, but thinking that a seed might be set + once and for all, it should be done a clean way. */ + if (seed && IS_LONG == Z_TYPE_P(seed)) { + XXH64_reset(&ctx->s, (XXH64_hash_t)Z_LVAL_P(seed)); + } else { + XXH64_reset(&ctx->s, 0); + } + } else { + XXH64_reset(&ctx->s, 0); + } +} + +PHP_HASH_API void PHP_XXH64Update(PHP_XXH64_CTX *ctx, const unsigned char *in, size_t len) +{ + XXH64_update(&ctx->s, in, len); +} + +PHP_HASH_API void PHP_XXH64Final(unsigned char digest[8], PHP_XXH64_CTX *ctx) +{ + XXH64_hash_t const h = XXH64_digest(&ctx->s); + + digest[0] = (unsigned char)((h >> 56) & 0xff); + digest[1] = (unsigned char)((h >> 48) & 0xff); + digest[2] = (unsigned char)((h >> 40) & 0xff); + digest[3] = (unsigned char)((h >> 32) & 0xff); + digest[4] = (unsigned char)((h >> 24) & 0xff); + digest[5] = (unsigned char)((h >> 16) & 0xff); + digest[6] = (unsigned char)((h >> 8) & 0xff); + digest[7] = (unsigned char)(h & 0xff); +} + +PHP_HASH_API int PHP_XXH64Copy(const php_hash_ops *ops, PHP_XXH64_CTX *orig_context, PHP_XXH64_CTX *copy_context) +{ + copy_context->s = orig_context->s; + return SUCCESS; +} + +const php_hash_ops php_hash_xxh3_64_ops = { + "xxh3", + (php_hash_init_func_t) PHP_XXH3_64_Init, + (php_hash_update_func_t) PHP_XXH3_64_Update, + (php_hash_final_func_t) PHP_XXH3_64_Final, + (php_hash_copy_func_t) PHP_XXH3_64_Copy, + php_hash_serialize, + php_hash_unserialize, + NULL, + 8, + 8, + sizeof(PHP_XXH3_64_CTX), + 0 +}; + +PHP_HASH_API void PHP_XXH3_64_Init(PHP_XXH3_64_CTX *ctx, HashTable *args) +{ + /* TODO integrate also XXH3_64bits_reset_withSecret(). */ + XXH64_hash_t seed = 0; + + if (args) { + zval *_seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1); + /* This might be a bit too restrictive, but thinking that a seed might be set + once and for all, it should be done a clean way. */ + if (_seed && IS_LONG == Z_TYPE_P(_seed)) { + seed = (XXH64_hash_t)Z_LVAL_P(_seed); + } + } + + XXH3_64bits_reset_withSeed(&ctx->s, seed); +} + +PHP_HASH_API void PHP_XXH3_64_Update(PHP_XXH3_64_CTX *ctx, const unsigned char *in, size_t len) +{ + XXH3_64bits_update(&ctx->s, in, len); +} + +PHP_HASH_API void PHP_XXH3_64_Final(unsigned char digest[8], PHP_XXH3_64_CTX *ctx) +{ + XXH64_hash_t const h = XXH3_64bits_digest(&ctx->s); + + digest[0] = (unsigned char)((h >> 56) & 0xff); + digest[1] = (unsigned char)((h >> 48) & 0xff); + digest[2] = (unsigned char)((h >> 40) & 0xff); + digest[3] = (unsigned char)((h >> 32) & 0xff); + digest[4] = (unsigned char)((h >> 24) & 0xff); + digest[5] = (unsigned char)((h >> 16) & 0xff); + digest[6] = (unsigned char)((h >> 8) & 0xff); + digest[7] = (unsigned char)(h & 0xff); +} + +PHP_HASH_API int PHP_XXH3_64_Copy(const php_hash_ops *ops, PHP_XXH3_64_CTX *orig_context, PHP_XXH3_64_CTX *copy_context) +{ + copy_context->s = orig_context->s; + return SUCCESS; +} + +static int php_hash_xxh64_unserialize( + php_hashcontext_object *hash, zend_long magic, const zval *zv) +{ + PHP_XXH64_CTX *ctx = (PHP_XXH64_CTX *) hash->context; + int r = FAILURE; + if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC + && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH64_SPEC)) == SUCCESS + && ctx->s.memsize < 32) { + return SUCCESS; + } else { + return r != SUCCESS ? r : -2000; + } +} + +const php_hash_ops php_hash_xxh3_128_ops = { + "xxh128", + (php_hash_init_func_t) PHP_XXH3_128_Init, + (php_hash_update_func_t) PHP_XXH3_128_Update, + (php_hash_final_func_t) PHP_XXH3_128_Final, + (php_hash_copy_func_t) PHP_XXH3_128_Copy, + php_hash_serialize, + php_hash_unserialize, + NULL, + 16, + 8, + sizeof(PHP_XXH3_128_CTX), + 0 +}; + +PHP_HASH_API void PHP_XXH3_128_Init(PHP_XXH3_128_CTX *ctx, HashTable *args) +{ + /* TODO integrate also XXH3_128__64bits_reset_withSecret(). */ + XXH64_hash_t seed = 0; + + if (args) { + zval *_seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1); + /* This might be a bit too restrictive, but thinking that a seed might be set + once and for all, it should be done a clean way. */ + if (_seed && IS_LONG == Z_TYPE_P(_seed)) { + seed = (XXH64_hash_t)Z_LVAL_P(_seed); + } + } + + XXH3_128bits_reset_withSeed(&ctx->s, seed); +} + +PHP_HASH_API void PHP_XXH3_128_Update(PHP_XXH3_128_CTX *ctx, const unsigned char *in, size_t len) +{ + XXH3_128bits_update(&ctx->s, in, len); +} + +PHP_HASH_API void PHP_XXH3_128_Final(unsigned char digest[16], PHP_XXH3_128_CTX *ctx) +{ + XXH128_hash_t const h = XXH3_128bits_digest(&ctx->s); + + digest[0] = (unsigned char)((h.high64 >> 56) & 0xff); + digest[1] = (unsigned char)((h.high64 >> 48) & 0xff); + digest[2] = (unsigned char)((h.high64 >> 40) & 0xff); + digest[3] = (unsigned char)((h.high64 >> 32) & 0xff); + digest[4] = (unsigned char)((h.high64 >> 24) & 0xff); + digest[5] = (unsigned char)((h.high64 >> 16) & 0xff); + digest[6] = (unsigned char)((h.high64 >> 8) & 0xff); + digest[7] = (unsigned char)(h.high64 & 0xff); + digest[8] = (unsigned char)((h.low64 >> 56) & 0xff); + digest[9] = (unsigned char)((h.low64 >> 48) & 0xff); + digest[10] = (unsigned char)((h.low64 >> 40) & 0xff); + digest[11] = (unsigned char)((h.low64 >> 32) & 0xff); + digest[12] = (unsigned char)((h.low64 >> 24) & 0xff); + digest[13] = (unsigned char)((h.low64 >> 16) & 0xff); + digest[14] = (unsigned char)((h.low64 >> 8) & 0xff); + digest[15] = (unsigned char)(h.low64 & 0xff); +} + +PHP_HASH_API int PHP_XXH3_128_Copy(const php_hash_ops *ops, PHP_XXH3_128_CTX *orig_context, PHP_XXH3_128_CTX *copy_context) +{ + copy_context->s = orig_context->s; + return SUCCESS; +} + |