#define NV double
#endif
+static int go_yell = 1;
+
/* Checks to see if thing is in the hash. Returns true or false, and
notes thing in the hash.
if (hv_exists(tracking_hash, (char *)&thing, sizeof(void *))) {
return FALSE;
}
- hv_store(tracking_hash, (char *)&thing, sizeof(void *), &PL_sv_undef, 0);
+ hv_store(tracking_hash, (char *)&thing, sizeof(void *), &PL_sv_yes, 0);
return TRUE;
}
if (cur_entry->hent_hek) {
/* Hash keys can be shared. Have we seen this before? */
if (check_new(tracking_hash, cur_entry->hent_hek)) {
- total_size += sizeof(HEK);
- total_size += cur_entry->hent_hek->hek_len - 1;
+ total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
}
}
cur_entry = cur_entry->hent_next;
break;
case SVt_PVCV:
total_size += sizeof(XPVCV);
- carp("CV isn't complete");
+ total_size += magic_size(thing, tracking_hash);
+ if (go_yell) {
+ carp("Devel::Size: Calculated sizes for CVs are incomplete");
+ }
break;
case SVt_PVGV:
+ total_size += magic_size(thing, tracking_hash);
total_size += sizeof(XPVGV);
- carp("GC isn't complete");
+ total_size += GvNAMELEN(thing);
+#ifdef GvFILE
+ /* Is there a file? */
+ if (GvFILE(thing)) {
+ if (check_new(tracking_hash, GvFILE(thing))) {
+ total_size += strlen(GvFILE(thing));
+ }
+ }
+#endif
+ /* Is there something hanging off the glob? */
+ if (GvGP(thing)) {
+ if (check_new(tracking_hash, GvGP(thing))) {
+ total_size += sizeof(GP);
+ {
+ SV *generic_thing;
+ if (generic_thing = (SV *)(GvGP(thing)->gp_sv)) {
+ total_size += thing_size(generic_thing, tracking_hash);
+ }
+ if (generic_thing = (SV *)(GvGP(thing)->gp_form)) {
+ total_size += thing_size(generic_thing, tracking_hash);
+ }
+ if (generic_thing = (SV *)(GvGP(thing)->gp_av)) {
+ total_size += thing_size(generic_thing, tracking_hash);
+ }
+ if (generic_thing = (SV *)(GvGP(thing)->gp_hv)) {
+ total_size += thing_size(generic_thing, tracking_hash);
+ }
+ if (generic_thing = (SV *)(GvGP(thing)->gp_egv)) {
+ total_size += thing_size(generic_thing, tracking_hash);
+ }
+ if (generic_thing = (SV *)(GvGP(thing)->gp_cv)) {
+ total_size += thing_size(generic_thing, tracking_hash);
+ }
+ }
+ }
+ }
break;
case SVt_PVFM:
total_size += sizeof(XPVFM);
- carp("FM isn't complete");
+ if (go_yell) {
+ carp("Devel::Size: Calculated sizes for FMs are incomplete");
+ }
break;
case SVt_PVIO:
total_size += sizeof(XPVIO);
- carp("IO isn't complete");
+ total_size += magic_size(thing, tracking_hash);
+ if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xpv_pv)) {
+ total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
+ }
+ /* Some embedded char pointers */
+ if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_top_name)) {
+ total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
+ }
+ if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
+ total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
+ }
+ if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
+ total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
+ }
+ /* Throw the GVs on the list to be walked if they're not-null */
+ if (((XPVIO *) SvANY(thing))->xio_top_gv) {
+ total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
+ tracking_hash);
+ }
+ if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
+ total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
+ tracking_hash);
+ }
+ if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
+ total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
+ tracking_hash);
+ }
+
+ /* Only go trotting through the IO structures if they're really
+ trottable. If USE_PERLIO is defined we can do this. If
+ not... we can't, so we don't even try */
+#ifdef USE_PERLIO
+ /* Dig into xio_ifp and xio_ofp here */
+ croak("Devel::Size: Can't size up perlio layers yet");
+#endif
break;
default:
- croak("Unknown variable type");
+ croak("Devel::Size: Unknown variable type");
}
return total_size;
}
-
MODULE = Devel::Size PACKAGE = Devel::Size
+PROTOTYPES: DISABLE
+
IV
size(orig_thing)
SV *orig_thing
SV *thing = orig_thing;
/* Hash to track our seen pointers */
HV *tracking_hash = newHV();
+ SV *warn_flag;
+
+ /* Check warning status */
+ go_yell = 0;
+
+ if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
+ go_yell = SvIV(warn_flag);
+ }
+
/* If they passed us a reference then dereference it. This is the
only way we can check the sizes of arrays and hashes */
/* Hash to track our seen pointers */
HV *tracking_hash = newHV();
AV *pending_array = newAV();
+ IV size = 0;
+ SV *warn_flag;
+
+ IV count = 0;
/* Size starts at zero */
RETVAL = 0;
+ /* Check warning status */
+ go_yell = 0;
+
+ if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
+ go_yell = SvIV(warn_flag);
+ }
+
+
/* If they passed us a reference then dereference it. This is the
only way we can check the sizes of arrays and hashes */
if (SvOK(thing) && SvROK(thing)) {
av_push(pending_array, thing);
/* Now just yank things off the end of the array until it's done */
- while (&PL_sv_undef != (thing = av_pop(pending_array))) {
+ while (av_len(pending_array) >= 0) {
+ thing = av_pop(pending_array);
/* Process it if we've not seen it */
if (check_new(tracking_hash, thing)) {
- /* First, is it pointing to or contraining something else? */
- if (SvOK(thing)) {
+ /* Is it valid? */
+ if (thing) {
/* Yes, it is. So let's check the type */
-
switch (SvTYPE(thing)) {
case SVt_RV:
av_push(pending_array, SvRV(thing));
break;
case SVt_PVHV:
+ /* Is there anything in here? */
+ if (hv_iterinit((HV *)thing)) {
+ HE *temp_he;
+ while (temp_he = hv_iternext((HV *)thing)) {
+ av_push(pending_array, hv_iterval((HV *)thing, temp_he));
+ }
+ }
break;
+ case SVt_PVGV:
+ /* Run through all the pieces and push the ones with bits */
+ if (GvSV(thing)) {
+ av_push(pending_array, (SV *)GvSV(thing));
+ }
+ if (GvFORM(thing)) {
+ av_push(pending_array, (SV *)GvFORM(thing));
+ }
+ if (GvAV(thing)) {
+ av_push(pending_array, (SV *)GvAV(thing));
+ }
+ if (GvHV(thing)) {
+ av_push(pending_array, (SV *)GvHV(thing));
+ }
+ if (GvCV(thing)) {
+ av_push(pending_array, (SV *)GvCV(thing));
+ }
+ break;
default:
- puts("Dunno");
+ break;
}
}
- RETVAL += thing_size(thing, tracking_hash);
+
+ size = thing_size(thing, tracking_hash);
+ RETVAL += size;
}
}