ST(0) = sv_2mortal(newSVuv(o == NULL));
XSRETURN(1);
+void
+zero(SV *sv)
+PROTOTYPE: $
+PREINIT:
+ HV *hv;
+ IV res;
+CODE:
+ if (!SvOK(sv))
+ XSRETURN_IV(1);
+ if (!SvROK(sv)) {
+ res = SvNOK(sv) ? SvNV(sv) == 0.0 : SvUV(sv) == 0;
+ XSRETURN_IV(res);
+ }
+ hv = (HV *) SvRV(sv);
+ res = hv_exists(hv, "0", 1) && hv_iterinit(hv) == 1;
+ XSRETURN_IV(res);
+
+void
+list(SV *sv)
+PROTOTYPE: $
+PREINIT:
+ HV *hv;
+ IV res;
+CODE:
+ if (!SvOK(sv))
+ XSRETURN_IV(0);
+ if (!SvROK(sv)) {
+ res = strEQ(SvPV_nolen(sv), "list");
+ XSRETURN_IV(res);
+ }
+ hv = (HV *) SvRV(sv);
+ res = hv_exists(hv, "list", 4) && hv_iterinit(hv) == 1;
+ XSRETURN_IV(res);
+
+void
+count(SV *sv)
+PROTOTYPE: $
+PREINIT:
+ HV *hv;
+ HE *key;
+ NV c = 0;
+CODE:
+ if (!SvOK(sv))
+ XSRETURN_IV(0);
+ if (!SvROK(sv))
+ XSRETURN_IV(1);
+ hv = (HV *) SvRV(sv);
+ hv_iterinit(hv);
+ while (key = hv_iternext(hv)) {
+ c += SvNV(HeVAL(key));
+ }
+ XSRETURN_NV(c);
+
+void
+normalize(SV *sv)
+PROTOTYPE: $
+PREINIT:
+ HV *hv, *res;
+ HE *key;
+ SV *val;
+ NV c = 0;
+CODE:
+ if (!SvOK(sv))
+ XSRETURN_UNDEF;
+ res = newHV();
+ if (!SvROK(sv)) {
+ val = newSVuv(1);
+ if (!hv_store_ent(res, sv, val, 0)) {
+ SvREFCNT_dec(val);
+ XSRETURN_UNDEF;
+ }
+ } else {
+ hv = (HV *) SvRV(sv);
+ if (!hv_iterinit(hv)) {
+ val = newSVuv(1);
+ if (!hv_store(res, "0", 1, val, 0)) {
+ SvREFCNT_dec(val);
+ XSRETURN_UNDEF;
+ }
+ } else {
+ while (key = hv_iternext(hv)) {
+ c += SvNV(HeVAL(key));
+ }
+ hv_iterinit(hv);
+ while (key = hv_iternext(hv)) {
+ val = newSVnv(SvNV(HeVAL(key)) / c);
+ if (!hv_store_ent(res, HeSVKEY_force(key), val, HeHASH(key)))
+ SvREFCNT_dec(val);
+ }
+ }
+ }
+ ST(0) = sv_2mortal(newRV_noinc((SV *) res));
+ XSRETURN(1);
+
void
scalops()
PROTOTYPE: