]> git.lizzy.rs Git - zlib.git/commitdiff
Change gzgetc() to a macro for speed (~40% speedup in testing).
authorMark Adler <madler@alumni.caltech.edu>
Tue, 27 Sep 2011 05:50:28 +0000 (22:50 -0700)
committerMark Adler <madler@alumni.caltech.edu>
Tue, 27 Sep 2011 05:50:28 +0000 (22:50 -0700)
gzguts.h
gzlib.c
gzread.c
gzwrite.c
zlib.h

index 63b0c3f4a63a56e25e34e5b1601df57a2f6f2abd..ab3313a94148759c35e03c0db682f5e9ff984be9 100644 (file)
--- a/gzguts.h
+++ b/gzguts.h
 
 /* internal gzip file state data structure */
 typedef struct {
+        /* exposed contents for gzgetc() macro */
+    struct gzFile_s x;      /* "x" for exposed */
+                            /* x.have: number of bytes available at x.next */
+                            /* x.next: next output data to deliver or write */
+                            /* x.pos: current position in uncompressed data */
         /* used for both reading and writing */
     int mode;               /* see gzip modes above */
     int fd;                 /* file descriptor */
     char *path;             /* path or fd for error messages */
-    z_off64_t pos;          /* current position in uncompressed data */
     unsigned size;          /* buffer size, zero if not allocated yet */
     unsigned want;          /* requested buffer size, default is GZBUFSIZE */
     unsigned char *in;      /* input buffer */
     unsigned char *out;     /* output buffer (double-sized when reading) */
-    unsigned char *next;    /* next output data to deliver or write */
         /* just for reading */
-    unsigned have;          /* amount of output data unused at next */
     int eof;                /* true if end of input file reached */
     z_off64_t start;        /* where the gzip data started, for rewinding */
     int how;                /* 0: get header, 1: copy, 2: decompress */
diff --git a/gzlib.c b/gzlib.c
index b26b0c2ffc110775c7034c1920df424e982bf39b..61da8fdfc268d219bd222715c8b297d622399085 100644 (file)
--- a/gzlib.c
+++ b/gzlib.c
@@ -71,15 +71,15 @@ char ZLIB_INTERNAL *gz_strwinerror (error)
 local void gz_reset(state)
     gz_statep state;
 {
+    state->x.have = 0;              /* no output data available */
     if (state->mode == GZ_READ) {   /* for reading ... */
-        state->have = 0;            /* no output data available */
         state->eof = 0;             /* not at end of file */
         state->how = LOOK;          /* look for gzip header */
         state->direct = 1;          /* default for empty file */
     }
     state->seek = 0;                /* no seek request pending */
     gz_error(state, Z_OK, NULL);    /* clear error */
-    state->pos = 0;                 /* no uncompressed data yet */
+    state->x.pos = 0;               /* no uncompressed data yet */
     state->strm.avail_in = 0;       /* no input data yet */
 }
 
@@ -303,31 +303,31 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
 
     /* normalize offset to a SEEK_CUR specification */
     if (whence == SEEK_SET)
-        offset -= state->pos;
+        offset -= state->x.pos;
     else if (state->seek)
         offset += state->skip;
     state->seek = 0;
 
     /* if within raw area while reading, just go there */
     if (state->mode == GZ_READ && state->how == COPY &&
-            state->pos + offset >= 0) {
-        ret = LSEEK(state->fd, offset - state->have, SEEK_CUR);
+            state->x.pos + offset >= 0) {
+        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
         if (ret == -1)
             return -1;
-        state->have = 0;
+        state->x.have = 0;
         state->eof = 0;
         state->seek = 0;
         gz_error(state, Z_OK, NULL);
         state->strm.avail_in = 0;
-        state->pos += offset;
-        return state->pos;
+        state->x.pos += offset;
+        return state->x.pos;
     }
 
     /* calculate skip amount, rewinding if needed for back seek when reading */
     if (offset < 0) {
         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
             return -1;
-        offset += state->pos;
+        offset += state->x.pos;
         if (offset < 0)                     /* before start of file! */
             return -1;
         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
@@ -336,11 +336,11 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
 
     /* if reading, skip what's in output buffer (one less gzgetc() check) */
     if (state->mode == GZ_READ) {
-        n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?
-            (unsigned)offset : state->have;
-        state->have -= n;
-        state->next += n;
-        state->pos += n;
+        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
+            (unsigned)offset : state->x.have;
+        state->x.have -= n;
+        state->x.next += n;
+        state->x.pos += n;
         offset -= n;
     }
 
@@ -349,7 +349,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
         state->seek = 1;
         state->skip = offset;
     }
-    return state->pos + offset;
+    return state->x.pos + offset;
 }
 
 /* -- see zlib.h -- */
