Merge branch 'master' of https://github.com/odin-lang/Odin
This commit is contained in:
commit
519308a16a
7 files changed
+7525
-1851
No files matched your search
@@ -45,12 +45,12 @@ Error :: enum {
|
|||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
XXH_DISABLE_PREFETCH :: #config(XXH_DISABLE_PREFETCH, false)
|
XXH_DISABLE_PREFETCH :: #config(XXH_DISABLE_PREFETCH, true)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
llvm.prefetch fails code generation on Linux.
|
llvm.prefetch fails code generation on Linux.
|
||||||
*/
|
*/
|
||||||
when !XXH_DISABLE_PREFETCH && ODIN_OS == "windows" {
|
when XXH_DISABLE_PREFETCH {
|
||||||
import "core:sys/llvm"
|
import "core:sys/llvm"
|
||||||
|
|
||||||
prefetch_address :: #force_inline proc(address: rawptr) {
|
prefetch_address :: #force_inline proc(address: rawptr) {
|
||||||
@@ -60,11 +60,12 @@ when !XXH_DISABLE_PREFETCH && ODIN_OS == "windows" {
|
|||||||
ptr := rawptr(uintptr(address) + offset)
|
ptr := rawptr(uintptr(address) + offset)
|
||||||
prefetch_address(ptr)
|
prefetch_address(ptr)
|
||||||
}
|
}
|
||||||
|
prefetch :: proc { prefetch_address, prefetch_offset, }
|
||||||
} else {
|
} else {
|
||||||
prefetch_address :: #force_inline proc(address: rawptr) {}
|
prefetch_address :: #force_inline proc(address: rawptr) {}
|
||||||
prefetch_offset :: #force_inline proc(address: rawptr, auto_cast offset: uintptr) {}
|
prefetch_offset :: #force_inline proc(address: rawptr, auto_cast offset: uintptr) {}
|
||||||
}
|
}
|
||||||
prefetch :: proc { prefetch_address, prefetch_offset, }
|
|
||||||
|
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
XXH_rotl32 :: #force_inline proc(x, r: u32) -> (res: u32) {
|
XXH_rotl32 :: #force_inline proc(x, r: u32) -> (res: u32) {
|
||||||
|
|||||||
+641
-126
@@ -8,6 +8,7 @@
|
|||||||
Jeroen van Rijn: Initial implementation.
|
Jeroen van Rijn: Initial implementation.
|
||||||
*/
|
*/
|
||||||
package xxhash
|
package xxhash
|
||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
/* *********************************************************************
|
/* *********************************************************************
|
||||||
@@ -16,79 +17,14 @@ import "core:intrinsics"
|
|||||||
************************************************************************
|
************************************************************************
|
||||||
* One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while
|
* One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while
|
||||||
* remaining a true 64-bit/128-bit hash function.
|
* remaining a true 64-bit/128-bit hash function.
|
||||||
*
|
|
||||||
* This is done by prioritizing a subset of 64-bit operations that can be
|
|
||||||
* emulated without too many steps on the average 32-bit machine.
|
|
||||||
*
|
|
||||||
* For example, these two lines seem similar, and run equally fast on 64-bit:
|
|
||||||
*
|
|
||||||
* xxh_u64 x;
|
|
||||||
* x ^= (x >> 47); // good
|
|
||||||
* x ^= (x >> 13); // bad
|
|
||||||
*
|
|
||||||
* However, to a 32-bit machine, there is a major difference.
|
|
||||||
*
|
|
||||||
* x ^= (x >> 47) looks like this:
|
|
||||||
*
|
|
||||||
* x.lo ^= (x.hi >> (47 - 32));
|
|
||||||
*
|
|
||||||
* while x ^= (x >> 13) looks like this:
|
|
||||||
*
|
|
||||||
* // note: funnel shifts are not usually cheap.
|
|
||||||
* x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13));
|
|
||||||
* x.hi ^= (x.hi >> 13);
|
|
||||||
*
|
|
||||||
* The first one is significantly faster than the second, simply because the
|
|
||||||
* shift is larger than 32. This means:
|
|
||||||
* - All the bits we need are in the upper 32 bits, so we can ignore the lower
|
|
||||||
* 32 bits in the shift.
|
|
||||||
* - The shift result will always fit in the lower 32 bits, and therefore,
|
|
||||||
* we can ignore the upper 32 bits in the xor.
|
|
||||||
*
|
|
||||||
* Thanks to this optimization, XXH3 only requires these features to be efficient:
|
|
||||||
*
|
|
||||||
* - Usable unaligned access
|
|
||||||
* - A 32-bit or 64-bit ALU
|
|
||||||
* - If 32-bit, a decent ADC instruction
|
|
||||||
* - A 32 or 64-bit multiply with a 64-bit result
|
|
||||||
* - For the 128-bit variant, a decent byteswap helps short inputs.
|
|
||||||
*
|
|
||||||
* The first two are already required by XXH32, and almost all 32-bit and 64-bit
|
|
||||||
* platforms which can run XXH32 can run XXH3 efficiently.
|
|
||||||
*
|
|
||||||
* Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one
|
|
||||||
* notable exception.
|
|
||||||
*
|
|
||||||
* First of all, Thumb-1 lacks support for the UMULL instruction which
|
|
||||||
* performs the important long multiply. This means numerous __aeabi_lmul
|
|
||||||
* calls.
|
|
||||||
*
|
|
||||||
* Second of all, the 8 functional registers are just not enough.
|
|
||||||
* Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need
|
|
||||||
* Lo registers, and this shuffling results in thousands more MOVs than A32.
|
|
||||||
*
|
|
||||||
* A32 and T32 don't have this limitation. They can access all 14 registers,
|
|
||||||
* do a 32->64 multiply with UMULL, and the flexible operand allowing free
|
|
||||||
* shifts is helpful, too.
|
|
||||||
*
|
|
||||||
* Therefore, we do a quick sanity check.
|
|
||||||
*
|
|
||||||
* If compiling Thumb-1 for a target which supports ARM instructions, we will
|
|
||||||
* emit a warning, as it is not a "sane" platform to compile for.
|
|
||||||
*
|
|
||||||
* Usually, if this happens, it is because of an accident and you probably need
|
|
||||||
* to specify -march, as you likely meant to compile for a newer architecture.
|
|
||||||
*
|
|
||||||
* Credit: large sections of the vectorial and asm source code paths
|
|
||||||
* have been contributed by @easyaspi314
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
XXH_ACC_ALIGN :: 8 /* scalar */
|
|
||||||
|
|
||||||
/* ==========================================
|
/* ==========================================
|
||||||
* XXH3 default settings
|
* XXH3 default settings
|
||||||
* ========================================== */
|
* ========================================== */
|
||||||
|
|
||||||
|
XXH_ACC_ALIGN :: 8 /* scalar */
|
||||||
|
|
||||||
XXH3_SECRET_SIZE_MIN :: 136
|
XXH3_SECRET_SIZE_MIN :: 136
|
||||||
XXH_SECRET_DEFAULT_SIZE :: max(XXH3_SECRET_SIZE_MIN, #config(XXH_SECRET_DEFAULT_SIZE, 192))
|
XXH_SECRET_DEFAULT_SIZE :: max(XXH3_SECRET_SIZE_MIN, #config(XXH_SECRET_DEFAULT_SIZE, 192))
|
||||||
|
|
||||||
@@ -129,16 +65,6 @@ XXH128_hash_t :: struct #raw_union {
|
|||||||
}
|
}
|
||||||
#assert(size_of(xxh_u128) == size_of(XXH128_hash_t))
|
#assert(size_of(xxh_u128) == size_of(XXH128_hash_t))
|
||||||
|
|
||||||
@(optimization_mode="speed")
|
|
||||||
XXH_mul_32_to_64 :: #force_inline proc(x, y: xxh_u32) -> (res: xxh_u64) {
|
|
||||||
return u64(x) * u64(y)
|
|
||||||
}
|
|
||||||
|
|
||||||
@(optimization_mode="speed")
|
|
||||||
XXH_mul_64_to_128 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_u128) {
|
|
||||||
return xxh_u128(lhs) * xxh_u128(rhs)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The reason for the separate function is to prevent passing too many structs
|
The reason for the separate function is to prevent passing too many structs
|
||||||
around by value. This will hopefully inline the multiply, but we don't force it.
|
around by value. This will hopefully inline the multiply, but we don't force it.
|
||||||
@@ -148,9 +74,8 @@ XXH_mul_64_to_128 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_u128) {
|
|||||||
*/
|
*/
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
XXH_mul_64_to_128_fold_64 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_u64) {
|
XXH_mul_64_to_128_fold_64 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_u64) {
|
||||||
t := XXH128_hash_t{}
|
t := u128(lhs) * u128(rhs)
|
||||||
t.h = #force_inline XXH_mul_64_to_128(lhs, rhs)
|
return u64(t & 0xFFFFFFFFFFFFFFFF) ~ u64(t >> 64)
|
||||||
return t.low ~ t.high
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
@@ -241,7 +166,7 @@ XXH3_len_4to8_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u6
|
|||||||
|
|
||||||
/* Shift len to the left to ensure it is even, this avoids even multiplies. */
|
/* Shift len to the left to ensure it is even, this avoids even multiplies. */
|
||||||
m128 := XXH128_hash_t{
|
m128 := XXH128_hash_t{
|
||||||
h = XXH_mul_64_to_128(keyed, u64(XXH_PRIME64_1) + (u64(length) << 2)),
|
h = u128(keyed) * (XXH_PRIME64_1 + u128(length) << 2),
|
||||||
}
|
}
|
||||||
m128.high += (m128.low << 1)
|
m128.high += (m128.low << 1)
|
||||||
m128.low ~= (m128.high >> 3)
|
m128.low ~= (m128.high >> 3)
|
||||||
@@ -265,7 +190,7 @@ XXH3_len_9to16_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u
|
|||||||
input_lo := XXH64_read64(input[0:])
|
input_lo := XXH64_read64(input[0:])
|
||||||
input_hi := XXH64_read64(input[length - 8:])
|
input_hi := XXH64_read64(input[length - 8:])
|
||||||
m128 := XXH128_hash_t{
|
m128 := XXH128_hash_t{
|
||||||
h = XXH_mul_64_to_128(input_lo ~ input_hi ~ bitflipl, XXH_PRIME64_1),
|
h = u128(input_lo ~ input_hi ~ bitflipl) * XXH_PRIME64_1,
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Put len in the middle of m128 to ensure that the length gets mixed to
|
* Put len in the middle of m128 to ensure that the length gets mixed to
|
||||||
@@ -277,49 +202,14 @@ XXH3_len_9to16_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u
|
|||||||
* Add the high 32 bits of input_hi to the high 32 bits of m128, then
|
* Add the high 32 bits of input_hi to the high 32 bits of m128, then
|
||||||
* add the long product of the low 32 bits of input_hi and XXH_XXH_PRIME32_2 to
|
* add the long product of the low 32 bits of input_hi and XXH_XXH_PRIME32_2 to
|
||||||
* the high 64 bits of m128.
|
* the high 64 bits of m128.
|
||||||
*
|
|
||||||
* The best approach to this operation is different on 32-bit and 64-bit.
|
|
||||||
*/
|
*/
|
||||||
when size_of(rawptr) == 4 { /* 32-bit */
|
m128.high += input_hi + u64(u32(input_hi)) * u64(XXH_PRIME32_2 - 1)
|
||||||
/*
|
|
||||||
* 32-bit optimized version, which is more readable.
|
|
||||||
*
|
|
||||||
* On 32-bit, it removes an ADC and delays a dependency between the two
|
|
||||||
* halves of m128.high64, but it generates an extra mask on 64-bit.
|
|
||||||
*/
|
|
||||||
m128.high += (input_hi & 0xFFFFFFFF00000000) + XXH_mul_32_to_64(u32(input_hi), XXH_PRIME32_2)
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* 64-bit optimized (albeit more confusing) version.
|
|
||||||
*
|
|
||||||
* Uses some properties of addition and multiplication to remove the mask:
|
|
||||||
*
|
|
||||||
* Let:
|
|
||||||
* a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF)
|
|
||||||
* b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000)
|
|
||||||
* c = XXH_XXH_PRIME32_2
|
|
||||||
*
|
|
||||||
* a + (b * c)
|
|
||||||
* Inverse Property: x + y - x == y
|
|
||||||
* a + (b * (1 + c - 1))
|
|
||||||
* Distributive Property: x * (y + z) == (x * y) + (x * z)
|
|
||||||
* a + (b * 1) + (b * (c - 1))
|
|
||||||
* Identity Property: x * 1 == x
|
|
||||||
* a + b + (b * (c - 1))
|
|
||||||
*
|
|
||||||
* Substitute a, b, and c:
|
|
||||||
* input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_XXH_PRIME32_2 - 1))
|
|
||||||
*
|
|
||||||
* Since input_hi.hi + input_hi.lo == input_hi, we get this:
|
|
||||||
* input_hi + ((xxh_u64)input_hi.lo * (XXH_XXH_PRIME32_2 - 1))
|
|
||||||
*/
|
|
||||||
m128.high += input_hi + XXH_mul_32_to_64(u32(input_hi), XXH_PRIME32_2 - 1)
|
|
||||||
}
|
|
||||||
/* m128 ^= XXH_swap64(m128 >> 64); */
|
/* m128 ^= XXH_swap64(m128 >> 64); */
|
||||||
m128.low ~= byte_swap(m128.high)
|
m128.low ~= byte_swap(m128.high)
|
||||||
{ /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */
|
{ /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */
|
||||||
h128 := XXH128_hash_t{
|
h128 := XXH128_hash_t{
|
||||||
h = XXH_mul_64_to_128(m128.low, XXH_PRIME64_2),
|
h = u128(m128.low) * XXH_PRIME64_2,
|
||||||
}
|
}
|
||||||
h128.high += m128.high * XXH_PRIME64_2
|
h128.high += m128.high * XXH_PRIME64_2
|
||||||
h128.low = XXH3_avalanche(h128.low)
|
h128.low = XXH3_avalanche(h128.low)
|
||||||
@@ -505,9 +395,9 @@ XXH3_hashLong_128b_withSeed_internal :: #force_inline proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
secret := [XXH_SECRET_DEFAULT_SIZE]u8{}
|
_secret := [XXH_SECRET_DEFAULT_SIZE]u8{}
|
||||||
f_initSec(secret[:], seed)
|
f_initSec(_secret[:], seed)
|
||||||
return XXH3_hashLong_128b_internal(input, secret[:], f_acc512, f_scramble)
|
return XXH3_hashLong_128b_internal(input, _secret[:], f_acc512, f_scramble)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,11 +436,143 @@ XXH3_128bits_internal :: #force_inline proc(
|
|||||||
|
|
||||||
/* === Public XXH128 API === */
|
/* === Public XXH128 API === */
|
||||||
|
|
||||||
XXH3_128bits :: proc(input: []u8) -> (hash: XXH3_128_hash) {
|
XXH3_128_with_seed :: proc(input: []u8, seed := XXH3_128_DEFAULT_SEED) -> (hash: XXH3_128_hash) {
|
||||||
k := XXH3_kSecret
|
k := XXH3_kSecret
|
||||||
return XXH3_128bits_internal(input, XXH3_128_DEFAULT_SEED, k[:], XXH3_hashLong_128b_default)
|
return XXH3_128bits_internal(input, seed, k[:], XXH3_hashLong_128b_withSeed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XXH3_128_with_secret :: proc(input: []u8, secret: []u8) -> (hash: XXH3_128_hash) {
|
||||||
|
return XXH3_128bits_internal(input, 0, secret, XXH3_hashLong_128b_withSecret)
|
||||||
|
}
|
||||||
|
XXH3_128 :: proc { XXH3_128_with_seed, XXH3_128_with_secret }
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/* === XXH3 128-bit streaming === */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All the functions are actually the same as for 64-bit streaming variant.
|
||||||
|
* The only difference is the finalization routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_128bits_reset(XXH3_state_t* statePtr)
|
||||||
|
{
|
||||||
|
if (statePtr == NULL) return XXH_ERROR;
|
||||||
|
XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize)
|
||||||
|
{
|
||||||
|
if (statePtr == NULL) return XXH_ERROR;
|
||||||
|
XXH3_reset_internal(statePtr, 0, secret, secretSize);
|
||||||
|
if (secret == NULL) return XXH_ERROR;
|
||||||
|
if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed)
|
||||||
|
{
|
||||||
|
if (statePtr == NULL) return XXH_ERROR;
|
||||||
|
if (seed==0) return XXH3_128bits_reset(statePtr);
|
||||||
|
if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed);
|
||||||
|
XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len)
|
||||||
|
{
|
||||||
|
return XXH3_update(state, (const xxh_u8*)input, len,
|
||||||
|
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state)
|
||||||
|
{
|
||||||
|
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
|
||||||
|
if (state->totalLen > XXH3_MIDSIZE_MAX) {
|
||||||
|
XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
|
||||||
|
XXH3_digest_long(acc, state, secret);
|
||||||
|
XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
|
||||||
|
{ XXH128_hash_t h128;
|
||||||
|
h128.low64 = XXH3_mergeAccs(acc,
|
||||||
|
secret + XXH_SECRET_MERGEACCS_START,
|
||||||
|
(xxh_u64)state->totalLen * XXH_PRIME64_1);
|
||||||
|
h128.high64 = XXH3_mergeAccs(acc,
|
||||||
|
secret + state->secretLimit + XXH_STRIPE_LEN
|
||||||
|
- sizeof(acc) - XXH_SECRET_MERGEACCS_START,
|
||||||
|
~((xxh_u64)state->totalLen * XXH_PRIME64_2));
|
||||||
|
return h128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* len <= XXH3_MIDSIZE_MAX : short code */
|
||||||
|
if (state->seed)
|
||||||
|
return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);
|
||||||
|
return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen),
|
||||||
|
secret, state->secretLimit + XXH_STRIPE_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 128-bit utility functions */
|
||||||
|
|
||||||
|
#include <string.h> /* memcmp, memcpy */
|
||||||
|
|
||||||
|
/* return : 1 is equal, 0 if different */
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2)
|
||||||
|
{
|
||||||
|
/* note : XXH128_hash_t is compact, it has no padding byte */
|
||||||
|
return !(memcmp(&h1, &h2, sizeof(h1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This prototype is compatible with stdlib's qsort().
|
||||||
|
* return : >0 if *h128_1 > *h128_2
|
||||||
|
* <0 if *h128_1 < *h128_2
|
||||||
|
* =0 if *h128_1 == *h128_2 */
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2)
|
||||||
|
{
|
||||||
|
XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1;
|
||||||
|
XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2;
|
||||||
|
int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64);
|
||||||
|
/* note : bets that, in most cases, hash values are different */
|
||||||
|
if (hcmp) return hcmp;
|
||||||
|
return (h1.low64 > h2.low64) - (h2.low64 > h1.low64);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*====== Canonical representation ======*/
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API void
|
||||||
|
XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash)
|
||||||
|
{
|
||||||
|
XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t));
|
||||||
|
if (XXH_CPU_LITTLE_ENDIAN) {
|
||||||
|
hash.high64 = XXH_swap64(hash.high64);
|
||||||
|
hash.low64 = XXH_swap64(hash.low64);
|
||||||
|
}
|
||||||
|
memcpy(dst, &hash.high64, sizeof(hash.high64));
|
||||||
|
memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH128_hash_t
|
||||||
|
XXH128_hashFromCanonical(const XXH128_canonical_t* src)
|
||||||
|
{
|
||||||
|
XXH128_hash_t h;
|
||||||
|
h.high64 = XXH_readBE64(src);
|
||||||
|
h.low64 = XXH_readBE64(src->digest + 8);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -810,7 +832,7 @@ XXH3_accumulate_512_scalar :: #force_inline proc(acc: []xxh_u64, input: []u8, se
|
|||||||
data_val := XXH64_read64(xinput[8 * i:])
|
data_val := XXH64_read64(xinput[8 * i:])
|
||||||
data_key := data_val ~ XXH64_read64(xsecret[8 * i:])
|
data_key := data_val ~ XXH64_read64(xsecret[8 * i:])
|
||||||
xacc[i ~ 1] += data_val /* swap adjacent lanes */
|
xacc[i ~ 1] += data_val /* swap adjacent lanes */
|
||||||
xacc[i ] += XXH_mul_32_to_64(u32(data_key & 0xFFFFFFFF), u32(data_key >> 32))
|
xacc[i ] += u64(u32(data_key)) * u64(data_key >> 32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,3 +934,496 @@ XXH3_mergeAccs :: #force_inline proc(acc: []xxh_u64, secret: []u8, start: xxh_u6
|
|||||||
}
|
}
|
||||||
return XXH3_avalanche(result64)
|
return XXH3_avalanche(result64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
XXH_FORCE_INLINE XXH64_hash_t
|
||||||
|
XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len,
|
||||||
|
const void* XXH_RESTRICT secret, size_t secretSize,
|
||||||
|
XXH3_f_accumulate_512 f_acc512,
|
||||||
|
XXH3_f_scrambleAcc f_scramble)
|
||||||
|
{
|
||||||
|
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
|
||||||
|
|
||||||
|
XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble);
|
||||||
|
|
||||||
|
/* converge into final hash */
|
||||||
|
XXH_STATIC_ASSERT(sizeof(acc) == 64);
|
||||||
|
/* do not align on 8, so that the secret is different from the accumulator */
|
||||||
|
#define XXH_SECRET_MERGEACCS_START 11
|
||||||
|
XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
|
||||||
|
return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's important for performance that XXH3_hashLong is not inlined.
|
||||||
|
*/
|
||||||
|
XXH_NO_INLINE XXH64_hash_t
|
||||||
|
XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len,
|
||||||
|
XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
|
||||||
|
{
|
||||||
|
(void)seed64;
|
||||||
|
return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's important for performance that XXH3_hashLong is not inlined.
|
||||||
|
* Since the function is not inlined, the compiler may not be able to understand that,
|
||||||
|
* in some scenarios, its `secret` argument is actually a compile time constant.
|
||||||
|
* This variant enforces that the compiler can detect that,
|
||||||
|
* and uses this opportunity to streamline the generated code for better performance.
|
||||||
|
*/
|
||||||
|
XXH_NO_INLINE XXH64_hash_t
|
||||||
|
XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len,
|
||||||
|
XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
|
||||||
|
{
|
||||||
|
(void)seed64; (void)secret; (void)secretLen;
|
||||||
|
return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXH3_hashLong_64b_withSeed():
|
||||||
|
* Generate a custom key based on alteration of default XXH3_kSecret with the seed,
|
||||||
|
* and then use this key for long mode hashing.
|
||||||
|
*
|
||||||
|
* This operation is decently fast but nonetheless costs a little bit of time.
|
||||||
|
* Try to avoid it whenever possible (typically when seed==0).
|
||||||
|
*
|
||||||
|
* It's important for performance that XXH3_hashLong is not inlined. Not sure
|
||||||
|
* why (uop cache maybe?), but the difference is large and easily measurable.
|
||||||
|
*/
|
||||||
|
XXH_FORCE_INLINE XXH64_hash_t
|
||||||
|
XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len,
|
||||||
|
XXH64_hash_t seed,
|
||||||
|
XXH3_f_accumulate_512 f_acc512,
|
||||||
|
XXH3_f_scrambleAcc f_scramble,
|
||||||
|
XXH3_f_initCustomSecret f_initSec)
|
||||||
|
{
|
||||||
|
if (seed == 0)
|
||||||
|
return XXH3_hashLong_64b_internal(input, len,
|
||||||
|
XXH3_kSecret, sizeof(XXH3_kSecret),
|
||||||
|
f_acc512, f_scramble);
|
||||||
|
{ XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
|
||||||
|
f_initSec(secret, seed);
|
||||||
|
return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret),
|
||||||
|
f_acc512, f_scramble);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's important for performance that XXH3_hashLong is not inlined.
|
||||||
|
*/
|
||||||
|
XXH_NO_INLINE XXH64_hash_t
|
||||||
|
XXH3_hashLong_64b_withSeed(const void* input, size_t len,
|
||||||
|
XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen)
|
||||||
|
{
|
||||||
|
(void)secret; (void)secretLen;
|
||||||
|
return XXH3_hashLong_64b_withSeed_internal(input, len, seed,
|
||||||
|
XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t,
|
||||||
|
XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t);
|
||||||
|
|
||||||
|
XXH_FORCE_INLINE XXH64_hash_t
|
||||||
|
XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len,
|
||||||
|
XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen,
|
||||||
|
XXH3_hashLong64_f f_hashLong)
|
||||||
|
{
|
||||||
|
XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);
|
||||||
|
/*
|
||||||
|
* If an action is to be taken if `secretLen` condition is not respected,
|
||||||
|
* it should be done here.
|
||||||
|
* For now, it's a contract pre-condition.
|
||||||
|
* Adding a check and a branch here would cost performance at every hash.
|
||||||
|
* Also, note that function signature doesn't offer room to return an error.
|
||||||
|
*/
|
||||||
|
if (len <= 16)
|
||||||
|
return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64);
|
||||||
|
if (len <= 128)
|
||||||
|
return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
|
||||||
|
if (len <= XXH3_MIDSIZE_MAX)
|
||||||
|
return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
|
||||||
|
return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* === Public entry point === */
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len)
|
||||||
|
{
|
||||||
|
return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t
|
||||||
|
XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize)
|
||||||
|
{
|
||||||
|
return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t
|
||||||
|
XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed)
|
||||||
|
{
|
||||||
|
return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* === XXH3 streaming === */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Malloc's a pointer that is always aligned to align.
|
||||||
|
*
|
||||||
|
* This must be freed with `XXH_alignedFree()`.
|
||||||
|
*
|
||||||
|
* malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte
|
||||||
|
* alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2
|
||||||
|
* or on 32-bit, the 16 byte aligned loads in SSE2 and NEON.
|
||||||
|
*
|
||||||
|
* This underalignment previously caused a rather obvious crash which went
|
||||||
|
* completely unnoticed due to XXH3_createState() not actually being tested.
|
||||||
|
* Credit to RedSpah for noticing this bug.
|
||||||
|
*
|
||||||
|
* The alignment is done manually: Functions like posix_memalign or _mm_malloc
|
||||||
|
* are avoided: To maintain portability, we would have to write a fallback
|
||||||
|
* like this anyways, and besides, testing for the existence of library
|
||||||
|
* functions without relying on external build tools is impossible.
|
||||||
|
*
|
||||||
|
* The method is simple: Overallocate, manually align, and store the offset
|
||||||
|
* to the original behind the returned pointer.
|
||||||
|
*
|
||||||
|
* Align must be a power of 2 and 8 <= align <= 128.
|
||||||
|
*/
|
||||||
|
static void* XXH_alignedMalloc(size_t s, size_t align)
|
||||||
|
{
|
||||||
|
XXH_ASSERT(align <= 128 && align >= 8); /* range check */
|
||||||
|
XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */
|
||||||
|
XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */
|
||||||
|
{ /* Overallocate to make room for manual realignment and an offset byte */
|
||||||
|
xxh_u8* base = (xxh_u8*)XXH_malloc(s + align);
|
||||||
|
if (base != NULL) {
|
||||||
|
/*
|
||||||
|
* Get the offset needed to align this pointer.
|
||||||
|
*
|
||||||
|
* Even if the returned pointer is aligned, there will always be
|
||||||
|
* at least one byte to store the offset to the original pointer.
|
||||||
|
*/
|
||||||
|
size_t offset = align - ((size_t)base & (align - 1)); /* base % align */
|
||||||
|
/* Add the offset for the now-aligned pointer */
|
||||||
|
xxh_u8* ptr = base + offset;
|
||||||
|
|
||||||
|
XXH_ASSERT((size_t)ptr % align == 0);
|
||||||
|
|
||||||
|
/* Store the offset immediately before the returned pointer. */
|
||||||
|
ptr[-1] = (xxh_u8)offset;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass
|
||||||
|
* normal malloc'd pointers, XXH_alignedMalloc has a specific data layout.
|
||||||
|
*/
|
||||||
|
static void XXH_alignedFree(void* p)
|
||||||
|
{
|
||||||
|
if (p != NULL) {
|
||||||
|
xxh_u8* ptr = (xxh_u8*)p;
|
||||||
|
/* Get the offset byte we added in XXH_malloc. */
|
||||||
|
xxh_u8 offset = ptr[-1];
|
||||||
|
/* Free the original malloc'd pointer */
|
||||||
|
xxh_u8* base = ptr - offset;
|
||||||
|
XXH_free(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void)
|
||||||
|
{
|
||||||
|
XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64);
|
||||||
|
if (state==NULL) return NULL;
|
||||||
|
XXH3_INITSTATE(state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr)
|
||||||
|
{
|
||||||
|
XXH_alignedFree(statePtr);
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API void
|
||||||
|
XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state)
|
||||||
|
{
|
||||||
|
memcpy(dst_state, src_state, sizeof(*dst_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
XXH3_reset_internal(XXH3_state_t* statePtr,
|
||||||
|
XXH64_hash_t seed,
|
||||||
|
const void* secret, size_t secretSize)
|
||||||
|
{
|
||||||
|
size_t const initStart = offsetof(XXH3_state_t, bufferedSize);
|
||||||
|
size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart;
|
||||||
|
XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart);
|
||||||
|
XXH_ASSERT(statePtr != NULL);
|
||||||
|
/* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */
|
||||||
|
memset((char*)statePtr + initStart, 0, initLength);
|
||||||
|
statePtr->acc[0] = XXH_XXH_PRIME32_3;
|
||||||
|
statePtr->acc[1] = XXH_PRIME64_1;
|
||||||
|
statePtr->acc[2] = XXH_PRIME64_2;
|
||||||
|
statePtr->acc[3] = XXH_PRIME64_3;
|
||||||
|
statePtr->acc[4] = XXH_PRIME64_4;
|
||||||
|
statePtr->acc[5] = XXH_XXH_PRIME32_2;
|
||||||
|
statePtr->acc[6] = XXH_PRIME64_5;
|
||||||
|
statePtr->acc[7] = XXH_XXH_PRIME32_1;
|
||||||
|
statePtr->seed = seed;
|
||||||
|
statePtr->extSecret = (const unsigned char*)secret;
|
||||||
|
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
|
||||||
|
statePtr->secretLimit = secretSize - XXH_STRIPE_LEN;
|
||||||
|
statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_64bits_reset(XXH3_state_t* statePtr)
|
||||||
|
{
|
||||||
|
if (statePtr == NULL) return XXH_ERROR;
|
||||||
|
XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize)
|
||||||
|
{
|
||||||
|
if (statePtr == NULL) return XXH_ERROR;
|
||||||
|
XXH3_reset_internal(statePtr, 0, secret, secretSize);
|
||||||
|
if (secret == NULL) return XXH_ERROR;
|
||||||
|
if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed)
|
||||||
|
{
|
||||||
|
if (statePtr == NULL) return XXH_ERROR;
|
||||||
|
if (seed==0) return XXH3_64bits_reset(statePtr);
|
||||||
|
if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed);
|
||||||
|
XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note : when XXH3_consumeStripes() is invoked,
|
||||||
|
* there must be a guarantee that at least one more byte must be consumed from input
|
||||||
|
* so that the function can blindly consume all stripes using the "normal" secret segment */
|
||||||
|
XXH_FORCE_INLINE void
|
||||||
|
XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,
|
||||||
|
size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock,
|
||||||
|
const xxh_u8* XXH_RESTRICT input, size_t nbStripes,
|
||||||
|
const xxh_u8* XXH_RESTRICT secret, size_t secretLimit,
|
||||||
|
XXH3_f_accumulate_512 f_acc512,
|
||||||
|
XXH3_f_scrambleAcc f_scramble)
|
||||||
|
{
|
||||||
|
XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */
|
||||||
|
XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock);
|
||||||
|
if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) {
|
||||||
|
/* need a scrambling operation */
|
||||||
|
size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr;
|
||||||
|
size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock;
|
||||||
|
XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512);
|
||||||
|
f_scramble(acc, secret + secretLimit);
|
||||||
|
XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512);
|
||||||
|
*nbStripesSoFarPtr = nbStripesAfterBlock;
|
||||||
|
} else {
|
||||||
|
XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512);
|
||||||
|
*nbStripesSoFarPtr += nbStripes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both XXH3_64bits_update and XXH3_128bits_update use this routine.
|
||||||
|
*/
|
||||||
|
XXH_FORCE_INLINE XXH_errorcode
|
||||||
|
XXH3_update(XXH3_state_t* state,
|
||||||
|
const xxh_u8* input, size_t len,
|
||||||
|
XXH3_f_accumulate_512 f_acc512,
|
||||||
|
XXH3_f_scrambleAcc f_scramble)
|
||||||
|
{
|
||||||
|
if (input==NULL)
|
||||||
|
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
|
||||||
|
return XXH_OK;
|
||||||
|
#else
|
||||||
|
return XXH_ERROR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{ const xxh_u8* const bEnd = input + len;
|
||||||
|
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
|
||||||
|
|
||||||
|
state->totalLen += len;
|
||||||
|
XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE);
|
||||||
|
|
||||||
|
if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { /* fill in tmp buffer */
|
||||||
|
XXH_memcpy(state->buffer + state->bufferedSize, input, len);
|
||||||
|
state->bufferedSize += (XXH32_hash_t)len;
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
/* total input is now > XXH3_INTERNALBUFFER_SIZE */
|
||||||
|
|
||||||
|
#define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN)
|
||||||
|
XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal buffer is partially filled (always, except at beginning)
|
||||||
|
* Complete it, then consume it.
|
||||||
|
*/
|
||||||
|
if (state->bufferedSize) {
|
||||||
|
size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize;
|
||||||
|
XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize);
|
||||||
|
input += loadSize;
|
||||||
|
XXH3_consumeStripes(state->acc,
|
||||||
|
&state->nbStripesSoFar, state->nbStripesPerBlock,
|
||||||
|
state->buffer, XXH3_INTERNALBUFFER_STRIPES,
|
||||||
|
secret, state->secretLimit,
|
||||||
|
f_acc512, f_scramble);
|
||||||
|
state->bufferedSize = 0;
|
||||||
|
}
|
||||||
|
XXH_ASSERT(input < bEnd);
|
||||||
|
|
||||||
|
/* Consume input by a multiple of internal buffer size */
|
||||||
|
if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) {
|
||||||
|
const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE;
|
||||||
|
do {
|
||||||
|
XXH3_consumeStripes(state->acc,
|
||||||
|
&state->nbStripesSoFar, state->nbStripesPerBlock,
|
||||||
|
input, XXH3_INTERNALBUFFER_STRIPES,
|
||||||
|
secret, state->secretLimit,
|
||||||
|
f_acc512, f_scramble);
|
||||||
|
input += XXH3_INTERNALBUFFER_SIZE;
|
||||||
|
} while (input<limit);
|
||||||
|
/* for last partial stripe */
|
||||||
|
memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
|
||||||
|
}
|
||||||
|
XXH_ASSERT(input < bEnd);
|
||||||
|
|
||||||
|
/* Some remaining input (always) : buffer it */
|
||||||
|
XXH_memcpy(state->buffer, input, (size_t)(bEnd-input));
|
||||||
|
state->bufferedSize = (XXH32_hash_t)(bEnd-input);
|
||||||
|
}
|
||||||
|
|
||||||
|
return XXH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH_errorcode
|
||||||
|
XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len)
|
||||||
|
{
|
||||||
|
return XXH3_update(state, (const xxh_u8*)input, len,
|
||||||
|
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XXH_FORCE_INLINE void
|
||||||
|
XXH3_digest_long (XXH64_hash_t* acc,
|
||||||
|
const XXH3_state_t* state,
|
||||||
|
const unsigned char* secret)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Digest on a local copy. This way, the state remains unaltered, and it can
|
||||||
|
* continue ingesting more input afterwards.
|
||||||
|
*/
|
||||||
|
memcpy(acc, state->acc, sizeof(state->acc));
|
||||||
|
if (state->bufferedSize >= XXH_STRIPE_LEN) {
|
||||||
|
size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN;
|
||||||
|
size_t nbStripesSoFar = state->nbStripesSoFar;
|
||||||
|
XXH3_consumeStripes(acc,
|
||||||
|
&nbStripesSoFar, state->nbStripesPerBlock,
|
||||||
|
state->buffer, nbStripes,
|
||||||
|
secret, state->secretLimit,
|
||||||
|
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||||
|
/* last stripe */
|
||||||
|
XXH3_accumulate_512(acc,
|
||||||
|
state->buffer + state->bufferedSize - XXH_STRIPE_LEN,
|
||||||
|
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
|
||||||
|
} else { /* bufferedSize < XXH_STRIPE_LEN */
|
||||||
|
xxh_u8 lastStripe[XXH_STRIPE_LEN];
|
||||||
|
size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize;
|
||||||
|
XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */
|
||||||
|
memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize);
|
||||||
|
memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize);
|
||||||
|
XXH3_accumulate_512(acc,
|
||||||
|
lastStripe,
|
||||||
|
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state)
|
||||||
|
{
|
||||||
|
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
|
||||||
|
if (state->totalLen > XXH3_MIDSIZE_MAX) {
|
||||||
|
XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
|
||||||
|
XXH3_digest_long(acc, state, secret);
|
||||||
|
return XXH3_mergeAccs(acc,
|
||||||
|
secret + XXH_SECRET_MERGEACCS_START,
|
||||||
|
(xxh_u64)state->totalLen * XXH_PRIME64_1);
|
||||||
|
}
|
||||||
|
/* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */
|
||||||
|
if (state->seed)
|
||||||
|
return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);
|
||||||
|
return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen),
|
||||||
|
secret, state->secretLimit + XXH_STRIPE_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x))
|
||||||
|
|
||||||
|
/*! @ingroup xxh3_family */
|
||||||
|
XXH_PUBLIC_API void
|
||||||
|
XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize)
|
||||||
|
{
|
||||||
|
XXH_ASSERT(secretBuffer != NULL);
|
||||||
|
if (customSeedSize == 0) {
|
||||||
|
memcpy(secretBuffer, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XXH_ASSERT(customSeed != NULL);
|
||||||
|
|
||||||
|
{ size_t const segmentSize = sizeof(XXH128_hash_t);
|
||||||
|
size_t const nbSegments = XXH_SECRET_DEFAULT_SIZE / segmentSize;
|
||||||
|
XXH128_canonical_t scrambler;
|
||||||
|
XXH64_hash_t seeds[12];
|
||||||
|
size_t segnb;
|
||||||
|
XXH_ASSERT(nbSegments == 12);
|
||||||
|
XXH_ASSERT(segmentSize * nbSegments == XXH_SECRET_DEFAULT_SIZE); /* exact multiple */
|
||||||
|
XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy customSeed to seeds[], truncating or repeating as necessary.
|
||||||
|
*/
|
||||||
|
{ size_t toFill = XXH_MIN(customSeedSize, sizeof(seeds));
|
||||||
|
size_t filled = toFill;
|
||||||
|
memcpy(seeds, customSeed, toFill);
|
||||||
|
while (filled < sizeof(seeds)) {
|
||||||
|
toFill = XXH_MIN(filled, sizeof(seeds) - filled);
|
||||||
|
memcpy((char*)seeds + filled, seeds, toFill);
|
||||||
|
filled += toFill;
|
||||||
|
} }
|
||||||
|
|
||||||
|
/* generate secret */
|
||||||
|
memcpy(secretBuffer, &scrambler, sizeof(scrambler));
|
||||||
|
for (segnb=1; segnb < nbSegments; segnb++) {
|
||||||
|
size_t const segmentStart = segnb * segmentSize;
|
||||||
|
XXH128_canonical_t segment;
|
||||||
|
XXH128_canonicalFromHash(&segment,
|
||||||
|
XXH128(&scrambler, sizeof(scrambler), XXH64_read64(seeds + segnb) + segnb) );
|
||||||
|
memcpy((char*)secretBuffer + segmentStart, &segment, sizeof(segment));
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
+141
-122
@@ -9,177 +9,196 @@ TEST_count := 0
|
|||||||
TEST_fail := 0
|
TEST_fail := 0
|
||||||
|
|
||||||
when ODIN_TEST {
|
when ODIN_TEST {
|
||||||
expect :: testing.expect
|
expect :: testing.expect
|
||||||
log :: testing.log
|
log :: testing.log
|
||||||
} else {
|
} else {
|
||||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||||
fmt.printf("[%v] ", loc)
|
fmt.printf("[%v] ", loc)
|
||||||
TEST_count += 1
|
TEST_count += 1
|
||||||
if !condition {
|
if !condition {
|
||||||
TEST_fail += 1
|
TEST_fail += 1
|
||||||
fmt.println(" FAIL:", message)
|
fmt.println(" FAIL:", message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.println(" PASS")
|
fmt.println(" PASS")
|
||||||
}
|
}
|
||||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||||
fmt.printf("[%v] ", loc)
|
fmt.printf("[%v] ", loc)
|
||||||
fmt.printf("log: %v\n", v)
|
fmt.printf("log: %v\n", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
t := testing.T{}
|
t := testing.T{}
|
||||||
test_benchmark_runner(&t)
|
test_benchmark_runner(&t)
|
||||||
test_xxhash_vectors(&t)
|
test_xxhash_vectors(&t)
|
||||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Benchmarks
|
Benchmarks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
setup_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
setup_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
||||||
assert(options != nil)
|
assert(options != nil)
|
||||||
|
|
||||||
options.input = make([]u8, options.bytes, allocator)
|
options.input = make([]u8, options.bytes, allocator)
|
||||||
return nil if len(options.input) == options.bytes else .Allocation_Error
|
return nil if len(options.input) == options.bytes else .Allocation_Error
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
teardown_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
||||||
assert(options != nil)
|
assert(options != nil)
|
||||||
|
|
||||||
delete(options.input)
|
delete(options.input)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
benchmark_xxh32 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
benchmark_xxh32 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
||||||
buf := options.input
|
buf := options.input
|
||||||
|
|
||||||
h: u32
|
h: u32
|
||||||
for _ in 0..=options.rounds {
|
for _ in 0..=options.rounds {
|
||||||
h = xxhash.XXH32(buf)
|
h = xxhash.XXH32(buf)
|
||||||
}
|
}
|
||||||
options.count = options.rounds
|
options.count = options.rounds
|
||||||
options.processed = options.rounds * options.bytes
|
options.processed = options.rounds * options.bytes
|
||||||
options.hash = u128(h)
|
options.hash = u128(h)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
benchmark_xxh64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
benchmark_xxh64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
||||||
buf := options.input
|
buf := options.input
|
||||||
|
|
||||||
h: u64
|
h: u64
|
||||||
for _ in 0..=options.rounds {
|
for _ in 0..=options.rounds {
|
||||||
h = xxhash.XXH64(buf)
|
h = xxhash.XXH64(buf)
|
||||||
}
|
}
|
||||||
options.count = options.rounds
|
options.count = options.rounds
|
||||||
options.processed = options.rounds * options.bytes
|
options.processed = options.rounds * options.bytes
|
||||||
options.hash = u128(h)
|
options.hash = u128(h)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
benchmark_xxh3_128 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
benchmark_xxh3_128 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
|
||||||
buf := options.input
|
buf := options.input
|
||||||
|
|
||||||
h: u128
|
h: u128
|
||||||
for _ in 0..=options.rounds {
|
for _ in 0..=options.rounds {
|
||||||
h = xxhash.XXH3_128bits(buf)
|
h = xxhash.XXH3_128(buf)
|
||||||
}
|
}
|
||||||
options.count = options.rounds
|
options.count = options.rounds
|
||||||
options.processed = options.rounds * options.bytes
|
options.processed = options.rounds * options.bytes
|
||||||
options.hash = h
|
options.hash = h
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) {
|
benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) {
|
||||||
fmt.printf("\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n",
|
fmt.printf("\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n",
|
||||||
name,
|
name,
|
||||||
options.rounds,
|
options.rounds,
|
||||||
options.processed,
|
options.processed,
|
||||||
time.duration_nanoseconds(options.duration),
|
time.duration_nanoseconds(options.duration),
|
||||||
options.rounds_per_second,
|
options.rounds_per_second,
|
||||||
options.megabytes_per_second,
|
options.megabytes_per_second,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@test
|
@test
|
||||||
test_benchmark_runner :: proc(t: ^testing.T) {
|
test_benchmark_runner :: proc(t: ^testing.T) {
|
||||||
fmt.println("Starting benchmarks:")
|
fmt.println("Starting benchmarks:")
|
||||||
|
|
||||||
name := "XXH32 100 zero bytes"
|
name := "XXH32 100 zero bytes"
|
||||||
options := &time.Benchmark_Options{
|
options := &time.Benchmark_Options{
|
||||||
rounds = 1_000,
|
rounds = 1_000,
|
||||||
bytes = 100,
|
bytes = 100,
|
||||||
setup = setup_xxhash,
|
setup = setup_xxhash,
|
||||||
bench = benchmark_xxh32,
|
bench = benchmark_xxh32,
|
||||||
teardown = teardown_xxhash,
|
teardown = teardown_xxhash,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := time.benchmark(options, context.allocator)
|
err := time.benchmark(options, context.allocator)
|
||||||
expect(t, err == nil, name)
|
expect(t, err == nil, name)
|
||||||
expect(t, options.hash == 0x85f6413c, name)
|
expect(t, options.hash == 0x85f6413c, name)
|
||||||
benchmark_print(name, options)
|
benchmark_print(name, options)
|
||||||
|
|
||||||
name = "XXH32 1 MiB zero bytes"
|
name = "XXH32 1 MiB zero bytes"
|
||||||
options.bytes = 1_048_576
|
options.bytes = 1_048_576
|
||||||
err = time.benchmark(options, context.allocator)
|
err = time.benchmark(options, context.allocator)
|
||||||
expect(t, err == nil, name)
|
expect(t, err == nil, name)
|
||||||
expect(t, options.hash == 0x9430f97f, name)
|
expect(t, options.hash == 0x9430f97f, name)
|
||||||
benchmark_print(name, options)
|
benchmark_print(name, options)
|
||||||
|
|
||||||
name = "XXH64 100 zero bytes"
|
name = "XXH64 100 zero bytes"
|
||||||
options.bytes = 100
|
options.bytes = 100
|
||||||
options.bench = benchmark_xxh64
|
options.bench = benchmark_xxh64
|
||||||
err = time.benchmark(options, context.allocator)
|
err = time.benchmark(options, context.allocator)
|
||||||
expect(t, err == nil, name)
|
expect(t, err == nil, name)
|
||||||
expect(t, options.hash == 0x17bb1103c92c502f, name)
|
expect(t, options.hash == 0x17bb1103c92c502f, name)
|
||||||
benchmark_print(name, options)
|
benchmark_print(name, options)
|
||||||
|
|
||||||
name = "XXH64 1 MiB zero bytes"
|
name = "XXH64 1 MiB zero bytes"
|
||||||
options.bytes = 1_048_576
|
options.bytes = 1_048_576
|
||||||
err = time.benchmark(options, context.allocator)
|
err = time.benchmark(options, context.allocator)
|
||||||
expect(t, err == nil, name)
|
expect(t, err == nil, name)
|
||||||
expect(t, options.hash == 0x87d2a1b6e1163ef1, name)
|
expect(t, options.hash == 0x87d2a1b6e1163ef1, name)
|
||||||
benchmark_print(name, options)
|
benchmark_print(name, options)
|
||||||
|
|
||||||
name = "XXH3_128 100 zero bytes"
|
name = "XXH3_128 100 zero bytes"
|
||||||
options.bytes = 100
|
options.bytes = 100
|
||||||
options.bench = benchmark_xxh3_128
|
options.bench = benchmark_xxh3_128
|
||||||
err = time.benchmark(options, context.allocator)
|
err = time.benchmark(options, context.allocator)
|
||||||
expect(t, err == nil, name)
|
expect(t, err == nil, name)
|
||||||
expect(t, options.hash == 0x6ba30a4e9dffe1ff801fedc74ccd608c, name)
|
expect(t, options.hash == 0x6ba30a4e9dffe1ff801fedc74ccd608c, name)
|
||||||
benchmark_print(name, options)
|
benchmark_print(name, options)
|
||||||
|
|
||||||
name = "XXH3_128 1 MiB zero bytes"
|
name = "XXH3_128 1 MiB zero bytes"
|
||||||
options.bytes = 1_048_576
|
options.bytes = 1_048_576
|
||||||
err = time.benchmark(options, context.allocator)
|
err = time.benchmark(options, context.allocator)
|
||||||
expect(t, err == nil, name)
|
expect(t, err == nil, name)
|
||||||
expect(t, options.hash == 0xb6ef17a3448492b6918780b90550bf34, name)
|
expect(t, options.hash == 0xb6ef17a3448492b6918780b90550bf34, name)
|
||||||
benchmark_print(name, options)
|
benchmark_print(name, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
@test
|
@test
|
||||||
test_xxhash_vectors :: proc(t: ^testing.T) {
|
test_xxhash_vectors :: proc(t: ^testing.T) {
|
||||||
fmt.println("Verifying against XXHASH_TEST_VECTOR_ZERO:")
|
fmt.println("Verifying against XXHASH_TEST_VECTOR_SEEDED:")
|
||||||
|
|
||||||
buf := make([]u8, 256)
|
buf := make([]u8, 256)
|
||||||
defer delete(buf)
|
defer delete(buf)
|
||||||
|
|
||||||
for v, i in XXHASH_TEST_VECTOR_ZERO[:] {
|
for seed, table in XXHASH_TEST_VECTOR_SEEDED {
|
||||||
b := buf[:i]
|
fmt.printf("\tSeed: %v\n", seed)
|
||||||
|
|
||||||
xxh32 := xxhash.XXH32(b)
|
for v, i in table {
|
||||||
xxh64 := xxhash.XXH64(b)
|
b := buf[:i]
|
||||||
xxh3_128 := xxhash.XXH3_128bits(b)
|
|
||||||
|
|
||||||
xxh32_error := fmt.tprintf("[ XXH32(%03d] Expected: %08x. Got: %08x.", i, v.xxh_32, xxh32)
|
xxh32 := xxhash.XXH32(b, u32(seed))
|
||||||
xxh64_error := fmt.tprintf("[ XXH64(%03d] Expected: %16x. Got: %16x.", i, v.xxh_64, xxh64)
|
xxh64 := xxhash.XXH64(b, seed)
|
||||||
xxh3_128_error := fmt.tprintf("[XXH3_128(%03d] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128)
|
xxh3_128 := xxhash.XXH3_128(b, seed)
|
||||||
|
|
||||||
expect(t, xxh32 == v.xxh_32, xxh32_error)
|
xxh32_error := fmt.tprintf("[ XXH32(%03d)] Expected: %08x. Got: %08x.", i, v.xxh_32, xxh32)
|
||||||
expect(t, xxh64 == v.xxh_64, xxh64_error)
|
xxh64_error := fmt.tprintf("[ XXH64(%03d)] Expected: %16x. Got: %16x.", i, v.xxh_64, xxh64)
|
||||||
expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error)
|
xxh3_128_error := fmt.tprintf("[XXH3_128(%03d)] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128)
|
||||||
}
|
|
||||||
|
|
||||||
|
expect(t, xxh32 == v.xxh_32, xxh32_error)
|
||||||
|
expect(t, xxh64 == v.xxh_64, xxh64_error)
|
||||||
|
expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.println("Verifying against XXHASH_TEST_VECTOR_SECRET:")
|
||||||
|
for secret, table in XXHASH_TEST_VECTOR_SECRET {
|
||||||
|
fmt.printf("\tSecret:\n\t\t\"%v\"\n", secret)
|
||||||
|
|
||||||
|
secret_bytes := transmute([]u8)secret
|
||||||
|
|
||||||
|
for v, i in table {
|
||||||
|
b := buf[:i]
|
||||||
|
|
||||||
|
xxh3_128 := xxhash.XXH3_128(b, secret_bytes)
|
||||||
|
xxh3_128_error := fmt.tprintf("[XXH3_128(%03d)] Expected: %32x. Got: %32x.", i, v.xxh3_128_secret, xxh3_128)
|
||||||
|
|
||||||
|
expect(t, xxh3_128 == v.xxh3_128_secret, xxh3_128_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+6703
-1547
File diff suppressed because it is too large.
Load diff
@@ -2,6 +2,7 @@
|
|||||||
rem math/big tests
|
rem math/big tests
|
||||||
set PATH_TO_ODIN==..\..\..\..\odin
|
set PATH_TO_ODIN==..\..\..\..\odin
|
||||||
set TEST_ARGS=-fast-tests
|
set TEST_ARGS=-fast-tests
|
||||||
|
set TEST_ARGS=-no-random
|
||||||
set TEST_ARGS=
|
set TEST_ARGS=
|
||||||
set OUT_NAME=math_big_test_library
|
set OUT_NAME=math_big_test_library
|
||||||
set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style
|
set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style
|
||||||
@@ -9,5 +10,8 @@ echo ---
|
|||||||
echo Running core:math/big tests
|
echo Running core:math/big tests
|
||||||
echo ---
|
echo ---
|
||||||
|
|
||||||
%PATH_TO_ODIN% build . %COMMON% -o:speed -out:%OUT_NAME%
|
rem Fails
|
||||||
|
:%PATH_TO_ODIN% build . %COMMON% -o:speed -out:%OUT_NAME%
|
||||||
|
rem Passes
|
||||||
|
%PATH_TO_ODIN% build . %COMMON% -o:size -out:%OUT_NAME%
|
||||||
python3 test.py %TEST_ARGS%
|
python3 test.py %TEST_ARGS%
|
||||||
@@ -24,6 +24,12 @@ PyRes :: struct {
|
|||||||
err: big.Error,
|
err: big.Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_to_buffer :: proc(val: ^big.Int) -> cstring {
|
||||||
|
context = runtime.default_context()
|
||||||
|
r, _ := big.int_itoa_cstring(val, 16, context.allocator)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
@export test_initialize_constants :: proc "c" () -> (res: u64) {
|
@export test_initialize_constants :: proc "c" () -> (res: u64) {
|
||||||
context = runtime.default_context()
|
context = runtime.default_context()
|
||||||
res = u64(big.initialize_constants())
|
res = u64(big.initialize_constants())
|
||||||
@@ -34,7 +40,7 @@ PyRes :: struct {
|
|||||||
@export test_error_string :: proc "c" (err: big.Error) -> (res: cstring) {
|
@export test_error_string :: proc "c" (err: big.Error) -> (res: cstring) {
|
||||||
context = runtime.default_context()
|
context = runtime.default_context()
|
||||||
es := big.Error_String
|
es := big.Error_String
|
||||||
return strings.clone_to_cstring(es[err], context.temp_allocator)
|
return strings.clone_to_cstring(es[err], context.allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
@export test_add :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
@export test_add :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||||
@@ -52,9 +58,8 @@ PyRes :: struct {
|
|||||||
if err = #force_inline big.internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err} }
|
if err = #force_inline big.internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err} }
|
||||||
}
|
}
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(sum)
|
||||||
r, err = big.int_itoa_cstring(sum, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":add:itoa(sum):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +78,7 @@ PyRes :: struct {
|
|||||||
if err = #force_inline big.internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err} }
|
if err = #force_inline big.internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err} }
|
||||||
}
|
}
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(sum)
|
||||||
r, err = big.int_itoa_cstring(sum, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":sub:itoa(sum):", err=err} }
|
if err != nil { return PyRes{res=":sub:itoa(sum):", err=err} }
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
@@ -90,9 +94,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err} }
|
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err} }
|
||||||
if err = #force_inline big.internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err} }
|
if err = #force_inline big.internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(product)
|
||||||
r, err = big.int_itoa_cstring(product, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":mul:itoa(product):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +108,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err} }
|
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err} }
|
||||||
if err = #force_inline big.internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err} }
|
if err = #force_inline big.internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(square)
|
||||||
r, err = big.int_itoa_cstring(square, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":sqr:itoa(square):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,13 +126,10 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err} }
|
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err} }
|
||||||
if err = #force_inline big.internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err} }
|
if err = #force_inline big.internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(quotient)
|
||||||
r, err = big.int_itoa_cstring(quotient, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":div:itoa(quotient):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
res = log(a, base)
|
res = log(a, base)
|
||||||
*/
|
*/
|
||||||
@@ -153,9 +150,7 @@ PyRes :: struct {
|
|||||||
aa.used = 2
|
aa.used = 2
|
||||||
big.clamp(aa)
|
big.clamp(aa)
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(aa)
|
||||||
r, err = big.int_itoa_cstring(aa, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +167,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err} }
|
if err = big.atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err} }
|
||||||
if err = #force_inline big.internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err} }
|
if err = #force_inline big.internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(dest)
|
||||||
r, err = big.int_itoa_cstring(dest, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,9 +184,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err} }
|
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err} }
|
||||||
if err = #force_inline big.internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err} }
|
if err = #force_inline big.internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(src)
|
||||||
r, err = big.int_itoa_cstring(src, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,9 +201,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err} }
|
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err} }
|
||||||
if err = #force_inline big.internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err} }
|
if err = #force_inline big.internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(src)
|
||||||
r, err = big.int_itoa_cstring(src, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":root_n:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +218,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err} }
|
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err} }
|
||||||
if err = #force_inline big.internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} }
|
if err = #force_inline big.internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(src)
|
||||||
r, err = big.int_itoa_cstring(src, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":shr_digit:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,9 +235,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err} }
|
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err} }
|
||||||
if err = #force_inline big.internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} }
|
if err = #force_inline big.internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(src)
|
||||||
r, err = big.int_itoa_cstring(src, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":shl_digit:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,9 +252,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err} }
|
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err} }
|
||||||
if err = #force_inline big.internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err} }
|
if err = #force_inline big.internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(src)
|
||||||
r, err = big.int_itoa_cstring(src, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":shr:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,9 +269,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err} }
|
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err} }
|
||||||
if err = #force_inline big.internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err} }
|
if err = #force_inline big.internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(src)
|
||||||
r, err = big.int_itoa_cstring(src, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":shr_signed:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,9 +286,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err} }
|
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err} }
|
||||||
if err = #force_inline big.internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err} }
|
if err = #force_inline big.internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(src)
|
||||||
r, err = big.int_itoa_cstring(src, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":shl:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,9 +302,7 @@ PyRes :: struct {
|
|||||||
|
|
||||||
if err = #force_inline big.internal_int_factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err} }
|
if err = #force_inline big.internal_int_factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(dest)
|
||||||
r, err = big.int_itoa_cstring(dest, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":factorial:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,9 +320,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err} }
|
if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err} }
|
||||||
if err = #force_inline big.internal_int_gcd_lcm(dest, nil, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err} }
|
if err = #force_inline big.internal_int_gcd_lcm(dest, nil, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(dest)
|
||||||
r, err = big.int_itoa_cstring(dest, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":gcd:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,9 +338,7 @@ PyRes :: struct {
|
|||||||
if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err} }
|
if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err} }
|
||||||
if err = #force_inline big.internal_int_gcd_lcm(nil, dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err} }
|
if err = #force_inline big.internal_int_gcd_lcm(nil, dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err} }
|
||||||
|
|
||||||
r: cstring
|
r := print_to_buffer(dest)
|
||||||
r, err = big.int_itoa_cstring(dest, 16, context.temp_allocator)
|
|
||||||
if err != nil { return PyRes{res=":lcm:itoa(res):", err=err} }
|
|
||||||
return PyRes{res = r, err = nil}
|
return PyRes{res = r, err = nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -509,6 +509,10 @@ TESTS = {
|
|||||||
[ 1234, 5432],
|
[ 1234, 5432],
|
||||||
[ 0xd3b4e926aaba3040e1c12b5ea553b5, 0x1a821e41257ed9281bee5bc7789ea7 ],
|
[ 0xd3b4e926aaba3040e1c12b5ea553b5, 0x1a821e41257ed9281bee5bc7789ea7 ],
|
||||||
[ 1 << 21_105, 1 << 21_501 ],
|
[ 1 << 21_105, 1 << 21_501 ],
|
||||||
|
[
|
||||||
|
1730049336780927115956819686084386761976649380496856295804733690382760679622521498499921378784999570040271671925282244844227926513254947505760453265751925233363030016710223529453611114150096214358876871544215680932353097397897122621984375092474133393053294977255698548380501779165732851763338230363578093763769439102609171758268746816086960113106882499458387307669542211952704912157356576861961972768593905554420978528580995386554359520223733821688040356932599460903642004593989258224090066200205811545449328342874985004936989038151949680315248981915720041124876396153675254746544866867028149203350976744445435225126520798064171376343984296634838803422918301298254984982665599902379373705468835781969789807400857256337356383393961948567488204866782561661516542741894721525263376596495934506415330671185934290682139796941439411384604901664995378273710569974505716752886145273338333891832366700048762023254741569307251599758237233773781429091918051518799686824417084288083651448165395380039381015360363773971673121312498405250931600966368271888969486090874111776466343306964128647016555509147202959928525495091285313778400354945501547606122608174049426458283906654605017272762789394862530631456378675885996618520988466391688295798533253809765316410882810991690837065239007520466766004127431689022253919911135407947926638077005426651048535013175810559524255472354897202098221602023343651307693092594595360916333574712793311566096740232505174235926796670762625867042793655130238521985025204494551431086964825393205742515852874523288485034055478725362889688070393834278042164537803763851055914331239178122380835108766976077034143441567602291243077986687725000039509776134269255948365679462005506286749635355692967678000137403769294016297074060159759958317333838183102961577247353080391899380925437019232361883658021468008626726340998633758018693007791420933588169821810101049458198325500017716951681696808012893297261929276815421897289964433942270688119583435216485766144260090560765441294877258212550540337102518762499129074888234322963229378578567988816715822301010709403075393789989770675527771854132912072315260600909792474033475665370488822055013572703331421366250253857961301330238864830844458292605005914325375618249733031623536934624536852343616515661053681173955269638737116947238948249548629819827998846959450749725369804986271927749582045980299289917776988677895104094745962452512491680956045772823555404030003162937740443845867469746904408025223895782807886855239537989132423006372119600868205973133604844769569791145608016444032946191020200576534243394193912801091722722241519777526906505124763900211982937072618715161818565145685306927315199322818876860612197941236260782243172598045161156734259422066932002893512561419310981825851272999858949983337436890302365344666481416720248061311845178104735892705675864159873031989853816586787033390034673399302527048969000571597056500471799485619607682961163996605458680900518142302640900244347937450870396258768686407877177058812610043549822495930513342101301685377267950709023913123118184810480469280363562564884653831970201667432585603615619490494224693972998053027375230118709801926300034079053018961758730437332325252251350871203856288581014729514119560028148702180915117133398079363829103930529685044592367216255367190344182262795831891396761345379486553003619077290827379834924118492352991278451970215860985161359740489218979048771848630734561772340413962282961951804839625192043526541100859135769664389353539653630387616786543322936429843226114776303864861511695088506754638071413183425075157412033344878110436795248633793319478706590787894029114890373877308647612480475135214049464963978960668902827298257063068707176495355541396976529698791443461770107134798292939666824250865906686636698298197121275208617399798893909663169890996536443582415047536165536175951228939095370262297540739547030517255966952547257702145967949012072201028511301852718794364319420244621446892329053553246148144112081349361624442771772388755907316964438478859218275909737233525949036317571033995766105927660789131388251571227854553974279399708496051956380863384593620968959971485529230649053881484031745181426655178676848017753052407611172598644994015055915246460354688848624422876857835341735842161346022540204702522267158458602984859826599961545022260296316276614178053663813496408301794503725163099263816293240353309262025728123008689433505658663285062523880631681698771921612557802476061765240639561588595265817294323233970250837840575194407464234222979084474077958037785835381666582687877520067943278544017087958639705129542601285058824285572725116601751577454014615064562691406682443953290955190682772857673269166420239497581367393789984827784359106010906907058631730428203252038517507628886546612909267330933695114669909915658899947655985966169811892262417427166701685411877537404682428835743477163267979780725082034393056636608881552476411102026459078465300516694338277916543090502895827917092227860170900169467257173674074040468421319196473491980178317Line truncated
|
||||||
|
2792137305616803816125736371202973842588346907871060193054596221054431637248346525789679785002348132727403381050304333403521587481999372458732683632074946655377226940586292319536282433288785140521353343308120807715685064882137593035298916678320083374661595910612775567155701908996438831713949883784550281569922822457622483208201069251422918253408268112431251358808846071984701166253332282516847624734963781054838320368378806085407578003670518453665342046001889832393119117981341763310622979760755154908902675663856179579170795549470005409764197071438300067489902175089330223064432949726633984891191217176923572344031319455165221390100825635588930238712211222900630755916931560094286195805301756672856225362900244385069233409314804800555961055112156915896179495209531521091435382602595906681453589203960409330978681534220701636627295448211492515088551856302206336820688924876541862852433315779578401739255143867316193807225825715088332912079762451987915314991328087937869306870185231839600162732468104581586152236000750824310995237864293343076286813472691908460982179549036215799901611606423103486063968144180643595753778104520856295571372210315676707071859268823314407120141976675397217336731750795995085232031550730601606044459215570889361983964918472534668526006951123584013924608101570234604877448321092888556603237971244202651109712462161745773547686312884958613172030057699852955140949056233828521648810014892164015132153435011571445381241333780422537123555422435609629862120174301124523055521576485380354301671470141661212013573861351884055770762914906495885949222560999728824951688440107934227374154118679817743711808528809954738849359290001209496723174655240141359924552463330058881371406476600283097970722993054002258834190103641779964974253356931460360048162772804601446022399431015079317112767461578236761288013160789539641472439762181155222054214898090412728062295571731377939868071718985282868670884355757224431507927345732372304163280099866736872721892104636961718101143568602345468944046398382072225271834301304572610815491239030099291767882628770553815655662175838187711099718792290209526514091707024088965625034258707633779373243346268648329011153933286770043104417809552124808102136896675994089547278593004073015362968463599596578808554308520819477600709399168831674255233814165978438526056464478361078391570301959747951289682375087784454254875832221297205223901288838563060542703593685527750869144993727690389411606195646234819572249449567243254465740006482986141506934764083958093696735082026903459069667976547476516046890396191667227069623602398724393529957207486930237108727816598703252336372477271447734620874259257795128322794191544771805411025396764711020975687954299867611459526389083964109961947440978470627588649814866591303328893199861375161351958311192953547610275226193511445893322412132479577605643259736796700502677627676267041108462702498261065294302672511049691223029856778461413499388902372985325489354381113828400128516099643753556431806252824133845353202718540757824181008426150764385827590610022246644888836091709210250256398141051312513942928954281436235203212567329074893150623351979520678490139460207349640843291411935584566997192161120659139802646742056374022348966159384272092526970237017924564363344493535352294266381140549452439197336725170887381697376886867046749323594343191610842495649736825742316119130427699443475457713598478466346701382298420337950120109995758607430701428567672350707901408092793306772973362032467941978203984901698196532107974266061183843855638984220193220163705886917993169740301478717686350138061573948448741546857385535907921238736855169291062872344097792957993007878225570218484070546472765435925667231916054161810140888976824496637911413419457929009269183006205319984045418637498768203719778261755449850497212353922333319713911122334012343134900598916132270604644829454913634527563629404058568623810952755998640033078156451155513267560035484543574043019538784339291871629242325012384135204944882954281389553477879152189124185640959913574077763346382522067410470664241929898503518376560219743198942917391546341101346576855027761227615741812857212781462286291281590403815100866266423178896838999326288367507389614853952328467348264448254848365058616869337644188901694696995597838072259497574878250630600839142179130636622540992856173959139004457390425665695792424693753125303601262422567700409003968093051687322744044494593827435761811466144076164950315807153252935989036175890085157965570880415587551579321808355449005861634711633242567666630114041548642355332004815350423836237355785553577904690555782852626348974775339521215576039797408230631782562433766133887679273870867449928642255968517342018207630614890818003729320237201378717014670107160543911914739280475504823611684049206124135234239649426264861333817106553364926318082950317482140041827480077919125447928404894685157009517457024722358190275650378618567733069775349818673041206914762974760977283863231733835125792093849471287070810803893410185857944700112882461Line truncated
|
||||||
|
]
|
||||||
],
|
],
|
||||||
test_sqr: [
|
test_sqr: [
|
||||||
[ 5432],
|
[ 5432],
|
||||||
@@ -534,6 +538,8 @@ TESTS = {
|
|||||||
[ 42, 1 ], # 1
|
[ 42, 1 ], # 1
|
||||||
[ 42, 0 ], # 42
|
[ 42, 0 ], # 42
|
||||||
[ 42, 2 ], # 42*42
|
[ 42, 2 ], # 42*42
|
||||||
|
[ 1023423462055631945665902260039819522, 6],
|
||||||
|
[ 2351415513563017480724958108064794964140712340951636081608226461329298597792428177392182921045756382154475969841516481766099091057155043079113409578271460350765774152509347176654430118446048617733844782454267084644777022821998489944144604889308377152515711394170267839394315842510152114743680838721625924309675796181595284284935359605488617487126635442626578631, 4],
|
||||||
],
|
],
|
||||||
test_sqrt: [
|
test_sqrt: [
|
||||||
[ -1, Error.Invalid_Argument, ],
|
[ -1, Error.Invalid_Argument, ],
|
||||||
|
|||||||
Reference in new issue
Block a user