summaryrefslogtreecommitdiff
path: root/pp_pack.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2005-01-21 22:15:43 +0000
committerNicholas Clark <nick@ccl4.org>2005-01-21 22:15:43 +0000
commit80a13697042a4d823de61ba24b77aa9d893765d6 (patch)
tree4bba6d03fe49b465c41642e0be1d1ce8ec25abf1 /pp_pack.c
parent78d46eaae9d8413e104f494881b97489e46e1fd4 (diff)
downloadperl-80a13697042a4d823de61ba24b77aa9d893765d6.tar.gz
Shrink a switch() statment by driving the size calculations from the
size table. This requires #ifdef()s in the size table initialiser. Astoundingly this shaves over 6K of the object size with -Os on OS X. I was expecting about 1K (due to shrinking a branch table). Mind you, I'm not going to argue with what I got. :-) p4raw-id: //depot/perl@23854
Diffstat (limited to 'pp_pack.c')
-rw-r--r--pp_pack.c221
1 files changed, 105 insertions, 116 deletions
diff --git a/pp_pack.c b/pp_pack.c
index 8b50c70a8a..815c326ffa 100644
--- a/pp_pack.c
+++ b/pp_pack.c
@@ -259,7 +259,11 @@ struct packsize_t {
/* ASCII */
unsigned char size_normal[53] = {
/* C */ sizeof(unsigned char),
+#if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE)
/* D */ LONG_DOUBLESIZE,
+#else
+ 0,
+#endif
0,
/* F */ NVSIZE,
0, 0,
@@ -270,7 +274,11 @@ unsigned char size_normal[53] = {
0,
/* N */ SIZE32,
0, 0,
+#if defined(HAS_QUAD)
/* Q */ sizeof(Uquad_t),
+#else
+ 0,
+#endif
0,
/* S */ SIZE16,
0,
@@ -290,7 +298,11 @@ unsigned char size_normal[53] = {
/* n */ SIZE16,
0,
/* p */ sizeof(char *) | PACK_SIZE_CANNOT_ONLY_ONE | PACK_SIZE_CANNOT_CSUM,
+#if defined(HAS_QUAD)
/* q */ sizeof(Quad_t),
+#else
+ 0,
+#endif
0,
/* s */ SIZE16,
0, 0,
@@ -339,7 +351,11 @@ unsigned char size_normal[99] = {
/* n */ SIZE16,
0,
/* p */ sizeof(char *) | PACK_SIZE_CANNOT_ONLY_ONE | PACK_SIZE_CANNOT_CSUM,
+#if defined(HAS_QUAD)
/* q */ sizeof(Quad_t),
+#else
+ 0,
+#endif
0, 0, 0, 0, 0, 0, 0, 0, 0,
/* s */ SIZE16,
0, 0,
@@ -348,7 +364,11 @@ unsigned char size_normal[99] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
/* C */ sizeof(unsigned char),
+#if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE)
/* D */ LONG_DOUBLESIZE,
+#else
+ 0,
+#endif
0,
/* F */ NVSIZE,
0, 0,
@@ -360,7 +380,11 @@ unsigned char size_normal[99] = {
0,
/* N */ SIZE32,
0, 0,
+#if defined(HAS_QUAD)
/* Q */ sizeof(Uquad_t),
+#else
+ 0,
+#endif
0, 0, 0, 0, 0, 0, 0, 0, 0,
/* S */ SIZE16,
0,
@@ -407,6 +431,10 @@ S_measure_struct(pTHX_ register tempsym_t* symptr)
register int size;
while (next_symbol(symptr)) {
+ int which = (symptr->code & TYPE_IS_SHRIEKING)
+ ? PACK_SIZE_SHRIEKING : PACK_SIZE_NORMAL;
+ int offset
+ = TYPE_NO_MODIFIERS(symptr->code) - packsize[which].first;
switch( symptr->howlen ){
case e_no_len:
@@ -419,125 +447,86 @@ S_measure_struct(pTHX_ register tempsym_t* symptr)
break;
}
- /* endianness doesn't influence the size of a type */
- switch(TYPE_NO_ENDIANNESS(symptr->code)) {
- default:
- Perl_croak(aTHX_ "Invalid type '%c' in %s",
- (int)TYPE_NO_MODIFIERS(symptr->code),
- symptr->flags & FLAG_PACK ? "pack" : "unpack" );
- case '@':
- case '/':
- case 'U': /* XXXX Is it correct? */
- case 'w':
- case 'u':
- Perl_croak(aTHX_ "Within []-length '%c' not allowed in %s",
- (int)symptr->code,
- symptr->flags & FLAG_PACK ? "pack" : "unpack" );
- case '%':
+ if ((offset >= 0) && (offset < packsize[which].size))
+ size = packsize[which].array[offset] & PACK_SIZE_MASK;
+ else
size = 0;
- break;
- case '(':
- {
- tempsym_t savsym = *symptr;
- symptr->patptr = savsym.grpbeg;
- symptr->patend = savsym.grpend;
- /* XXXX Theoretically, we need to measure many times at different
- positions, since the subexpression may contain
- alignment commands, but be not of aligned length.
- Need to detect this and croak(). */
- size = measure_struct(symptr);
- *symptr = savsym;
- break;
- }
- case 'X' | TYPE_IS_SHRIEKING:
- /* XXXX Is this useful? Then need to treat MEASURE_BACKWARDS. */
- if (!len) /* Avoid division by 0 */
- len = 1;
- len = total % len; /* Assumed: the start is aligned. */
- /* FALL THROUGH */
- case 'X':
- size = -1;
- if (total < len)
- Perl_croak(aTHX_ "'X' outside of string in %s",
- symptr->flags & FLAG_PACK ? "pack" : "unpack" );
- break;
- case 'x' | TYPE_IS_SHRIEKING:
- if (!len) /* Avoid division by 0 */
- len = 1;
- star = total % len; /* Assumed: the start is aligned. */
- if (star) /* Other portable ways? */
- len = len - star;
- else
- len = 0;
- /* FALL THROUGH */
- case 'x':
- case 'A':
- case 'Z':
- case 'a':
- case 'c':
- case 'C':
- size = 1;
- break;
- case 'B':
- case 'b':
- len = (len + 7)/8;
- size = 1;
- break;
- case 'H':
- case 'h':
- len = (len + 1)/2;
- size = 1;
- break;
-
- case 'P':
- len = 1;
- /* FALL THROUGH */
- case 'p':
- size = sizeof(char*);
- break;
+ if (!size) {
+ /* endianness doesn't influence the size of a type */
+ switch(TYPE_NO_ENDIANNESS(symptr->code)) {
+ default:
+ Perl_croak(aTHX_ "Invalid type '%c' in %s",
+ (int)TYPE_NO_MODIFIERS(symptr->code),
+ symptr->flags & FLAG_PACK ? "pack" : "unpack" );
+ case '@':
+ case '/':
+ case 'U': /* XXXX Is it correct? */
+ case 'w':
+ case 'u':
+ Perl_croak(aTHX_ "Within []-length '%c' not allowed in %s",
+ (int)symptr->code,
+ symptr->flags & FLAG_PACK ? "pack" : "unpack" );
+ case '%':
+ size = 0;
+ break;
+ case '(':
+ {
+ tempsym_t savsym = *symptr;
+ symptr->patptr = savsym.grpbeg;
+ symptr->patend = savsym.grpend;
+ /* XXXX Theoretically, we need to measure many times at
+ different positions, since the subexpression may contain
+ alignment commands, but be not of aligned length.
+ Need to detect this and croak(). */
+ size = measure_struct(symptr);
+ *symptr = savsym;
+ break;
+ }
+ case 'X' | TYPE_IS_SHRIEKING:
+ /* XXXX Is this useful? Then need to treat MEASURE_BACKWARDS.
+ */
+ if (!len) /* Avoid division by 0 */
+ len = 1;
+ len = total % len; /* Assumed: the start is aligned. */
+ /* FALL THROUGH */
+ case 'X':
+ size = -1;
+ if (total < len)
+ Perl_croak(aTHX_ "'X' outside of string in %s",
+ symptr->flags & FLAG_PACK ? "pack" : "unpack" );
+ break;
+ case 'x' | TYPE_IS_SHRIEKING:
+ if (!len) /* Avoid division by 0 */
+ len = 1;
+ star = total % len; /* Assumed: the start is aligned. */
+ if (star) /* Other portable ways? */
+ len = len - star;
+ else
+ len = 0;
+ /* FALL THROUGH */
+ case 'x':
+ case 'A':
+ case 'Z':
+ case 'a':
+ case 'c':
+ case 'C':
+ size = 1;
+ break;
+ case 'B':
+ case 'b':
+ len = (len + 7)/8;
+ size = 1;
+ break;
+ case 'H':
+ case 'h':
+ len = (len + 1)/2;
+ size = 1;
+ break;
- case 's' | TYPE_IS_SHRIEKING:
- case 'S' | TYPE_IS_SHRIEKING:
- case 'v' | TYPE_IS_SHRIEKING:
- case 'n' | TYPE_IS_SHRIEKING:
- case 'i' | TYPE_IS_SHRIEKING:
- case 'I' | TYPE_IS_SHRIEKING:
- case 'l' | TYPE_IS_SHRIEKING:
- case 'L' | TYPE_IS_SHRIEKING:
- case 'V' | TYPE_IS_SHRIEKING:
- case 'N' | TYPE_IS_SHRIEKING:
- case 'i':
- case 'I':
- case 'j':
- case 'J':
- case 'l':
- case 's':
- case 'v':
- case 'n':
- case 'S':
- case 'V':
- case 'N':
- case 'L':
-#ifdef HAS_QUAD
- case 'q':
- case 'Q':
-#endif
- case 'f':
- case 'd':
- case 'F':
-#if defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE)
- case 'D':
-#endif
- {
- int which = (symptr->code & TYPE_IS_SHRIEKING)
- ? PACK_SIZE_SHRIEKING : PACK_SIZE_NORMAL;
- int offset
- = TYPE_NO_MODIFIERS(symptr->code) - packsize[which].first;
- assert (offset >= 0);
- assert (offset < packsize[which].size);
- size = packsize[which].array[offset] & PACK_SIZE_MASK;
- assert(size);
+ case 'P':
+ len = 1;
+ size = sizeof(char*);
break;
}
}