@@ -378,7 +378,7 @@ z_off64_t ZEXPORT gztell64(file)
         return -1;
 
     /* return position */
-    return state->pos + (state->seek ? state->skip : 0);
+    return state->x.pos + (state->seek ? state->skip : 0);
 }
 
 /* -- see zlib.h -- */
@@ -439,7 +439,7 @@ int ZEXPORT gzeof(file)
 
     /* return end-of-file state */
     return state->mode == GZ_READ ?
-        (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0;
+        (state->eof && state->strm.avail_in == 0 && state->x.have == 0) : 0;
 }
 
 /* -- see zlib.h -- */
@@ -499,6 +499,10 @@ void ZLIB_INTERNAL gz_error(state, err, msg)
         state->msg = NULL;
     }
 
+    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
+    if (err != Z_OK && err != Z_BUF_ERROR)
+        state->x.have = 0;
+
     /* set error code, and if no message, then done */
     state->err = err;
     if (msg == NULL)
index a41e5d940e9e71449e93a8444e8d53c9b0fcfc4d..22eb6271a1534002f96ff68a8bc9b21613a3e6ed 100644 (file)
--- a/gzread.c
+++ b/gzread.c
@@ -68,7 +68,7 @@ local int gz_avail(state)
     return 0;
 }
 
-/* Look for gzip header, set up for inflate or copy.  state->have must be zero.
+/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
    If this is the first time in, allocate required memory.  state->how will be
    left unchanged if there is no more input data available, will be set to COPY
    if there is no gzip header and direct copying will be performed, or it will
@@ -140,17 +140,17 @@ local int gz_look(state)
     if (state->direct == 0) {
         strm->avail_in = 0;
         state->eof = 1;
-        state->have = 0;
+        state->x.have = 0;
         return 0;
     }
 
     /* doing raw i/o, copy any leftover input to output -- this assumes that
        the output buffer is larger than the input buffer, which also assures
        space for gzungetc() */
-    state->next = state->out;
+    state->x.next = state->out;
     if (strm->avail_in) {
-        memcpy(state->next, strm->next_in, strm->avail_in);
-        state->have = strm->avail_in;
+        memcpy(state->x.next, strm->next_in, strm->avail_in);
+        state->x.have = strm->avail_in;
         strm->avail_in = 0;
     }
     state->how = COPY;
@@ -159,10 +159,10 @@ local int gz_look(state)
 }
 
 /* Decompress from input to the provided next_out and avail_out in the state.
-   state->have and state->next are set to point to the just decompressed data,
-   If the gzip stream completes, state->how is reset to LOOK to look for the
-   next gzip stream or raw data, once state->have is depleted.  Returns 0 on
-   success, -1 on failure. */
+   On return, state->x.have and state->x.next point to the just decompressed
+   data.  If the gzip stream completes, state->how is reset to LOOK to look for
+   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
+   on success, -1 on failure. */
 local int gz_decomp(state)
     gz_statep state;
 {
@@ -200,8 +200,8 @@ local int gz_decomp(state)
     } while (strm->avail_out && ret != Z_STREAM_END);
 
     /* update available output */
