u_long Scm_EqvHash(ScmObj obj) { u_long hashval; if (SCM_NUMBERP(obj)) { if (SCM_INTP(obj)) { SMALL_INT_HASH(hashval, SCM_INT_VALUE(obj)); } else if (SCM_BIGNUMP(obj)) { u_int i; u_long u = 0; for (i=0; i<SCM_BIGNUM_SIZE(obj); i++) { u += SCM_BIGNUM(obj)->values[i]; } SMALL_INT_HASH(hashval, u); } else if (SCM_FLONUMP(obj)) { /* TODO: I'm not sure this is a good hash. */ hashval = (u_long)(SCM_FLONUM_VALUE(obj)*2654435761UL); } else if (SCM_RATNUMP(obj)) { /* Ratnum must be normalized, so we can simply combine hashvals of numerator and denominator. */ u_long h1 = Scm_EqvHash(SCM_RATNUM_NUMER(obj)); u_long h2 = Scm_EqvHash(SCM_RATNUM_DENOM(obj)); hashval = COMBINE(h1, h2); } else { /* TODO: I'm not sure this is a good hash. */ hashval = (u_long)((SCM_COMPNUM_REAL(obj)+SCM_COMPNUM_IMAG(obj))*2654435761UL); } } else { ADDRESS_HASH(hashval, obj); } return hashval&HASHMASK; }
/* we need special routines for int64 */ ScmInt64 Scm_BignumToSI64(const ScmBignum *b, int clamp, int *oor) { #if SCM_EMULATE_INT64 ScmInt64 r = {0, 0}; if (clamp == SCM_CLAMP_NONE && oor != NULL) *oor = FALSE; if (b->sign > 0) { if (b->size > 2 || b->values[1] > LONG_MAX) { if (!(clamp & SCM_CLAMP_HI)) goto err; SCM_SET_INT64_MAX(r); } else { r.lo = b->values[0]; if (b->size == 2) r.hi = b->values[1]; } } else if (b->sign < 0) { if (b->size > 2 || b->values[1] > (u_long)LONG_MAX + 1) { if (!(clamp&SCM_CLAMP_LO)) goto err; SCM_SET_INT64_MIN(r); } else { b = SCM_BIGNUM(Scm_BignumComplement(b)); r.lo = b->values[0]; if (b->size == 2) r.hi = b->values[1]; else r.hi = -1; } } return r; #else /*!SCM_EMULATE_INT64*/ int64_t r = 0; if (clamp == SCM_CLAMP_NONE && oor != NULL) *oor = FALSE; if (b->sign > 0) { if (b->size == 1) { r = b->values[0]; } else if (b->size > 2 || b->values[1] > LONG_MAX) { if (!(clamp & SCM_CLAMP_HI)) goto err; SCM_SET_INT64_MAX(r); } else { r = ((int64_t)b->values[1] << 32) + (uint64_t)b->values[0]; } } else { /* b->sign < 0 */ if (b->size == 1) { r = -(int64_t)b->values[0]; } else if (b->size > 2 || (b->values[1] > LONG_MAX && b->values[0] > 0)) { if (!(clamp&SCM_CLAMP_LO)) goto err; SCM_SET_INT64_MIN(r); } else { r = -(int64_t)(((int64_t)b->values[1] << 32) + (uint64_t)b->values[0]); } } return r; #endif /*!SCM_EMULATE_INT64*/ err: if (clamp == SCM_CLAMP_NONE && oor != NULL) { *oor = TRUE; } else { Scm_Error("argument out of range: %S", SCM_OBJ(b)); } return r; }