xref: /openbsd-src/gnu/usr.bin/perl/ext/Hash-Util-FieldHash/FieldHash.xs (revision 3d61058aa5c692477b6d18acfbbdb653a9930ff9)
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