-    state->have = had - strm->avail_out;
-    state->next = strm->next_out - state->have;
+    state->x.have = had - strm->avail_out;
+    state->x.next = strm->next_out - state->x.have;
 
     /* if the gzip stream completed successfully, look for another */
     if (ret == Z_STREAM_END)
@@ -211,7 +211,7 @@ local int gz_decomp(state)
     return 0;
 }
 
-/* Fetch data and put it in the output buffer.  Assumes that state->have == 0.
+/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
    Data is either copied from the input file or decompressed from the input
    file depending on state->how.  If state->how is LOOK, then a gzip header is
    looked for to determine whether to copy or decompress.  Returns -1 on error,
@@ -231,10 +231,10 @@ local int gz_fetch(state)
                 return 0;
             break;
         case COPY:      /* -> COPY */
-            if (gz_load(state, state->out, state->size << 1, &(state->have))
+            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
                     == -1)
                 return -1;
-            state->next = state->out;
+            state->x.next = state->out;
             return 0;
         case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
             strm->avail_out = state->size << 1;
@@ -242,7 +242,7 @@ local int gz_fetch(state)
             if (gz_decomp(state) == -1)
                 return -1;
         }
-    } while (state->have == 0);
+    } while (state->x.have == 0);
     return 0;
 }
 
@@ -256,12 +256,12 @@ local int gz_skip(state, len)
     /* skip over len bytes or reach end-of-file, whichever comes first */
     while (len)
         /* skip over whatever is in output buffer */
-        if (state->have) {
-            n = GT_OFF(state->have) || (z_off64_t)state->have > len ?
-                (unsigned)len : state->have;
-            state->have -= n;
-            state->next += n;
-            state->pos += n;
+        if (state->x.have) {
+            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
+                (unsigned)len : state->x.have;
+            state->x.have -= n;
+            state->x.next += n;
+            state->x.pos += n;
             len -= n;
         }
 
@@ -321,11 +321,11 @@ int ZEXPORT gzread(file, buf, len)
     got = 0;
     do {
         /* first just try copying data from the output buffer */
-        if (state->have) {
-            n = state->have > len ? len : state->have;
-            memcpy(buf, state->next, n);
-            state->next += n;
-            state->have -= n;
+        if (state->x.have) {
+            n = state->x.have > len ? len : state->x.have;
+            memcpy(buf, state->x.next, n);
+            state->x.next += n;
+            state->x.have -= n;
         }
 
         /* output buffer empty -- return if we're at the end of the input */
@@ -355,15 +355,15 @@ int ZEXPORT gzread(file, buf, len)
             strm->next_out = buf;
             if (gz_decomp(state) == -1)
                 return -1;
-            n = state->have;
-            state->have = 0;
+            n = state->x.have;
+            state->x.have = 0;
         }
 
         /* update progress */
         len -= n;
         buf = (char *)buf + n;
         got += n;
-        state->pos += n;
+        state->x.pos += n;
     } while (len);
 
     /* return number of bytes read into user buffer (will fit in int) */
@@ -371,7 +371,7 @@ int ZEXPORT gzread(file, buf, len)
 }
 
 /* -- see zlib.h -- */
-int ZEXPORT gzgetc(file)
+int ZEXPORT gzgetc_(file)
     gzFile file;
 {
     int ret;
@@ -388,11 +388,14 @@ int ZEXPORT gzgetc(file)
         (state->err != Z_OK && state->err != Z_BUF_ERROR))
         return -1;
 
