dgaudet     98/03/29 01:35:44

  Modified:    src/ap   ap_snprintf.c
               src/include ap.h
               src/main alloc.c buff.c
  Log:
  Revamp the apapi_vformatter interface to reduce copies.  In this interface
  the callers hand apapi_vformatter pointers into their own private buffers,
  and are called back for flushing when appropriate.  This is more efficient
  and seems somewhat more clean.
  
  Revision  Changes    Path
  1.16      +23 -44    apache-1.3/src/ap/ap_snprintf.c
  
  Index: ap_snprintf.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/ap/ap_snprintf.c,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- ap_snprintf.c     1998/03/28 21:58:38     1.15
  +++ ap_snprintf.c     1998/03/29 09:35:40     1.16
  @@ -266,10 +266,11 @@
   #define INS_CHAR(c, sp, bep, cc)                             \
            {                                                   \
                if (sp == bep) {                                \
  -                 if (write_func(write_data, staging_buf,     \
  -                     sizeof(staging_buf)) != 0)              \
  +                 vbuff->curpos = sp;                         \
  +                 if (flush_func(vbuff))                      \
                        return -1;                              \
  -                 sp = staging_buf;                           \
  +                 sp = vbuff->curpos;                         \
  +                 bep = vbuff->endpos;                        \
                }                                               \
                *sp++ = (c);                                    \
                cc++;                                           \
  @@ -503,9 +504,8 @@
   /*
    * Do format conversion placing the output in buffer
    */
  -API_EXPORT(int) apapi_vformatter(
  -    int (*write_func)(void *, const char *, size_t),
  -    void *write_data, const char *fmt, va_list ap)
  +API_EXPORT(int) apapi_vformatter(int (*flush_func)(apapi_vformatter_buff *),
  +    apapi_vformatter_buff *vbuff, const char *fmt, va_list ap)
   {
       register char *sp;
       register char *bep;
  @@ -531,8 +531,6 @@
       char num_buf[NUM_BUF_SIZE];
       char char_buf[2];                /* for printing %% and %<unknown> */
   
  -    char staging_buf[MAX_STRING_LEN];
  -
       /*
        * Flag variables
        */
  @@ -544,8 +542,8 @@
       boolean_e adjust_width;
       bool_int is_negative;
   
  -    sp = staging_buf;
  -    bep = sp + sizeof(staging_buf);
  +    sp = vbuff->curpos;
  +    bep = vbuff->endpos;
   
       while (*fmt) {
        if (*fmt != '%') {
  @@ -875,33 +873,14 @@
        }
        fmt++;
       }
  -    if (sp > staging_buf) {
  -     if (write_func(write_data, staging_buf, sp - staging_buf) != 0) {
  -         return -1;
  -     }
  -    }
  +    vbuff->curpos = sp;
       return cc;
   }
   
   
  -struct snprintf_write_data {
  -    char *strp;
  -    char *end_buf;
  -};
  -
  -static int snprintf_write(void *vdata, const char *inp, size_t len)
  +static int snprintf_flush(apapi_vformatter_buff *vbuff)
   {
  -    struct snprintf_write_data *wd;
  -    size_t amt;
  -
  -    wd = vdata;
  -    amt = wd->end_buf - wd->strp;
  -    if (len > amt) {
  -     len = amt;
  -    }
  -    memcpy(wd->strp, inp, len);
  -    wd->strp += len;
  -    return 0;
  +    return -1;
   }
   
   
  @@ -909,19 +888,19 @@
   {
       int cc;
       va_list ap;
  -    struct snprintf_write_data wd;
  +    apapi_vformatter_buff vbuff;
   
       if (len == 0)
        return 0;
   
       /* save one byte for nul terminator */
  -    wd.strp = buf;
  -    wd.end_buf = buf + len - 1;
  +    vbuff.curpos = buf;
  +    vbuff.endpos = buf + len - 1;
       va_start(ap, format);
  -    cc = apapi_vformatter(snprintf_write, &wd, format, ap);
  -    *wd.strp = '\0';
  +    cc = apapi_vformatter(snprintf_flush, &vbuff, format, ap);
       va_end(ap);
  -    return (cc);
  +    *vbuff.curpos = '\0';
  +    return (cc == -1) ? len : cc;
   }
   
   
  @@ -929,15 +908,15 @@
                             va_list ap)
   {
       int cc;
  -    struct snprintf_write_data wd;
  +    apapi_vformatter_buff vbuff;
   
       if (len == 0)
        return 0;
   
       /* save one byte for nul terminator */
  -    wd.strp = buf;
  -    wd.end_buf = buf + len - 1;
  -    cc = apapi_vformatter(snprintf_write, &wd, format, ap);
  -    *wd.strp = '\0';
  -    return (cc);
  +    vbuff.curpos = buf;
  +    vbuff.endpos = buf + len - 1;
  +    cc = apapi_vformatter(snprintf_flush, &vbuff, format, ap);
  +    *vbuff.curpos = '\0';
  +    return (cc == -1) ? len : cc;
   }
  
  
  
  1.9       +41 -11    apache-1.3/src/include/ap.h
  
  Index: ap.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/include/ap.h,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- ap.h      1998/03/28 11:58:17     1.8
  +++ ap.h      1998/03/29 09:35:41     1.9
  @@ -80,21 +80,51 @@
   /* apapi_vformatter() is a generic printf-style formatting routine
    * with some extensions.
    *
  - * The write_func() is called when there is data available to be
  - * output.  write_func() should return 0 when it wishes apapi_vformatter
  - * to continue, and non-zero otherwise.  apapi_vformatter will stop
  - * immediately and return -1 when a non-zero return from
  - * write_func().
  + * The apapi_vformatter_buff has two elements curpos and endpos.
  + * curpos is where apapi_vformatter will write the next byte of output.
  + * It proceeds writing output to curpos, and updating curpos, until
  + * either the end of output is reached, or curpos == endpos (i.e. the
  + * buffer is full).
    *
  - * If write_func() always returns 0 then apapi_vformatter will return
  - * the number of characters written.
  + * If the end of output is reached, apapi_vformatter returns the
  + * number of bytes written.
  + *
  + * When the buffer is full, the flush_func is called.  The flush_func
  + * can return -1 to indicate that no further output should be attempted,
  + * and apapi_vformatter will return immediately with -1.  Otherwise
  + * the flush_func should flush the buffer in whatever manner is
  + * appropriate, re-initialize curpos and endpos, and return 0.
  + *
  + * Note that flush_func is only invoked as a result of attempting to
  + * write another byte at curpos when curpos == endpos.  So for
  + * example, it's possible when the output exactly matches the buffer
  + * space available that curpos == endpos will be true when
  + * apapi_vformatter returns.
    */
   
  -API_EXPORT(int) apapi_vformatter(
  -    int (*write_func)(void *write_data, const char *outp, size_t len),
  -    void *write_data, const char *fmt, va_list ap);
  +typedef struct {
  +    char *curpos;
  +    char *endpos;
  +} apapi_vformatter_buff;
   
  -/* These are snprintf implementations based on apapi_vformatter(). */
  +API_EXPORT(int) apapi_vformatter(int (*flush_func)(apapi_vformatter_buff *),
  +    apapi_vformatter_buff *, const char *fmt, va_list ap);
  +
  +/* These are snprintf implementations based on apapi_vformatter().
  + *
  + * Note that various standards and implementations disagree on the return
  + * value of snprintf, and side-effects due to %n in the formatting string.
  + * ap_snprintf behaves as follows:
  + *
  + * Process the format string until the entire string is exhausted, or
  + * the buffer fills.  If the buffer fills then stop processing immediately
  + * (so no further %n arguments are processed), and return the buffer
  + * length.  In all cases the buffer is NUL terminated.
  + *
  + * In no event does ap_snprintf return a negative number.  It's not possible
  + * to distinguish between an output which was truncated, and an output which
  + * exactly filled the buffer.
  + */
   API_EXPORT(int) ap_snprintf(char *buf, size_t len, const char *format,...)
                            __attribute__((format(printf,3,4)));
   API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format,
  
  
  
  1.82      +31 -40    apache-1.3/src/main/alloc.c
  
  Index: alloc.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/main/alloc.c,v
  retrieving revision 1.81
  retrieving revision 1.82
  diff -u -r1.81 -r1.82
  --- alloc.c   1998/03/28 21:35:41     1.81
  +++ alloc.c   1998/03/29 09:35:42     1.82
  @@ -779,68 +779,52 @@
    */
   
   struct psprintf_data {
  -    pool *p;
  +    apapi_vformatter_buff vbuff;
   #ifdef ALLOC_USE_MALLOC
       char *base;
  -    size_t len;
   #else
       union block_hdr *blok;
  -    char *strp;
       int got_a_new_block;
   #endif
   };
   
  -static int psprintf_write(void *vdata, const char *inp, size_t len)
  +static int psprintf_flush(apapi_vformatter_buff *vbuff)
   {
  +    struct psprintf_data *ps = (struct psprintf_data *)vbuff;
   #ifdef ALLOC_USE_MALLOC
  -    struct psprintf_data *ps;
       int size;
       char *ptr;
   
  -    ps = vdata;
  -
  -    size = ps->len + len + 1;
  -    ptr = realloc(ps->base, size);
  +    size = ps->vbuff.curpos - ps->base;
  +    ptr = realloc(ps->base, 2*size);
       if (ptr == NULL) {
        fputs("Ouch!  Out of memory!\n", stderr);
        exit(1);
       }
       ps->base = ptr;
  -    memcpy(ptr + ps->len, inp, len);
  -    ps->len += len;
  +    ps->vbuff.curpos = ptr + size;
  +    ps->vbuff.endpos = ptr + 2*size - 1;
       return 0;
   #else
  -    struct psprintf_data *ps;
       union block_hdr *blok;
       union block_hdr *nblok;
       size_t cur_len;
       char *strp;
   
  -    ps = vdata;
  -
  -    /* does it fit in the current block? */
       blok = ps->blok;
  -    strp = ps->strp;
  -    if (strp + len + 1 < blok->h.endp) {
  -     memcpy(strp, inp, len);
  -     ps->strp = strp + len;
  -     return 0;
  -    }
  -
  +    strp = ps->vbuff.curpos;
       cur_len = strp - blok->h.first_avail;
   
       /* must try another blok */
       block_alarms();
       (void) acquire_mutex(alloc_mutex);
  -    nblok = new_block((cur_len + len)*2);
  +    nblok = new_block(2 * cur_len);
       (void) release_mutex(alloc_mutex);
       unblock_alarms();
  -    strp = nblok->h.first_avail;
  -    memcpy(strp, blok->h.first_avail, cur_len);
  -    strp += cur_len;
  -    memcpy(strp, inp, len);
  -    strp += len;
  -    ps->strp = strp;
  +    memcpy(nblok->h.first_avail, strp, cur_len);
  +    strp = nblok->h.first_avail + cur_len;
  +    ps->vbuff.curpos = strp;
  +    ps->vbuff.endpos = nblok->h.endp - 1;
   
       /* did we allocate the current blok? if so free it up */
       if (ps->got_a_new_block) {
  @@ -865,16 +849,23 @@
       void *ptr;
   
       block_alarms();
  -    ps.p = p;
  -    ps.base = NULL;
  -    ps.len = CLICK_SZ;       /* need room at beginning for allocation_list */
  -    apapi_vformatter(psprintf_write, &ps, fmt, ap);
  +    ps.base = malloc(512);
  +    if (ps.base == NULL) {
  +     fputs("Ouch!  Out of memory!\n", stderr);
  +     exit(1);
  +    }
  +    /* need room at beginning for allocation_list */
  +    ps.vbuff.curpos = ps.base + CLICK_SZ;
  +    ps.vbuff.endpos = ps.base + 511;
  +    apapi_vformatter(psprintf_flush, &ps.vbuff, fmt, ap);
  +    *ps.vbuff.curpos++ = '\0';
       ptr = ps.base;
  +    /* shrink */
  +    ptr = realloc(ptr, ps.vbuff.curpos - ptr);
       if (ptr == NULL) {
  -     unblock_alarms();
  -     return pstrdup(p, "");
  +     fputs("Ouch!  Out of memory!\n", stderr);
  +     exit(1);
       }
  -    *((char *)ptr + ps.len) = '\0';  /* room was saved for this */
       *(void **)ptr = p->allocation_list;
       p->allocation_list = ptr;
       unblock_alarms();
  @@ -884,14 +875,14 @@
       char *strp;
       int size;
   
  -    ps.p = p;
       ps.blok = p->last;
  -    ps.strp = ps.blok->h.first_avail;
  +    ps.vbuff.curpos = ps.blok->h.first_avail;
  +    ps.vbuff.endpos = ps.blok->h.endp - 1;
       ps.got_a_new_block = 0;
   
  -    apapi_vformatter(psprintf_write, &ps, fmt, ap);
  +    apapi_vformatter(psprintf_flush, &ps.vbuff, fmt, ap);
   
  -    strp = ps.strp;
  +    strp = ps.vbuff.curpos;
       *strp++ = '\0';
   
       size = strp - ps.blok->h.first_avail;
  
  
  
  1.68      +35 -5     apache-1.3/src/main/buff.c
  
  Index: buff.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/main/buff.c,v
  retrieving revision 1.67
  retrieving revision 1.68
  diff -u -r1.67 -r1.68
  --- buff.c    1998/03/28 11:58:22     1.67
  +++ buff.c    1998/03/29 09:35:43     1.68
  @@ -1445,11 +1445,24 @@
       fb->error_data = data;
   }
   
  -static int bprintf_write(void *vdata, const char *inp, size_t len)
  +struct bprintf_data {
  +    apapi_vformatter_buff vbuff;
  +    BUFF *fb;
  +};
  +
  +static int bprintf_flush(apapi_vformatter_buff *vbuff)
   {
  -    if (bwrite(vdata, inp, len) != len) {
  -     return -1;
  +    struct bprintf_data *b = (struct bprintf_data *)vbuff;
  +    BUFF *fb = b->fb;
  +
  +    fb->outcnt += b->vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
  +    if (fb->outcnt == fb->bufsiz) {
  +     if (bflush(fb)) {
  +         return -1;
  +     }
       }
  +    vbuff->curpos = &fb->outbase[fb->outcnt];
  +    vbuff->endpos = &fb->outbase[fb->bufsiz];
       return 0;
   }
   
  @@ -1457,14 +1470,31 @@
   {
       va_list ap;
       int res;
  +    struct bprintf_data b;
   
  +    b.vbuff.curpos = &fb->outbase[fb->outcnt];
  +    b.vbuff.endpos = &fb->outbase[fb->bufsiz];
  +    b.fb = fb;
       va_start(ap, fmt);
  -    res = apapi_vformatter(bprintf_write, fb, fmt, ap);
  +    res = apapi_vformatter(bprintf_flush, &b.vbuff, fmt, ap);
       va_end(ap);
  +    if (res != -1) {
  +     fb->outcnt += b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
  +    }
       return res;
   }
   
   API_EXPORT(int) vbprintf(BUFF *fb, const char *fmt, va_list ap)
   {
  -    return apapi_vformatter(bprintf_write, fb, fmt, ap);
  +    struct bprintf_data b;
  +    int res;
  +
  +    b.vbuff.curpos = &fb->outbase[fb->outcnt];
  +    b.vbuff.endpos = &fb->outbase[fb->bufsiz];
  +    b.fb = fb;
  +    res = apapi_vformatter(bprintf_flush, &b.vbuff, fmt, ap);
  +    if (res != -1) {
  +     fb->outcnt += b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
  +    }
  +    return res;
   }
  
  
  

Reply via email to