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))
24 STATIC void sn_store_ent(pTHX_ HV *tb, SV *key, SV *val, U32 hash) {
25 #define sn_store_ent(T, K, V, H) sn_store_ent(aTHX_ (T), (K), (V), (H))
26 if (!hv_store_ent(tb, key, val, hash))
31 STATIC U32 sn_hash_list = 0;
33 /* --- XS ------------------------------------------------------------------ */
35 MODULE = Sub::Nary PACKAGE = Sub::Nary
41 PERL_HASH(sn_hash_list, "list", 4);
48 ST(0) = sv_2mortal(newSVuv(SvUV(SvRV(op))));
57 o = INT2PTR(OP *, SvUV(SvRV(op)));
58 ST(0) = sv_2mortal(newSVuv(o == NULL));
71 res = SvNOK(sv) ? SvNV(sv) == 0.0 : SvUV(sv) == 0;
75 res = hv_iterinit(hv) == 1 && hv_exists(hv, "0", 1);
92 while (key = hv_iternext(hv)) {
93 c += SvNV(HeVAL(key));
109 sn_store_ent(res, sv, newSVuv(1), 0);
111 hv = (HV *) SvRV(sv);
112 if (!hv_iterinit(hv)) {
113 sn_store(res, "0", 1, newSVuv(1), 0);
115 while (key = hv_iternext(hv))
116 c += SvNV(HeVAL(key));
118 while (key = hv_iternext(hv)) {
119 SV *val = newSVnv(SvNV(HeVAL(key)) / c);
120 sn_store_ent(res, HeSVKEY_force(key), val, HeHASH(key));
124 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
128 scale(SV *csv, SV *sv)
141 sn_store_ent(res, sv, newSVnv(c), 0);
143 hv = (HV *) SvRV(sv);
144 if (!hv_iterinit(hv)) {
145 sn_store(res, "0", 1, newSVnv(c), 0);
148 while (key = hv_iternext(hv)) {
149 SV *val = newSVnv(SvNV(HeVAL(key)) * c);
150 sn_store_ent(res, HeSVKEY_force(key), val, HeHASH(key));
154 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
169 for (i = 0; i < items; ++i) {
175 if ((old = hv_fetch_ent(res, cur, 1, 0)) && SvOK(val = HeVAL(old)))
177 sn_store_ent(res, cur, newSVnv(v), 0);
181 hv_iterinit((HV *) cur);
182 while (key = hv_iternext((HV *) cur)) {
183 SV *k = HeSVKEY_force(key);
184 NV v = SvNV(HeVAL(key));
185 if ((old = hv_fetch_ent(res, k, 1, 0)) && SvOK(val = HeVAL(old)))
187 sn_store_ent(res, k, newSVnv(v), 0);
190 if (!hv_iterinit(res)) {
194 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
198 cumulate(SV *sv, SV *nsv, SV *csv)
211 ST(0) = sv_2mortal(newSVuv(0));
214 if (!SvROK(sv) || !c0) {
219 if (!hv_iterinit((HV *) sv))
221 if (c0 == 1 || (SvIOK(csv) && SvIV(csv) == 1)) {
226 for (; n > 0; n /= 2) {
231 c = (1 - c) / (1 - c0);
234 while (key = hv_iternext((HV *) sv)) {
235 SV *k = HeSVKEY_force(key);
236 SV *val = newSVnv(c * SvNV(HeVAL(key)));
237 sn_store_ent(res, k, val, 0);
239 ST(0) = sv_2mortal(newRV_noinc((SV *) res));
254 UV shift = 0, do_shift = 0;
255 sn_combcache *cache = NULL;
260 res[0] = res[1] = NULL;
261 for (i = 0; i < items; ++i) {
266 if (strEQ(SvPV_nolen(cur), "list")) {
269 sn_store(res[0], "list", 4, newSVuv(1), sn_hash_list);
282 while (key = hv_iternext((HV *) cur))
283 sn_store_ent(res[0], HeSVKEY_force(key), newSVsv(HeVAL(key)), 0);
289 temp = sv_2mortal(newSViv(0));
290 for (++i; i < items; ++i) {
295 if (strEQ(SvPV_nolen(cur), "list")) {
297 sn_store(res[n], "list", 4, newSVuv(1), sn_hash_list);
312 list1 = hv_delete((HV *) cur, "list", 4, 0);
313 n1 = hv_iterinit((HV *) cur);
314 list2 = hv_delete(res[n], "list", 4, 0);
315 n2 = hv_iterinit(res[n]);
316 if ((list1 && !n1) || (list2 && !n2)) {
317 sn_store(res[o], "list", 4, newSViv(1), sn_hash_list);
320 } else if (list1 || list2) {
321 NV l1 = list1 ? SvNV(list1) : 0;
322 NV l2 = list2 ? SvNV(list2) : 0;
323 val = newSVnv(l1 + l2 - l1 * l2);
324 sn_store(res[o], "list", 4, val, sn_hash_list);
327 Renew(cache, n2, sn_combcache);
331 while (key = hv_iternext(res[n])) {
332 cache[j].k = SvUV(HeSVKEY_force(key));
333 cache[j].v = SvNV(HeVAL(key));
336 while (key = hv_iternext((HV *) cur)) {
337 IV k = SvUV(HeSVKEY_force(key));
338 NV v = SvNV(HeVAL(key));
339 for (j = 0; j < n2; ++j) {
340 sv_setiv(temp, k + cache[j].k);
341 if ((old = hv_fetch_ent(res[o], temp, 1, 0)) && SvOK(val = HeVAL(old))) {
342 val = newSVnv(SvNV(val) + v * cache[j].v);
344 val = newSVnv(v * cache[j].v);
346 sn_store_ent(res[o], temp, val, 0);
352 if (shift || do_shift) {
355 sv_setiv(temp, shift);
356 sn_store_ent(res[n], temp, newSViv(1), 0);
363 list1 = hv_delete(res[n], "list", 4, 0);
365 while (key = hv_iternext(res[n])) {
366 sv_setiv(temp, SvUV(HeSVKEY_force(key)) + shift);
367 sn_store_ent(res[o], temp, newSVsv(HeVAL(key)), 0);
370 sn_store(res[o], "list", 4, newSVsv(list1), sn_hash_list);
373 } else if (!res[0] && !res[1])
376 SvREFCNT_dec(res[0]);
378 SvREFCNT_dec(res[1]);
379 ST(0) = sv_2mortal(newRV_noinc((SV *) res[n]));
390 if (cxt == G_SCALAR) {
391 for (i = 0; i < OP_max; ++i) {
392 count += (PL_opargs[i] & (OA_RETSCALAR | OA_RETINTEGER)) != 0;
397 } else if (cxt == G_ARRAY) {
398 for (i = 0; i < OP_max; ++i) {
399 if (PL_opargs[i] & (OA_RETSCALAR | OA_RETINTEGER)) {
400 const char *name = PL_op_name[i];
401 XPUSHs(sv_2mortal(newSVpvn_share(name, strlen(name), 0)));