-    /* try output buffer (no need to check for skip request) */
-    if (state->have) {
-        state->have--;
-        state->pos++;
-        return *(state->next)++;
+    /* try output buffer (no need to check for skip request) -- while
+       this check really isn't required since the gzgetc() macro has
+       already determined that x.have is zero, we leave it in for
+       completeness. */
+    if (state->x.have) {
+        state->x.have--;
+        state->x.pos++;
+        return *(state->x.next)++;
     }
 
     /* nothing there -- try gzread() */
@@ -429,32 +432,32 @@ int ZEXPORT gzungetc(c, file)
         return -1;
 
     /* if output buffer empty, put byte at end (allows more pushing) */
-    if (state->have == 0) {
-        state->have = 1;
-        state->next = state->out + (state->size << 1) - 1;
-        state->next[0] = c;
-        state->pos--;
+    if (state->x.have == 0) {
+        state->x.have = 1;
+        state->x.next = state->out + (state->size << 1) - 1;
+        state->x.next[0] = c;
+        state->x.pos--;
         return c;
     }
 
     /* if no room, give up (must have already done a gzungetc()) */
-    if (state->have == (state->size << 1)) {
+    if (state->x.have == (state->size << 1)) {
         gz_error(state, Z_BUF_ERROR, "out of room to push characters");
         return -1;
     }
 
     /* slide output data if needed and insert byte before existing data */
-    if (state->next == state->out) {
-        unsigned char *src = state->out + state->have;
+    if (state->x.next == state->out) {
+        unsigned char *src = state->out + state->x.have;
         unsigned char *dest = state->out + (state->size << 1);
         while (src > state->out)
             *--dest = *--src;
-        state->next = dest;
+        state->x.next = dest;
     }
-    state->have++;
-    state->next--;
-    state->next[0] = c;
-    state->pos--;
+    state->x.have++;
+    state->x.next--;
+    state->x.next[0] = c;
+    state->x.pos--;
     return c;
 }
 
@@ -493,25 +496,25 @@ char * ZEXPORT gzgets(file, buf, len)
     left = (unsigned)len - 1;
     if (left) do {
         /* assure that something is in the output buffer */
-        if (state->have == 0 && gz_fetch(state) == -1)
+        if (state->x.have == 0 && gz_fetch(state) == -1)
             return NULL;                /* error */
-        if (state->have == 0) {         /* end of file */
+        if (state->x.have == 0) {       /* end of file */
             if (buf == str)             /* got bupkus */
                 return NULL;
             break;                      /* got something -- return it */
         }
 
         /* look for end-of-line in current output buffer */
-        n = state->have > left ? left : state->have;
-        eol = memchr(state->next, '\n', n);
+        n = state->x.have > left ? left : state->x.have;
+        eol = memchr(state->x.next, '\n', n);
         if (eol != NULL)
-            n = (unsigned)(eol - state->next) + 1;
+            n = (unsigned)(eol - state->x.next) + 1;
 
         /* copy through end-of-line, or remainder if not found */
-        memcpy(buf, state->next, n);
-        state->have -= n;
-        state->next += n;
-        state->pos += n;
+        memcpy(buf, state->x.next, n);
+        state->x.have -= n;
+        state->x.next += n;
+        state->x.pos += n;
         left -= n;
         buf += n;
     } while (left && eol == NULL);
@@ -538,7 +541,7 @@ int ZEXPORT gzdirect(file)
 
     /* if the state is not known, but we can find out, then do so (this is
        mainly for right after a gzopen() or gzdopen()) */
-    if (state->how == LOOK && state->have == 0)
+    if (state->how == LOOK && state->x.have == 0)
         (void)gz_look(state);
 
     /* return 1 if reading direct, 0 if decompressing a gzip stream */
index 0ea2994bd03b9f6c376cae7c05cf3055d78adea6..d08f30921cfbad75429b48545e8d3f7b35e84356 100644 (file)
--- a/gzwrite.c
+++ b/gzwrite.c
@@ -48,7 +48,7 @@ local int gz_init(state)
     /* initialize write buffer */
     strm->avail_out = state->size;
     strm->next_out = state->out;
-    state->next = strm->next_out;
+    state->x.next = strm->next_out;
     return 0;
 }
 
@@ -75,8 +75,8 @@ local int gz_comp(state, flush)
            doing Z_FINISH then don't write until we get to Z_STREAM_END */
         if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
             (flush != Z_FINISH || ret == Z_STREAM_END))) {
-            have = (unsigned)(strm->next_out - state->next);
-            if (have && ((got = write(state->fd, state->next, have)) < 0 ||
+            have = (unsigned)(strm->next_out - state->x.next);
+            if (have && ((got = write(state->fd, state->x.next, have)) < 0 ||
                          (unsigned)got != have)) {
                 gz_error(state, Z_ERRNO, zstrerror());
                 return -1;
@@ -85,7 +85,7 @@ local int gz_comp(state, flush)
                 strm->avail_out = state->size;
                 strm->next_out = state->out;
             }
-            state->next = strm->next_out;
+            state->x.next = strm->next_out;
         }
 
         /* compress */
@@ -131,7 +131,7 @@ local int gz_zero(state, len)
         }
         strm->avail_in = n;
         strm->next_in = state->in;
-        state->pos += n;
+        state->x.pos += n;
         if (gz_comp(state, Z_NO_FLUSH) == -1)
             return -1;
         len -= n;
@@ -193,7 +193,7 @@ int ZEXPORT gzwrite(file, buf, len)
                 n = len;
             memcpy(strm->next_in + strm->avail_in, buf, n);
             strm->avail_in += n;
-            state->pos += n;
+            state->x.pos += n;
             buf = (char *)buf + n;
             len -= n;
             if (len && gz_comp(state, Z_NO_FLUSH) == -1)
@@ -208,7 +208,7 @@ int ZEXPORT gzwrite(file, buf, len)
         /* directly compress user buffer to file */
         strm->avail_in = len;
         strm->next_in = (voidp)buf;
-        state->pos += len;
+        state->x.pos += len;
         if (gz_comp(state, Z_NO_FLUSH) == -1)
             return 0;
     }
@@ -249,7 +249,7 @@ int ZEXPORT gzputc(file, c)
         if (strm->avail_in == 0)
             strm->next_in = state->in;
         strm->next_in[strm->avail_in++] = c;
-        state->pos++;
+        state->x.pos++;
         return c;
     }
 
