/*
* This file was generated automatically by ExtUtils::ParseXS version 2.18 from the
* contents of RefHash.xs. Do not edit this file, edit RefHash.xs instead.
*
* ANY CHANGES MADE HERE WILL BE LOST!
*
*/
#line 1 "RefHash.xs"
/* Copyright (c) 1997-2006 -*- C -*-
Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version: http://www.gnu.org/licenses/gpl.txt.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ident "$Project: polymake $$Id: RefHash.xs 7146 2006-03-02 09:53:56Z gawrilow $"
#include "Ext.h"
/******************************************************************************************************/
/* references as hash keys */
static HV *my_pkg;
typedef struct tmp_keysv {
SV *ptr;
XPVUV xpv;
SV sv;
} tmp_keysv;
typedef union key_or_ptr {
SV *ptr;
unsigned long key;
} key_or_ptr;
static
SV* ref2key(SV *keysv, tmp_keysv *tmp_key)
{
key_or_ptr obj;
obj.ptr=SvRV(keysv);
if (SvAMAGIC(keysv)) obj.key |= 1;
tmp_key->ptr=obj.ptr;
tmp_key->xpv.xpv_pv=(char*)&tmp_key->ptr;
tmp_key->xpv.xpv_cur=sizeof(SV*);
tmp_key->xpv.xpv_len=0;
tmp_key->xpv.xuv_uv=obj.key >> 4; /* hash value */
tmp_key->sv.sv_any=&tmp_key->xpv;
tmp_key->sv.sv_refcnt=1;
tmp_key->sv.sv_flags= SVt_PVIV | SVf_IVisUV | SVf_POK | SVp_POK | SVf_FAKE | SVf_READONLY;
return &tmp_key->sv;
}
static char err_no_ref[]="Hash key is not a reference";
static char err_ref[]="Reference as a key in a normal hash";
static char err_no_local[]="Localizing in reference-keyed hashes not implemented yet";
static
OP* intercept_pp_helem(pTHX)
{
dSP;
tmp_keysv tmp_key;
SV *keysv=TOPs;
HV *hv=(HV*)TOPm1s, *class=SvSTASH(hv);
if (SvROK(keysv)) {
if (class != my_pkg) {
if (class!=0 || HvFILL(hv) || SvRMAGICAL(hv))
DIE(aTHX_ err_ref);
SvSTASH(hv)=my_pkg;
}
if (PL_op->op_private & OPpLVAL_INTRO)
DIE(aTHX_ err_no_local);
#ifndef not_PERL_5_8
SETs(ref2key(keysv, &tmp_key));
#else
/* must be perl 5.6 */
keysv=ref2key(keysv, &tmp_key);
(void)POPs;
{
U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
U32 defer = PL_op->op_private & OPpLVAL_DEFER;
HE *he=hv_fetch_ent(hv, keysv, lval && !defer, tmp_key.xpv.xuv_uv);
SV **svp=he ? &HeVAL(he) : 0, *sv;
if (lval) {
if (!svp || *svp == &PL_sv_undef) {
SV* lv;
SV* key2;
if (!defer) {
STRLEN n_a;
DIE(aTHX_ PL_no_helem, SvPV(keysv, n_a));
}
lv = sv_newmortal();
sv_upgrade(lv, SVt_PVLV);
LvTYPE(lv) = 'y';
sv_magic(lv, key2 = newSVsv(keysv), 'y', Nullch, 0);
SvREFCNT_dec(key2); /* sv_magic() increments refcount */
LvTARG(lv) = SvREFCNT_inc(hv);
LvTARGLEN(lv) = 1;
SETs(lv);
RETURN;
}
if (PL_op->op_private & OPpDEREF)
vivify_ref(*svp, PL_op->op_private & OPpDEREF);
}
SETs(svp ? *svp : &PL_sv_undef);
RETURN;
}
#endif
} else if (class == my_pkg) {
DIE(aTHX_ err_no_ref);
}
return pp_helem();
}
static
OP* intercept_pp_hslice(pTHX)
{
dSP;
HV *hv=(HV*)POPs, *class=SvSTASH(hv);
SV **firstkey=PL_stack_base+TOPMARK+1;
if (firstkey <= SP) {
if (SvROK(*firstkey)) {
if (class != my_pkg) {
if (class!=0 || HvFILL(hv) || SvRMAGICAL(hv))
DIE(aTHX_ err_ref);
SvSTASH(hv)=my_pkg;
}
{
dMARK; dORIGMARK;
tmp_keysv tmp_key;
I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
HE *he;
if (PL_op->op_private & OPpLVAL_INTRO) {
DIE(aTHX_ err_no_local);
} else {
while (++MARK <= SP) {
SV *keysv=*MARK;
if (!SvROK(keysv)) DIE(aTHX_ err_no_ref);
keysv=ref2key(keysv, &tmp_key);
he=hv_fetch_ent(hv, keysv, lval, tmp_key.xpv.xuv_uv);
*MARK=he ? HeVAL(he) : &PL_sv_undef;
}
}
if (GIMME != G_ARRAY) {
MARK = ORIGMARK;
*++MARK = *SP;
SP = MARK;
}
}
RETURN;
}
else if (class == my_pkg) {
DIE(aTHX_ err_no_ref);
}
return pp_hslice();
}
RETURN;
}
static
OP* intercept_pp_exists(pTHX)
{
dSP;
tmp_keysv tmp_key;
if (!(PL_op->op_private & OPpEXISTS_SUB) && SvSTASH(TOPm1s) == my_pkg) {
SV *keysv=POPs;
HV *hv=(HV*)POPs;
if (!SvROK(keysv))
RETPUSHNO;
keysv=ref2key(keysv, &tmp_key);
if (hv_exists_ent(hv, keysv, tmp_key.xpv.xuv_uv))
RETPUSHYES;
else
RETPUSHNO;
}
return pp_exists();
}
static
OP* intercept_pp_delete(pTHX)
{
dSP;
tmp_keysv tmp_key;
SV *sv;
if (PL_op->op_private & OPpSLICE) {
HV *hv=(HV*)POPs;
if (SvSTASH(hv) == my_pkg) {
I32 gimme = GIMME_V;
I32 discard = (gimme == G_VOID) ? G_DISCARD : 0;
dMARK; dORIGMARK;
while (++MARK <= SP) {
SV *keysv=*MARK;
if (!SvROK(keysv))
DIE(aTHX_ err_no_ref);
keysv=ref2key(keysv, &tmp_key);
sv=hv_delete_ent(hv, keysv, discard, tmp_key.xpv.xuv_uv);
*MARK = sv ? sv : &PL_sv_undef;
}
if (discard)
SP = ORIGMARK;
else if (gimme == G_SCALAR) {
MARK = ORIGMARK;
*++MARK = *SP;
SP = MARK;
}
RETURN;
}
} else if (SvSTASH(TOPm1s) == my_pkg) {
SV *keysv = POPs;
HV *hv=(HV*)POPs;
I32 discard = (GIMME_V == G_VOID) ? G_DISCARD : 0;
if (!SvROK(keysv))
DIE(aTHX_ err_no_ref);
keysv=ref2key(keysv,&tmp_key);
sv=hv_delete_ent(hv, keysv, discard, tmp_key.xpv.xuv_uv);
if (!discard) {
if (!sv) sv = &PL_sv_undef;
PUSHs(sv);
}
RETURN;
}
return pp_delete();
}
static
void key2ref(SV *keysv)
{
U32 flags=SVf_FAKE | SVf_READONLY | SVf_POK | SVp_POK | SVf_ROK;
key_or_ptr obj;
obj.ptr=*(SV**)SvPVX(keysv);
if (obj.key & 1) {
obj.key ^= 1;
flags |= SVf_AMAGIC;
}
SvFLAGS(keysv) ^= flags;
SvRV(keysv)=obj.ptr;
SvREFCNT_inc(obj.ptr);
}
static
OP* intercept_pp_each(pTHX)
{
dSP;
if (SvSTASH(TOPs) == my_pkg) {
I32 sp_dist=SP-PL_stack_base;
OP *ret=pp_each();
sp=PL_stack_base+sp_dist;
if (PL_stack_sp >= sp) key2ref(*sp);
return ret;
}
return pp_each();
}
static
OP* intercept_pp_keys(pTHX)
{
dSP;
if (SvSTASH(TOPs) == my_pkg && GIMME == G_ARRAY) {
I32 sp_dist=SP-PL_stack_base;
OP *ret=pp_keys();
SV **last=PL_stack_sp;
for (sp=PL_stack_base+sp_dist; sp <= last; ++sp)
key2ref(*sp);
return ret;
}
return pp_keys();
}
/* aassign isn't intercepted directly, since it is used very often and not only with hashes.
Instead, this routine is called from rv2hv and padhv when necessary */
static
OP* ref_assign(pTHX)
{
dSP;
I32 gimme;
HV *hv=(HV*)POPs, *class=SvSTASH(hv);
SV **lastR=PL_stack_base+TOPMARK, **firstR=PL_stack_base+PL_markstack_ptr[-1]+1;
I32 assign_other=lastR != SP;
if (assign_other) {
SV **lhs=lastR+1;
do {
I32 type=SvTYPE(*lhs);
if (type == SVt_PVAV || type == SVt_PVHV) {
firstR=lastR;
break;
}
++firstR;
} while (++lhs < SP);
}
if (firstR < lastR && SvROK(*firstR)) {
if (class != my_pkg) {
if (class!=0 || HvFILL(hv) || SvRMAGICAL(hv))
DIE(aTHX_ err_ref);
SvSTASH(hv)=my_pkg;
}
/* the assignment loop is borrowed from the appropriate branch in pp_aassign */
gimme = GIMME_V;
hv_clear(hv);
do {
tmp_keysv tmp_key;
SV *keysv=*(firstR++), *tmp_val;
if (!keysv || !SvROK(keysv))
DIE(aTHX_ err_no_ref);
keysv=ref2key(keysv, &tmp_key);
tmp_val = NEWSV(29,0); /* value */
if (*firstR)
sv_setsv(tmp_val,*firstR);
*(firstR++) = tmp_val;
hv_store_ent(hv,keysv,tmp_val,tmp_key.xpv.xuv_uv);
} while (firstR < lastR);
if (firstR == lastR) {
SV *keysv=*firstR;
if (!keysv || !SvROK(keysv))
DIE(aTHX_ err_no_ref);
if (SvSTASH(SvRV(keysv)) == my_pkg)
DIE(aTHX_ "RefHash object assignment in list context");
else
DIE(aTHX_ "Key without value in hash assignment");
}
if (assign_other) {
PUTBACK;
pp_aassign();
if (gimme == G_ARRAY)
SP=lastR;
} else {
PL_markstack_ptr-=2;
if (gimme == G_VOID)
SP=firstR-1;
else if (gimme == G_ARRAY)
SP=lastR;
else {
dTARGET;
SP = firstR;
SETi(HvFILL(hv)*2);
}
}
RETURN;
}
if (class==my_pkg) SvSTASH(hv)=0;
return pp_aassign();
}
static
OP* pp_pushhv(pTHX)
{
dSP; dMARK; dORIGMARK;
HV *hv=(HV*)*++MARK, *class=SvSTASH(hv);
SV *keysv, *value, *tmp_val;
if (!class && !HvFILL(hv) && MARK < SP && SvROK(MARK[1]))
class=SvSTASH(hv)=my_pkg;
if (class==my_pkg) {
tmp_keysv tmp_key;
while (MARK < SP) {
keysv=*++MARK;
if (!SvROK(keysv))
DIE(aTHX_ err_no_ref);
keysv=ref2key(keysv, &tmp_key);
value=*++MARK;
tmp_val = NEWSV(29,0); /* copy of the value */
if (value) sv_setsv(tmp_val,value);
hv_store_ent(hv, keysv, tmp_val, tmp_key.xpv.xuv_uv);
}
} else {
while (MARK < SP) {
keysv=*++MARK;
if (SvROK(keysv))
DIE(aTHX_ err_ref);
value=*++MARK;
tmp_val = NEWSV(29,0); /* copy of the value */
if (value) sv_setsv(tmp_val,value);
#ifdef not_PERL_5_8
hv_store_ent(hv, keysv, tmp_val, 0);
#else
hv_store_ent(hv, keysv, tmp_val, SvUVX(keysv));
#endif
}
}
SP=ORIGMARK;
RETURN;
}
static
OP* pp_rv2hv_ref_retrieve(pTHX)
{
dSP;
I32 sp_dist=SP-PL_stack_base;
OP *ret=pp_rv2hv();
SV **last=PL_stack_sp;
for (SP=PL_stack_base+sp_dist; SP < last; SP+=2)
key2ref(*SP);
return ret;
}
static
OP* pp_padhv_ref_retrieve(pTHX)
{
dSP;
I32 sp_dist=SP-PL_stack_base+1;
OP *ret=pp_padhv();
SV **last=PL_stack_sp;
for (SP=PL_stack_base+sp_dist; SP < last; SP+=2)
key2ref(*SP);
return ret;
}
static
OP* intercept_pp_rv2hv(pTHX)
{
dSP;
if (PL_op->op_flags & OPf_REF) {
if (PL_op->op_next->op_ppaddr == &Perl_pp_aassign) {
PL_op=pp_rv2hv();
return ref_assign(aTHX);
}
} else if (GIMME == G_ARRAY) {
HV *hv=(HV*)TOPs, *class;
if (SvROK(hv) && SvSTASH(SvRV(hv)) == my_pkg) { /* the easiest and most often case */
return pp_rv2hv_ref_retrieve(aTHX);
}
SAVEI8(PL_op->op_flags); /* just for the case the op dies */
PL_op->op_flags ^= OPf_REF;
pp_rv2hv(); /* get the hash */
PL_op->op_flags ^= OPf_REF;
hv=(HV*)TOPs; class=SvSTASH(hv);
if (class == my_pkg) {
return pp_rv2hv_ref_retrieve(aTHX);
}
}
return pp_rv2hv();
}
static
OP* intercept_pp_padhv(pTHX)
{
if (PL_op->op_flags & OPf_REF) {
if (PL_op->op_next->op_ppaddr == &Perl_pp_aassign) {
PL_op=pp_padhv();
return ref_assign(aTHX);
}
} else if (GIMME == G_ARRAY) {
dTARGET;
HV *hv=(HV*)TARG, *class=SvSTASH(hv);
if (class == my_pkg) {
return pp_padhv_ref_retrieve(aTHX);
}
}
return pp_padhv();
}
static
OP* pp_ref_anonhash(pTHX)
{
dSP; dMARK; dORIGMARK;
HV* hv = (HV*)sv_2mortal((SV*)newHV());
tmp_keysv tmp_key;
SV *keysv, *val;
while (++MARK < SP) {
keysv = *MARK;
if (!SvROK(keysv))
DIE(aTHX_ err_no_ref);
keysv=ref2key(keysv, &tmp_key);
val = NEWSV(46, 0);
if (MARK < SP)
sv_setsv(val, *++MARK);
(void)hv_store_ent(hv,keysv,val,tmp_key.xpv.xuv_uv);
}
SP = ORIGMARK;
XPUSHs((SV*)hv);
SvSTASH(hv)=my_pkg;
RETURN;
}
static
OP* intercept_pp_anonhash(pTHX)
{
dSP;
SV **firstkey=PL_stack_base+TOPMARK+1;
if (firstkey<SP && SvROK(*firstkey))
return pp_ref_anonhash(aTHX);
return pp_anonhash();
}
static
OP* check_pushhv(pTHX_ OP *o)
{
if (o->op_flags & OPf_KIDS) {
OP *kid=cLISTOPo->op_first;
if (kid->op_type == OP_PUSHMARK ||
(kid->op_type == OP_NULL && kid->op_targ == OP_PUSHMARK))
kid = kid->op_sibling;
if (kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV) {
int arg_cnt=2;
Perl_mod(aTHX_ kid, o->op_type);
while ((kid=kid->op_sibling)) {
if (kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV) {
Perl_list(aTHX_ kid);
} else {
Perl_yyerror(aTHX_ Perl_form(aTHX_ "Type of arg %d to push must be hash (not %s)", arg_cnt, OP_DESC(kid)));
}
++arg_cnt;
}
o->op_ppaddr=&pp_pushhv;
return o;
}
}
return ck_fun(o);
}
static
OP* intercept_pp_const(pTHX)
{
SV *sv=cSVOP_sv;
if ((PL_op->op_private & OPpCONST_BARE) && SvTYPE(sv)==SVt_PV)
SvIsUV_on(sv);
PL_op->op_ppaddr=&Perl_pp_const;
return pp_const();
}
#ifndef PERL_UNUSED_VAR
# define PERL_UNUSED_VAR(var) if (0) var = var
#endif
#line 545 "RefHash.c"
XS(XS_Poly_is_keyword); /* prototype to pass -Wmissing-prototypes */
XS(XS_Poly_is_keyword)
{
#ifdef dVAR
dVAR; dXSARGS;
#else
dXSARGS;
#endif
if (items != 1)
Perl_croak(aTHX_ "Usage: %s(%s)", "Poly::is_keyword", "sv");
PERL_UNUSED_VAR(cv); /* -W */
PERL_UNUSED_VAR(ax); /* -Wall */
SP -= items;
{
SV * sv = ST(0);
#line 539 "RefHash.xs"
{
if (SvIsUV(sv))
PUSHs(&PL_sv_yes);
else
PUSHs(&PL_sv_no);
}
#line 569 "RefHash.c"
PUTBACK;
return;
}
}
#ifdef __cplusplus
extern "C"
#endif
XS(boot_RefHash); /* prototype to pass -Wmissing-prototypes */
XS(boot_RefHash)
{
#ifdef dVAR
dVAR; dXSARGS;
#else
dXSARGS;
#endif
char* file = __FILE__;
PERL_UNUSED_VAR(cv); /* -W */
PERL_UNUSED_VAR(items); /* -W */
XS_VERSION_BOOTCHECK ;
newXS("Poly::is_keyword", XS_Poly_is_keyword, file);
/* Initialisation Section */
#line 548 "RefHash.xs"
PL_ppaddr[OP_CONST]=&intercept_pp_const;
PL_ppaddr[OP_HELEM]=&intercept_pp_helem;
PL_ppaddr[OP_HSLICE]=&intercept_pp_hslice;
PL_ppaddr[OP_EXISTS]=&intercept_pp_exists;
PL_ppaddr[OP_DELETE]=&intercept_pp_delete;
PL_ppaddr[OP_EACH]=&intercept_pp_each;
PL_ppaddr[OP_KEYS]=&intercept_pp_keys;
PL_ppaddr[OP_RV2HV]=&intercept_pp_rv2hv;
PL_ppaddr[OP_PADHV]=&intercept_pp_padhv;
PL_ppaddr[OP_ANONHASH]=&intercept_pp_anonhash;
PL_check[OP_PUSH]=&check_pushhv;
my_pkg=gv_stashpv("RefHash", FALSE);
#line 610 "RefHash.c"
/* End of Initialisation Section */
XSRETURN_YES;
}
syntax highlighted by Code2HTML, v. 0.9.1