1 /* This file is part of the Sub::Nary Perl module.
2 * See http://search.cpan.org/dist/Sub::Nary/ */
4 #define PERL_NO_GET_CONTEXT
10 # define mPUSHi(I) PUSHs(sv_2mortal(newSViv(I)))
18 STATIC void sn_store(pTHX_ HV *tb, const char *key, I32 klen, SV *val, U32 hash) {
19 #define sn_store(T, K, KL, V, H) sn_store(aTHX_ (T), (K), (KL), (V), (H))
20 if (!hv_store(tb, key, klen, val, hash)) SvREFCNT_dec(val);
23 STATIC void sn_store_ent(pTHX_ HV *tb, SV *key, SV *val, U32 hash) {
24 #define sn_store_ent(T, K, V, H) sn_store_ent(aTHX_ (T), (K), (V), (H))
25 if (!hv_store_ent(tb, key, val, hash)) SvREFCNT_dec(val);
29 STATIC U32 sn_hash_list = 0;
31 /* --- XS ------------------------------------------------------------------ */
33 MODULE = Sub::Nary PACKAGE = Sub::Nary
39 PERL_HASH(sn_hash_list, "list", 4);
46 ST(0) = sv_2mortal(newSVuv(SvUV(SvRV(op))));
55 o = INT2PTR(OP *, SvUV(SvRV(op)));
56 ST(0) = sv_2mortal(newSVuv(o == NULL));
69 res = SvNOK(sv) ? SvNV(sv) == 0.0 : SvUV(sv) == 0;
73 res = hv_iterinit(hv) == 1 && hv_exists(hv, "0", 1);
90 while (key = hv_iternext(hv)) {
91 c += SvNV(HeVAL(key));
107 sn_store_ent(res, sv, newSVuv(1), 0);
109 hv = (HV *) SvRV(sv);
110 if (!hv_iterinit(hv)) {
111 sn_store(res, "0", 1, newSVuv(1), 0);
113 while (key = hv_iternext(hv))
114 c += SvNV(HeVAL(key));
116 while (key = hv_iternext(hv)) {
117 SV *val = newSVnv(SvNV(HeVAL(key)) / c);
118 sn_store_ent(res, HeSVKEY_force(key), val, HeHASH(key));
122 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
126 scale(SV *csv, SV *sv)
139 sn_store_ent(res, sv, newSVnv(c), 0);
141 hv = (HV *) SvRV(sv);
142 if (!hv_iterinit(hv)) {
146 while (key = hv_iternext(hv)) {
147 SV *val = newSVnv(SvNV(HeVAL(key)) * c);
148 sn_store_ent(res, HeSVKEY_force(key), val, HeHASH(key));
152 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
167 for (i = 0; i < items; ++i) {
173 if ((old = hv_fetch_ent(res, cur, 1, 0)) && SvOK(val = HeVAL(old)))
175 sn_store_ent(res, cur, newSVnv(v), 0);
179 hv_iterinit((HV *) cur);
180 while (key = hv_iternext((HV *) cur)) {
181 SV *k = HeSVKEY_force(key);
182 NV v = SvNV(HeVAL(key));
183 if ((old = hv_fetch_ent(res, k, 1, 0)) && SvOK(val = HeVAL(old)))
185 sn_store_ent(res, k, newSVnv(v), 0);
188 if (!hv_iterinit(res)) {
192 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
196 cumulate(SV *sv, SV *nsv, SV *csv)
209 ST(0) = sv_2mortal(newSVuv(0));
212 if (!SvROK(sv) || !c0) {
217 if (!hv_iterinit((HV *) sv))
219 if (c0 == 1 || (SvIOK(csv) && SvIV(csv) == 1)) {
224 for (; n > 0; n /= 2) {
229 c = (1 - c) / (1 - c0);
232 while (key = hv_iternext((HV *) sv)) {
233 SV *k = HeSVKEY_force(key);
234 SV *val = newSVnv(c * SvNV(HeVAL(key)));
235 sn_store_ent(res, k, val, 0);
237 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
252 UV shift = 0, do_shift = 0;
253 sn_combcache *cache = NULL;
258 res[0] = res[1] = NULL;
259 for (i = 0; i < items; ++i) {
264 if (strEQ(SvPV_nolen(cur), "list")) {
267 sn_store(res[0], "list", 4, newSVuv(1), sn_hash_list);
280 while (key = hv_iternext((HV *) cur))
281 sn_store_ent(res[0], HeSVKEY_force(key), newSVsv(HeVAL(key)), 0);
287 temp = sv_2mortal(newSViv(0));
288 for (++i; i < items; ++i) {
293 if (strEQ(SvPV_nolen(cur), "list")) {
295 sn_store(res[n], "list", 4, newSVuv(1), sn_hash_list);
310 list1 = hv_delete((HV *) cur, "list", 4, 0);
311 n1 = hv_iterinit((HV *) cur);
312 list2 = hv_delete(res[n], "list", 4, 0);
313 n2 = hv_iterinit(res[n]);
314 if ((list1 && !n1) || (list2 && !n2)) {
315 sn_store(res[o], "list", 4, newSViv(1), sn_hash_list);
318 } else if (list1 || list2) {
319 NV l1 = list1 ? SvNV(list1) : 0;
320 NV l2 = list2 ? SvNV(list2) : 0;
321 val = newSVnv(l1 + l2 - l1 * l2);
322 sn_store(res[o], "list", 4, val, sn_hash_list);
325 Renew(cache, n2, sn_combcache);
329 while (key = hv_iternext(res[n])) {
330 cache[j].k = SvUV(HeSVKEY_force(key));
331 cache[j].v = SvNV(HeVAL(key));
334 while (key = hv_iternext((HV *) cur)) {
335 IV k = SvUV(HeSVKEY_force(key));
336 NV v = SvNV(HeVAL(key));
337 for (j = 0; j < n2; ++j) {
338 sv_setiv(temp, k + cache[j].k);
339 if ((old = hv_fetch_ent(res[o], temp, 1, 0)) && SvOK(val = HeVAL(old))) {
340 val = newSVnv(SvNV(val) + v * cache[j].v);
342 val = newSVnv(v * cache[j].v);
344 sn_store_ent(res[o], temp, val, 0);
350 if (shift || do_shift) {
353 sv_setiv(temp, shift);
354 sn_store_ent(res[n], temp, newSViv(1), 0);
361 list1 = hv_delete(res[n], "list", 4, 0);
363 while (key = hv_iternext(res[n])) {
364 sv_setiv(temp, SvUV(HeSVKEY_force(key)) + shift);
365 sn_store_ent(res[o], temp, newSVsv(HeVAL(key)), 0);
368 sn_store(res[o], "list", 4, newSVsv(list1), sn_hash_list);
371 } else if (!res[0] && !res[1])
374 SvREFCNT_dec(res[0]);
376 SvREFCNT_dec(res[1]);
377 ST(0) = sv_2mortal(newRV_noinc((SV *) res[n]));
388 if (cxt == G_SCALAR) {
389 for (i = 0; i < OP_max; ++i) {
390 count += (PL_opargs[i] & (OA_RETSCALAR | OA_RETINTEGER)) != 0;
395 } else if (cxt == G_ARRAY) {
396 for (i = 0; i < OP_max; ++i) {
397 if (PL_opargs[i] & (OA_RETSCALAR | OA_RETINTEGER)) {
398 const char *name = PL_op_name[i];
399 XPUSHs(sv_2mortal(newSVpvn_share(name, strlen(name), 0)));