@@ -342,7 +342,7 @@ int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
     /* update buffer and position, defer compression until needed */
     strm->avail_in = (unsigned)len;
     strm->next_in = state->in;
-    state->pos += len;
+    state->x.pos += len;
     return len;
 }
 
@@ -420,7 +420,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
     /* update buffer and position, defer compression until needed */
     strm->avail_in = (unsigned)len;
     strm->next_in = state->in;
-    state->pos += len;
+    state->x.pos += len;
     return len;
 }
 
diff --git a/zlib.h b/zlib.h
index 4c505b9a753e24f16ed88af085d31967c65f052d..d358a62dc4f0e4fd8b2a7f1c1b265a84466a876c 100644 (file)
--- a/zlib.h
+++ b/zlib.h
@@ -1186,7 +1186,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
    wrapper, documented in RFC 1952, wrapped around a deflate stream.
 */
 
-typedef voidp gzFile;       /* opaque gzip file descriptor */
+typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */
 
 /*
 ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
@@ -1322,10 +1322,13 @@ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
    returns the value that was written, or -1 in case of error.
 */
 
-ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
 /*
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
      Reads one byte from the compressed file.  gzgetc returns this byte or -1
-   in case of end of file or error.
+   in case of end of file or error.  This is implemented as a macro for speed.
+   As such, it does not do all of the checking the other functions do.  I.e.
+   it does not check to see if file is NULL, nor whether the structure file
+   points to has been clobbered or not.
 */
 
 ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
@@ -1583,6 +1586,22 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
         inflateBackInit_((strm), (windowBits), (window), \
                       ZLIB_VERSION, (int)sizeof(z_stream))
 
+/* gzgetc() macro and its supporting function and exposed data structure.  Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro.  The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously.  They can
+ * only be used by the gzgetc() macro.  You have been warned.
+ */
+struct gzFile_s {
+    unsigned have;
+    unsigned char *next;
+    z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));
+#define gzgetc(g) \
+    ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc_(g))
+
 /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
  * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
  * both are true, the application gets the *64 functions, and the regular