diff options
| author | Russ Cox <rsc@golang.org> | 2012-01-26 16:25:07 -0500 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2012-01-26 16:25:07 -0500 |
| commit | 408f0b1f7459ebcbc74ad5936950072796fe449a (patch) | |
| tree | 8b13422bc016157ca6a612913f638ff9bfc93446 /src/pkg/runtime/alg.c | |
| parent | 109a9763550aac3071e30f6e13cb5ec1172aa017 (diff) | |
| download | go-408f0b1f7459ebcbc74ad5936950072796fe449a.tar.xz | |
gc, runtime: handle floating point map keys
Fixes #2609.
R=ken2
CC=golang-dev
https://golang.org/cl/5572069
Diffstat (limited to 'src/pkg/runtime/alg.c')
| -rw-r--r-- | src/pkg/runtime/alg.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/pkg/runtime/alg.c b/src/pkg/runtime/alg.c index 033f5b462a..56ec2d69e6 100644 --- a/src/pkg/runtime/alg.c +++ b/src/pkg/runtime/alg.c @@ -198,6 +198,106 @@ runtime·memcopy128(uintptr s, void *a, void *b) } void +runtime·f32equal(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(float32*)a == *(float32*)b; +} + +void +runtime·f64equal(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(float64*)a == *(float64*)b; +} + +void +runtime·c64equal(bool *eq, uintptr s, void *a, void *b) +{ + Complex64 *ca, *cb; + + USED(s); + ca = a; + cb = b; + *eq = ca->real == cb->real && ca->imag == cb->imag; +} + +void +runtime·c128equal(bool *eq, uintptr s, void *a, void *b) +{ + Complex128 *ca, *cb; + + USED(s); + ca = a; + cb = b; + *eq = ca->real == cb->real && ca->imag == cb->imag; +} + +// NOTE: Because NaN != NaN, a map can contain any +// number of (mostly useless) entries keyed with NaNs. +// To avoid long hash chains, we assign a random number +// as the hash value for a NaN. + +void +runtime·f32hash(uintptr *h, uintptr s, void *a) +{ + uintptr hash; + float32 f; + + USED(s); + f = *(float32*)a; + if(f == 0) + hash = 0; // +0, -0 + else if(f != f) + hash = runtime·fastrand1(); // any kind of NaN + else + hash = *(uint32*)a; + *h ^= (*h ^ hash ^ 2860486313U) * 3267000013U; +} + +void +runtime·f64hash(uintptr *h, uintptr s, void *a) +{ + uintptr hash; + float64 f; + uint64 u; + + USED(s); + f = *(float32*)a; + if(f == 0) + hash = 0; // +0, -0 + else if(f != f) + hash = runtime·fastrand1(); // any kind of NaN + else { + u = *(uint64*)a; + if(sizeof(uintptr) == 4) + hash = ((uint32)(u>>32) ^ 2860486313) * (uint32)u; + else + hash = u; + } + if(sizeof(uintptr) == 4) + *h = (*h ^ hash ^ 2860486313U) * 3267000013U; + else + *h = (*h ^ hash ^ 33054211828000289ULL) * 23344194077549503ULL; +} + +void +runtime·c64hash(uintptr *h, uintptr s, void *a) +{ + USED(s); + runtime·f32hash(h, 0, a); + runtime·f32hash(h, 0, (float32*)a+1); +} + +void +runtime·c128hash(uintptr *h, uintptr s, void *a) +{ + USED(s); + runtime·f64hash(h, 0, a); + runtime·f64hash(h, 0, (float64*)a+1); +} + +void runtime·slicecopy(uintptr s, void *a, void *b) { USED(s); @@ -349,6 +449,10 @@ runtime·algarray[] = [AINTER] { runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy }, [ANILINTER] { runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy }, [ASLICE] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy }, +[AFLOAT32] { runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy }, +[AFLOAT64] { runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy }, +[ACPLX64] { runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy }, +[ACPLX128] { runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy }, [AMEM0] { runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 }, [AMEM8] { runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 }, [AMEM16] { runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 }, |
