import Devel-Size 0.59 from CPAN
[p5sagit/Devel-Size.git] / Size.xs
diff --git a/Size.xs b/Size.xs
old mode 100644 (file)
new mode 100755 (executable)
index 43b45ce..6cc21a5
--- a/Size.xs
+++ b/Size.xs
@@ -8,6 +8,8 @@
 #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.
 
@@ -21,7 +23,7 @@ IV check_new(HV *tracking_hash, void *thing) {
   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;
 
 }
@@ -153,8 +155,7 @@ UV thing_size(SV *orig_thing, HV *tracking_hash) {
          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;
@@ -166,35 +167,96 @@ UV thing_size(SV *orig_thing, HV *tracking_hash) {
   case SVt_PVCV:
     total_size += sizeof(XPVCV);
     total_size += magic_size(thing, tracking_hash);
-    carp("CV isn't complete");
+    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);
     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;
 }
@@ -211,6 +273,15 @@ CODE:
   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 */
@@ -235,10 +306,22 @@ CODE:
   /* 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)) {
@@ -318,7 +401,9 @@ CODE:
        }
       }
 
-      RETVAL += thing_size(thing, tracking_hash);
+      
+      size = thing_size(thing, tracking_hash);
+      RETVAL += size;
     }
   }