Re: Another useful string handling function

From: Erwin S. Andreasen (erwin@PIP.DKNET.DK)
Date: 04/24/98


On Thu, 23 Apr 1998, James Turner wrote:

> #define ITOA_NBUF 100
>
> char *
> itoa(int i)
> {
>   static char tbuf[ITOA_NBUF][MIL];
>   static int n = -1;
>
>   n = (n + 1) % ITOA_NBUF;
>
>   snprintf(tbuf[n], MIL, "%d", i);
>   tbuf[n][MIL-1] = 0;
>
>   return tbuf[n];
> }

Rather than wasting memory on mostly unused static buffers and
implementing such a multiple-buffer solution in each function returning a
pointer to static storage, consider implementing a general solution. The
idea was first introduced by Oliver Jowett in his IMC code: a pool of
static storage that functions with need for static storage request from.
The code looks like this:

const char* itoa (int i)
{
        char *buf = imc_getsbuf(MIL);

        sprintf(buf, "%d", i);
        imc_shrinksbuf(buf);

        return buf;
}

imc_getsbuf will return MIL bytes of space from a ring buffer: the
allocation simply remembers current position in that buffer then advances
that pointer the required number of bytes so that the next allocation will
not get the same memory.

After you print something to the buffer, you can call imc_shrinkbuf which
puts that first-free-byte pointer in the ring buffer exactly at the end of
the string you actually filled out the buffer with. Thus you can request a
1k buffer, but if you use only 4 bytes of it, the rest are reclaimed.

The buffers are assumed to have very temporary storage, so no effort is
made to preserve old buffers: when the ring buffer is filled up, we just
start over.

This system reduces memory usage depending on number of functions with
static buffers you have: If you 40 places reserve 4k for a static buffer,
you'll save 24k if you just use a 16k ring buffer.

In addition, you can call a function which returns static memory several
times without copying the results away, since the buffer is large enough
to hold several of their results.

It works even better in C++, the code looks roughly like:

const char* itoa (int i)
{
        StaticBuffer buf; // Defaults to some large value

        sprintf (buf, "%d", i);

        return buf;
}

The destructor for StaticBuffer takes care of automaticaly shrinking the
buffer, and a conversion operator allows use of sprintf on the buffer.

There are risks connected with doing this: in theory the buffer may
overflow and data you thought was OK overwritten. As long as you use the
data returned fairly close to where you will be OK. I use this
StaticBuffer 85 places in AR's 170k lines of code and have never had any
problems.


Oh, another note, regarding some argument-splitting code someone - James
Turner I think - posted. It's one thing to use global variables for things
like a list of players or rooms in the game - but using a set of global
variables for the return value of a function is a IMHO bad idea.
Especially a function used for splitting arguments up - that is a thing
very common to MUD code.

One day someone will make a function that has split up the args and is
going through them somehow recurse or it will call the split function from
another function that also is accessing the split arg and you will have
disaster.


PS: Regarding discussion for ASCII vs binary pfiles: I have never heard
any developers of any MERC 2 derived MUDs (the version which introduced
ASCII pfiles) nor its many derivatives consider binary pfiles. I have
never heard anyone complaint how long players took to save or load. Maybe
in 1992 people complained how MERC took up 20% of their 386'er running
Coherent but by now, whatever extra time saving ASCII files takes is worth
less than the programmer time saved because of the extendibility they
present.


PPS: If I used binary pfiles on AR, I'd estimate the size of the player
file to be about 82 megabyte: 6200 pfiles a 14000 bytes - and that'd be
only if I put artificial limits on may things stored in lists like
aliases, spell customizations, environment variables etc.



 =============================================================================
Erwin Andreasen   Herlev, Denmark <erwin@pip.dknet.dk>  UNIX System Programmer
<URL:http://www.abandoned.org/drylock/>     <*>         (not speaking for) DDE
 =============================================================================


     +------------------------------------------------------------+
     | Ensure that you have read the CircleMUD Mailing List FAQ:  |
     | http://democracy.queensu.ca/~fletcher/Circle/list-faq.html |
     +------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/15/00 PST