1898184e3Ssthen #define PERL_NO_GET_CONTEXT 2898184e3Ssthen 343003dfeSmillert #include "EXTERN.h" 443003dfeSmillert #include "perl.h" 543003dfeSmillert #include "XSUB.h" 643003dfeSmillert 743003dfeSmillert /* support for Hash::Util::FieldHash, prefix HUF_ */ 843003dfeSmillert 943003dfeSmillert /* A Perl sub that returns a hashref to the object registry */ 1043003dfeSmillert #define HUF_OB_REG "Hash::Util::FieldHash::_ob_reg" 1143003dfeSmillert /* Identifier for PERL_MAGIC_ext magic */ 1243003dfeSmillert #define HUF_IDCACHE 0x4944 1343003dfeSmillert 1443003dfeSmillert /* For global cache of object registry */ 1543003dfeSmillert #define MY_CXT_KEY "Hash::Util::FieldHash::_guts" XS_VERSION 1643003dfeSmillert typedef struct { 1743003dfeSmillert HV* ob_reg; /* Cache object registry */ 1843003dfeSmillert } my_cxt_t; 1943003dfeSmillert START_MY_CXT 2043003dfeSmillert 2143003dfeSmillert /* Inquire the object registry (a lexical hash) from perl */ 22b8851fccSafresh1 static HV * 23898184e3Ssthen HUF_get_ob_reg(pTHX) { 2443003dfeSmillert dSP; 2543003dfeSmillert HV* ob_reg = NULL; 2643003dfeSmillert I32 items; 2743003dfeSmillert ENTER; 2843003dfeSmillert SAVETMPS; 2943003dfeSmillert 3043003dfeSmillert PUSHMARK(SP); 3143003dfeSmillert items = call_pv(HUF_OB_REG, G_SCALAR|G_NOARGS); 3243003dfeSmillert SPAGAIN; 3343003dfeSmillert 3443003dfeSmillert if (items == 1 && TOPs && SvROK(TOPs) && SvTYPE(SvRV(TOPs)) == SVt_PVHV) 3543003dfeSmillert ob_reg = (HV*)SvRV(POPs); 3643003dfeSmillert PUTBACK; 3743003dfeSmillert FREETMPS; 3843003dfeSmillert LEAVE; 3943003dfeSmillert 4043003dfeSmillert if (!ob_reg) 4143003dfeSmillert Perl_die(aTHX_ "Can't get object registry hash"); 4243003dfeSmillert return ob_reg; 4343003dfeSmillert } 4443003dfeSmillert 4543003dfeSmillert /* Deal with global context */ 4643003dfeSmillert #define HUF_INIT 1 4743003dfeSmillert #define HUF_CLONE 0 4843003dfeSmillert #define HUF_RESET -1 4943003dfeSmillert 50b8851fccSafresh1 static void 51898184e3Ssthen HUF_global(pTHX_ I32 how) { 5243003dfeSmillert if (how == HUF_INIT) { 5343003dfeSmillert MY_CXT_INIT; 54898184e3Ssthen MY_CXT.ob_reg = HUF_get_ob_reg(aTHX); 5543003dfeSmillert } else if (how == HUF_CLONE) { 5643003dfeSmillert MY_CXT_CLONE; 57898184e3Ssthen MY_CXT.ob_reg = HUF_get_ob_reg(aTHX); 5843003dfeSmillert } else if (how == HUF_RESET) { 5943003dfeSmillert dMY_CXT; 60898184e3Ssthen MY_CXT.ob_reg = HUF_get_ob_reg(aTHX); 6143003dfeSmillert } 6243003dfeSmillert } 6343003dfeSmillert 6443003dfeSmillert /* Object id */ 6543003dfeSmillert 6643003dfeSmillert /* definition of id transformation */ 6743003dfeSmillert #define HUF_OBJ_ID(x) newSVuv(PTR2UV(x)) 6843003dfeSmillert 69b8851fccSafresh1 static SV * 70898184e3Ssthen HUF_obj_id(pTHX_ SV *obj) { 7143003dfeSmillert SV *item = SvRV(obj); 7243003dfeSmillert MAGIC *mg; 7343003dfeSmillert SV *id; 7443003dfeSmillert 7543003dfeSmillert /* Get cached object ID, if it exists */ 7643003dfeSmillert if (SvTYPE(item) >= SVt_PVMG) { 7743003dfeSmillert for ( mg = SvMAGIC(item); mg; mg = mg->mg_moremagic ) { 7843003dfeSmillert if ((mg->mg_type == PERL_MAGIC_ext) && 7943003dfeSmillert (mg->mg_private == HUF_IDCACHE) 8043003dfeSmillert ) { 8143003dfeSmillert return mg->mg_obj; 8243003dfeSmillert } 8343003dfeSmillert } 8443003dfeSmillert } 8543003dfeSmillert 8643003dfeSmillert /* Create an object ID, cache it */ 8743003dfeSmillert id = HUF_OBJ_ID(item); 8843003dfeSmillert mg = sv_magicext(item, id, PERL_MAGIC_ext, NULL, NULL, 0); 8943003dfeSmillert mg->mg_private = HUF_IDCACHE; 9043003dfeSmillert SvREFCNT_dec(id); /* refcnt++ in sv_magicext() */ 9143003dfeSmillert 9243003dfeSmillert /* Return the object ID */ 9343003dfeSmillert return id; 9443003dfeSmillert } 9543003dfeSmillert 9643003dfeSmillert /* set up uvar magic for any sv */ 97b8851fccSafresh1 static void 98898184e3Ssthen HUF_add_uvar_magic( 99898184e3Ssthen pTHX_ 10043003dfeSmillert SV* sv, /* the sv to enchant, visible to get/set */ 10143003dfeSmillert I32(* val)(pTHX_ IV, SV*), /* "get" function */ 10243003dfeSmillert I32(* set)(pTHX_ IV, SV*), /* "set" function */ 10343003dfeSmillert I32 index, /* get/set will see this */ 10443003dfeSmillert SV* thing /* any associated info */ 10543003dfeSmillert ) { 10643003dfeSmillert struct ufuncs uf; 10743003dfeSmillert uf.uf_val = val; 10843003dfeSmillert uf.uf_set = set; 10943003dfeSmillert uf.uf_index = index; 11043003dfeSmillert sv_magic(sv, thing, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf)); 11143003dfeSmillert } 11243003dfeSmillert 11343003dfeSmillert /* Fetch the data container of a trigger */ 114b8851fccSafresh1 static AV * 115898184e3Ssthen HUF_get_trigger_content(pTHX_ SV *trigger) { 11643003dfeSmillert MAGIC* mg; 11743003dfeSmillert if (trigger && (mg = mg_find(trigger, PERL_MAGIC_uvar))) 11843003dfeSmillert return (AV*)mg->mg_obj; 11943003dfeSmillert return NULL; 12043003dfeSmillert } 12143003dfeSmillert 12243003dfeSmillert /* Delete an object from all field hashes it may occur in. Also delete 12343003dfeSmillert * the object's entry from the object registry. This function goes in 12443003dfeSmillert * the uf_set field of the uvar magic of a trigger. 12543003dfeSmillert */ 126b8851fccSafresh1 static I32 HUF_destroy_obj(pTHX_ IV index, SV *trigger) { 127898184e3Ssthen PERL_UNUSED_ARG(index); 12843003dfeSmillert /* Do nothing if the weakref wasn't undef'd. Also don't bother 12943003dfeSmillert * during global destruction. (MY_CXT.ob_reg is sometimes funny there) */ 13043003dfeSmillert if (!SvROK(trigger) && (!PL_in_clean_all)) { 13143003dfeSmillert dMY_CXT; 132898184e3Ssthen AV* cont = HUF_get_trigger_content(aTHX_ trigger); 13343003dfeSmillert SV* ob_id = *av_fetch(cont, 0, 0); 13443003dfeSmillert HV* field_tab = (HV*) *av_fetch(cont, 1, 0); 13543003dfeSmillert HE* ent; 13643003dfeSmillert hv_iterinit(field_tab); 137898184e3Ssthen while ((ent = hv_iternext(field_tab))) { 13843003dfeSmillert SV* field_ref = HeVAL(ent); 13943003dfeSmillert SV* field = SvRV(field_ref); 140898184e3Ssthen (void) hv_delete_ent((HV*)field, ob_id, 0, 0); 14143003dfeSmillert } 14243003dfeSmillert /* make it safe in case we must run in global clenaup, after all */ 14343003dfeSmillert if (PL_in_clean_all) 144898184e3Ssthen HUF_global(aTHX_ HUF_RESET); /* shoudn't be needed */ 145898184e3Ssthen (void) hv_delete_ent(MY_CXT.ob_reg, ob_id, 0, 0); 14643003dfeSmillert } 14743003dfeSmillert return 0; 14843003dfeSmillert } 14943003dfeSmillert 15043003dfeSmillert /* Create a trigger for an object. The trigger is a magical SV 15143003dfeSmillert * that holds a weak ref to the object. The magic fires when the object 15243003dfeSmillert * expires and takes care of garbage collection in registred hashes. 15343003dfeSmillert * For that purpose, the magic structure holds the original id of 15443003dfeSmillert * the object, and a list (a hash, really) of hashes from which the 15543003dfeSmillert * object may * have to be deleted. The trigger is stored in the 15643003dfeSmillert * object registry and is also deleted when the object expires. 15743003dfeSmillert */ 158b8851fccSafresh1 static SV * 159898184e3Ssthen HUF_new_trigger(pTHX_ SV *obj, SV *ob_id) { 16043003dfeSmillert dMY_CXT; 16143003dfeSmillert SV* trigger = sv_rvweaken(newRV_inc(SvRV(obj))); 162*3d61058aSafresh1 AV* cont = newAV_mortal(); 163*3d61058aSafresh1 av_store_simple(cont, 0, SvREFCNT_inc(ob_id)); 164*3d61058aSafresh1 av_store_simple(cont, 1, (SV*)newHV()); 165898184e3Ssthen HUF_add_uvar_magic(aTHX_ trigger, NULL, &HUF_destroy_obj, 0, (SV*)cont); 166898184e3Ssthen (void) hv_store_ent(MY_CXT.ob_reg, ob_id, trigger, 0); 16743003dfeSmillert return trigger; 16843003dfeSmillert } 16943003dfeSmillert 17043003dfeSmillert /* retrieve a trigger for obj if one exists, return NULL otherwise */ 171b8851fccSafresh1 static SV * 172898184e3Ssthen HUF_ask_trigger(pTHX_ SV *ob_id) { 17343003dfeSmillert dMY_CXT; 17443003dfeSmillert HE* ent; 175898184e3Ssthen if ((ent = hv_fetch_ent(MY_CXT.ob_reg, ob_id, 0, 0))) 17643003dfeSmillert return HeVAL(ent); 17743003dfeSmillert return NULL; 17843003dfeSmillert } 17943003dfeSmillert 180b8851fccSafresh1 static SV * 181898184e3Ssthen HUF_get_trigger(pTHX_ SV *obj, SV *ob_id) { 182898184e3Ssthen SV* trigger = HUF_ask_trigger(aTHX_ ob_id); 18343003dfeSmillert if (!trigger) 184898184e3Ssthen trigger = HUF_new_trigger(aTHX_ obj, ob_id); 18543003dfeSmillert return( trigger); 18643003dfeSmillert } 18743003dfeSmillert 18843003dfeSmillert /* mark an object (trigger) as having been used with a field 18943003dfeSmillert (a clenup-liability) 19043003dfeSmillert */ 191b8851fccSafresh1 static void 192898184e3Ssthen HUF_mark_field(pTHX_ SV *trigger, SV *field) { 193898184e3Ssthen AV* cont = HUF_get_trigger_content(aTHX_ trigger); 19443003dfeSmillert HV* field_tab = (HV*) *av_fetch(cont, 1, 0); 19543003dfeSmillert SV* field_ref = newRV_inc(field); 19643003dfeSmillert UV field_addr = PTR2UV(field); 197898184e3Ssthen (void) hv_store(field_tab, (char *)&field_addr, sizeof(field_addr), field_ref, 0); 19843003dfeSmillert } 19943003dfeSmillert 20043003dfeSmillert /* Determine, from the value of action, whether this call may create a new 20143003dfeSmillert * hash key */ 20243003dfeSmillert #define HUF_WOULD_CREATE_KEY(x) ((x) != HV_DELETE && ((x) & (HV_FETCH_ISSTORE | HV_FETCH_LVALUE))) 20343003dfeSmillert 20443003dfeSmillert /* The key exchange functions. They communicate with S_hv_magic_uvar_xkey 20543003dfeSmillert * in hv.c */ 206b8851fccSafresh1 static I32 HUF_watch_key_safe(pTHX_ IV action, SV* field) { 20743003dfeSmillert MAGIC* mg = mg_find(field, PERL_MAGIC_uvar); 20843003dfeSmillert SV* keysv; 20943003dfeSmillert if (mg && (keysv = mg->mg_obj)) { 21043003dfeSmillert if (SvROK(keysv)) { /* ref key */ 211898184e3Ssthen SV* ob_id = HUF_obj_id(aTHX_ keysv); 21243003dfeSmillert mg->mg_obj = ob_id; /* key replacement */ 21343003dfeSmillert if (HUF_WOULD_CREATE_KEY(action)) { 214898184e3Ssthen SV* trigger = HUF_get_trigger(aTHX_ keysv, ob_id); 215898184e3Ssthen HUF_mark_field(aTHX_ trigger, field); 21643003dfeSmillert } 21743003dfeSmillert } else if (HUF_WOULD_CREATE_KEY(action)) { /* string key */ 21843003dfeSmillert /* registered as object id? */ 21943003dfeSmillert SV* trigger; 220898184e3Ssthen if (( trigger = HUF_ask_trigger(aTHX_ keysv))) 221898184e3Ssthen HUF_mark_field(aTHX_ trigger, field); 22243003dfeSmillert } 22343003dfeSmillert } else { 22443003dfeSmillert Perl_die(aTHX_ "Rogue call of 'HUF_watch_key_safe'"); 22543003dfeSmillert } 22643003dfeSmillert return 0; 22743003dfeSmillert } 22843003dfeSmillert 229b8851fccSafresh1 static I32 HUF_watch_key_id(pTHX_ IV action, SV* field) { 23043003dfeSmillert MAGIC* mg = mg_find(field, PERL_MAGIC_uvar); 23143003dfeSmillert SV* keysv; 232898184e3Ssthen PERL_UNUSED_ARG(action); 23343003dfeSmillert if (mg && (keysv = mg->mg_obj)) { 23443003dfeSmillert if (SvROK(keysv)) /* ref key */ 235898184e3Ssthen mg->mg_obj = HUF_obj_id(aTHX_ keysv); /* key replacement */ 23643003dfeSmillert } else { 23743003dfeSmillert Perl_die(aTHX_ "Rogue call of 'HUF_watch_key_id'"); 23843003dfeSmillert } 23943003dfeSmillert return 0; 24043003dfeSmillert } 24143003dfeSmillert 242b8851fccSafresh1 static int HUF_func_2mode( I32(* val)(pTHX_ IV, SV*)) { 24343003dfeSmillert int ans = 0; 24443003dfeSmillert if (val == &HUF_watch_key_id) 24543003dfeSmillert ans = 1; 24643003dfeSmillert if (val == &HUF_watch_key_safe) 24743003dfeSmillert ans = 2; 24843003dfeSmillert return(ans); 24943003dfeSmillert } 25043003dfeSmillert 251b8851fccSafresh1 static I32(* HUF_mode_2func( int mode))(pTHX_ IV, SV*) { 25243003dfeSmillert I32(* ans)(pTHX_ IV, SV*) = NULL; 25343003dfeSmillert switch (mode) { 25443003dfeSmillert case 1: 25543003dfeSmillert ans = &HUF_watch_key_id; 25643003dfeSmillert break; 25743003dfeSmillert case 2: 25843003dfeSmillert ans = &HUF_watch_key_safe; 25943003dfeSmillert break; 26043003dfeSmillert } 26143003dfeSmillert return(ans); 26243003dfeSmillert } 26343003dfeSmillert 26443003dfeSmillert /* see if something is a field hash */ 265b8851fccSafresh1 static int 266898184e3Ssthen HUF_get_status(pTHX_ HV *hash) { 26743003dfeSmillert int ans = 0; 26843003dfeSmillert if (hash && (SvTYPE(hash) == SVt_PVHV)) { 26943003dfeSmillert MAGIC* mg; 27043003dfeSmillert struct ufuncs* uf; 27143003dfeSmillert if ((mg = mg_find((SV*)hash, PERL_MAGIC_uvar)) && 27243003dfeSmillert (uf = (struct ufuncs *)mg->mg_ptr) && 27343003dfeSmillert (uf->uf_set == NULL) 27443003dfeSmillert ) { 27543003dfeSmillert ans = HUF_func_2mode(uf->uf_val); 27643003dfeSmillert } 27743003dfeSmillert } 27843003dfeSmillert return ans; 27943003dfeSmillert } 28043003dfeSmillert 28143003dfeSmillert /* Thread support. These routines are called by CLONE (and nothing else) */ 28243003dfeSmillert 28343003dfeSmillert /* Fix entries for one object in all field hashes */ 284b8851fccSafresh1 static void 285898184e3Ssthen HUF_fix_trigger(pTHX_ SV *trigger, SV *new_id) { 286898184e3Ssthen AV* cont = HUF_get_trigger_content(aTHX_ trigger); 28743003dfeSmillert HV* field_tab = (HV*) *av_fetch(cont, 1, 0); 28843003dfeSmillert HV* new_tab = newHV(); 28943003dfeSmillert HE* ent; 29043003dfeSmillert SV* old_id = *av_fetch(cont, 0, 0); 291eac174f2Safresh1 I32 entries = hv_iterinit(field_tab); 292eac174f2Safresh1 hv_ksplit(new_tab, entries); 293898184e3Ssthen while ((ent = hv_iternext(field_tab))) { 29443003dfeSmillert SV* field_ref = HeVAL(ent); 29543003dfeSmillert HV* field = (HV*)SvRV(field_ref); 29643003dfeSmillert UV field_addr = PTR2UV(field); 29743003dfeSmillert SV* val; 29843003dfeSmillert /* recreate field tab entry */ 299898184e3Ssthen (void) hv_store(new_tab, (char *)&field_addr, sizeof(field_addr), SvREFCNT_inc(field_ref), 0); 30043003dfeSmillert /* recreate field entry, if any */ 301898184e3Ssthen if ((val = hv_delete_ent(field, old_id, 0, 0))) 302898184e3Ssthen (void) hv_store_ent(field, new_id, SvREFCNT_inc(val), 0); 30343003dfeSmillert } 30443003dfeSmillert /* update the trigger */ 30543003dfeSmillert av_store(cont, 0, SvREFCNT_inc(new_id)); 30643003dfeSmillert av_store(cont, 1, (SV*)new_tab); 30743003dfeSmillert } 30843003dfeSmillert 30943003dfeSmillert /* Go over object registry and fix all objects. Also fix the object 31043003dfeSmillert * registry. 31143003dfeSmillert */ 312b8851fccSafresh1 static void 313898184e3Ssthen HUF_fix_objects(pTHX) { 31443003dfeSmillert dMY_CXT; 31543003dfeSmillert I32 i, len; 31643003dfeSmillert HE* ent; 317*3d61058aSafresh1 AV* oblist = newAV_mortal(); 31843003dfeSmillert hv_iterinit(MY_CXT.ob_reg); 319898184e3Ssthen while((ent = hv_iternext(MY_CXT.ob_reg))) 320*3d61058aSafresh1 av_push_simple(oblist, SvREFCNT_inc(hv_iterkeysv(ent))); 321eac174f2Safresh1 len = av_count(oblist); 322eac174f2Safresh1 for (i = 0; i < len; ++i) { 323*3d61058aSafresh1 SV* old_id = *av_fetch_simple(oblist, i, 0); 32443003dfeSmillert SV* trigger = hv_delete_ent(MY_CXT.ob_reg, old_id, 0, 0); 32543003dfeSmillert SV* obj = SvRV(trigger); 32643003dfeSmillert MAGIC *mg; 32743003dfeSmillert 32843003dfeSmillert SV* new_id = HUF_OBJ_ID(obj); 32943003dfeSmillert 33043003dfeSmillert /* Replace cached object ID with this new one */ 33143003dfeSmillert for (mg = SvMAGIC(obj); mg; mg = mg->mg_moremagic) { 33243003dfeSmillert if ((mg->mg_type == PERL_MAGIC_ext) && 33343003dfeSmillert (mg->mg_private == HUF_IDCACHE) 33443003dfeSmillert ) { 33543003dfeSmillert mg->mg_obj = new_id; 33643003dfeSmillert } 33743003dfeSmillert } 33843003dfeSmillert 339898184e3Ssthen HUF_fix_trigger(aTHX_ trigger, new_id); 340898184e3Ssthen (void) hv_store_ent(MY_CXT.ob_reg, new_id, SvREFCNT_inc(trigger), 0); 34143003dfeSmillert } 34243003dfeSmillert } 34343003dfeSmillert 34443003dfeSmillert /* test support (not needed for functionality) */ 34543003dfeSmillert 34643003dfeSmillert static SV* counter; 34743003dfeSmillert I32 HUF_inc_var(pTHX_ IV index, SV* which) { 348898184e3Ssthen PERL_UNUSED_ARG(index); 349898184e3Ssthen PERL_UNUSED_ARG(which); 35043003dfeSmillert sv_setiv(counter, 1 + SvIV(counter)); 35143003dfeSmillert return 0; 35243003dfeSmillert } 35343003dfeSmillert 35443003dfeSmillert MODULE = Hash::Util::FieldHash PACKAGE = Hash::Util::FieldHash 35543003dfeSmillert 35643003dfeSmillert BOOT: 35743003dfeSmillert { 358898184e3Ssthen HUF_global(aTHX_ HUF_INIT); /* create variables */ 35943003dfeSmillert } 36043003dfeSmillert 36143003dfeSmillert int 36243003dfeSmillert _fieldhash(SV* href, int mode) 36343003dfeSmillert PROTOTYPE: $$ 36443003dfeSmillert CODE: 36543003dfeSmillert HV* field; 36643003dfeSmillert RETVAL = 0; 36743003dfeSmillert if (mode && 36843003dfeSmillert href && SvROK(href) && 36943003dfeSmillert (field = (HV*)SvRV(href)) && 37043003dfeSmillert SvTYPE(field) == SVt_PVHV 37143003dfeSmillert ) { 37243003dfeSmillert 37343003dfeSmillert HUF_add_uvar_magic( 374898184e3Ssthen aTHX_ 37543003dfeSmillert SvRV(href), 37643003dfeSmillert HUF_mode_2func(mode), 37743003dfeSmillert NULL, 37843003dfeSmillert 0, 37943003dfeSmillert NULL 38043003dfeSmillert ); 381898184e3Ssthen RETVAL = HUF_get_status(aTHX_ field); 38243003dfeSmillert } 38343003dfeSmillert OUTPUT: 38443003dfeSmillert RETVAL 38543003dfeSmillert 38643003dfeSmillert void 38743003dfeSmillert id(SV* ref) 38843003dfeSmillert PROTOTYPE: $ 38943003dfeSmillert PPCODE: 39043003dfeSmillert if (SvROK(ref)) { 391898184e3Ssthen XPUSHs(HUF_obj_id(aTHX_ ref)); 39243003dfeSmillert } else { 39343003dfeSmillert XPUSHs(ref); 39443003dfeSmillert } 39543003dfeSmillert 39643003dfeSmillert SV* 39743003dfeSmillert id_2obj(SV* id) 39843003dfeSmillert PROTOTYPE: $ 39943003dfeSmillert CODE: 400898184e3Ssthen SV* obj = HUF_ask_trigger(aTHX_ id); 40143003dfeSmillert if (obj) { 40243003dfeSmillert RETVAL = newRV_inc(SvRV(obj)); 40343003dfeSmillert } else { 40443003dfeSmillert RETVAL = &PL_sv_undef; 40543003dfeSmillert } 40643003dfeSmillert OUTPUT: 40743003dfeSmillert RETVAL 40843003dfeSmillert 40943003dfeSmillert SV* 41043003dfeSmillert register(SV* obj, ...) 41143003dfeSmillert PROTOTYPE: $@ 41243003dfeSmillert CODE: 41343003dfeSmillert SV* trigger; 41443003dfeSmillert int i; 41543003dfeSmillert RETVAL = NULL; 41643003dfeSmillert if (!SvROK(obj)) { 41743003dfeSmillert Perl_die(aTHX_ "Attempt to register a non-ref"); 41843003dfeSmillert } else { 41943003dfeSmillert RETVAL = newRV_inc(SvRV(obj)); 42043003dfeSmillert } 421898184e3Ssthen trigger = HUF_get_trigger(aTHX_ obj, HUF_obj_id(aTHX_ obj)); 42243003dfeSmillert for (i = 1; i < items; ++ i) { 42343003dfeSmillert SV* field_ref = POPs; 42443003dfeSmillert if (SvROK(field_ref) && (SvTYPE(SvRV(field_ref)) == SVt_PVHV)) { 425898184e3Ssthen HUF_mark_field(aTHX_ trigger, SvRV(field_ref)); 42643003dfeSmillert } 42743003dfeSmillert } 42843003dfeSmillert OUTPUT: 42943003dfeSmillert RETVAL 43043003dfeSmillert 43143003dfeSmillert void 43243003dfeSmillert CLONE(char* classname) 43343003dfeSmillert CODE: 4349f11ffb7Safresh1 if (strEQ(classname, "Hash::Util::FieldHash")) { 435898184e3Ssthen HUF_global(aTHX_ HUF_CLONE); 436898184e3Ssthen HUF_fix_objects(aTHX); 43743003dfeSmillert } 43843003dfeSmillert 43943003dfeSmillert void 44043003dfeSmillert _active_fields(SV* obj) 44143003dfeSmillert PPCODE: 44243003dfeSmillert if (SvROK(obj)) { 443898184e3Ssthen SV* ob_id = HUF_obj_id(aTHX_ obj); 444898184e3Ssthen SV* trigger = HUF_ask_trigger(aTHX_ ob_id); 44543003dfeSmillert if (trigger) { 446898184e3Ssthen AV* cont = HUF_get_trigger_content(aTHX_ trigger); 44743003dfeSmillert HV* field_tab = (HV*) *av_fetch(cont, 1, 0); 44843003dfeSmillert HE* ent; 44943003dfeSmillert hv_iterinit(field_tab); 450898184e3Ssthen while ((ent = hv_iternext(field_tab))) { 45143003dfeSmillert HV* field = (HV*)SvRV(HeVAL(ent)); 45243003dfeSmillert if (hv_exists_ent(field, ob_id, 0)) 45343003dfeSmillert XPUSHs(sv_2mortal(newRV_inc((SV*)field))); 45443003dfeSmillert } 45543003dfeSmillert } 45643003dfeSmillert } 45743003dfeSmillert 45843003dfeSmillert void 45943003dfeSmillert _test_uvar_get(SV* svref, SV* countref) 460898184e3Ssthen ALIAS: 461898184e3Ssthen _test_uvar_get = 1 462898184e3Ssthen _test_uvar_set = 2 463898184e3Ssthen _test_uvar_same = 3 46443003dfeSmillert CODE: 46543003dfeSmillert if (SvROK(svref) && SvROK(countref)) { 46643003dfeSmillert counter = SvRV(countref); 46743003dfeSmillert sv_setiv(counter, 0); 46843003dfeSmillert HUF_add_uvar_magic( 469898184e3Ssthen aTHX_ 47043003dfeSmillert SvRV(svref), 471898184e3Ssthen ix & 1 ? &HUF_inc_var : 0, 472898184e3Ssthen ix & 2 ? &HUF_inc_var : 0, 47343003dfeSmillert 0, 47443003dfeSmillert SvRV(countref) 47543003dfeSmillert ); 47643003dfeSmillert } 477