Using Strings as IDs

June 26, 2009

Sometimes, it’s nice to be able to identify things by name, rather than using a number or an enum. The problem is, that if you’re not careful, using strings can take a lot of memory, and LOADS of CPU-power, with all the stricmp’s. When I was hired for the Tycoon City project, and assigned the task of speeding up the game (which was *really* slow at that point), it turned out they were using several hundred megabytes for storing strings (of which most were used as ID:s, and was mostly duplicates of duplicates), and that string comparisons and string copying was right at the top of the profiling results. I won’t go into how we went about solving that particular problem – it was late in the project, and things turned out the way they turned out – but it got significantly faster and smaller, that’s for sure.

Ever since then, I’m always a bit wary about using strings – it can easily get out of hand, and it feels wrong to waste both memory and CPU-power on something if you don’t have to. So, I thought I’d share my own system for solving this problem, extracted from my (recently cleaned up) Pixie Game Engine. It’s a solid, fast solution, ready to just drop into any project, and consists of only two classes. At its core is a class I call StringId, which is easily created by:

StringId myStringIdVariable("myOwnIdNameHere");

Which internally results in the string "myOwnIdNameHere" being located in a global string table (non-case-sensitive), or inserted if it’s not already added. The lookup is done through a pretty fast hash-table. In the StringId object is stored a pointer to the shared string, so you can do:

if (myStringIdVariable==anotherStringIdVariable)

and know that it will result, internally, in just a comparison of two pointers. Nice and fast. And takes less memory too, as a string is only stored in one place – the global string table. There’s also a couple of macros defined (they’re nifty at times), strSwitch and strCase, which can be used to compare StringId’s in a way similar to switch-case statements:

strSwitch (myFruitTypeStringId)
    {
    strCase(Apples)
        {
        // code to do stuff here
        }
 
    strCase(Oranges)
        {
        // code to do other stuff here
        }
    }

Which is the same as doing this, but looks a bit nicer (though that is, of course, a matter of taste :D )

static StringId applesId("Apples");
if (myFruitTypeStringId==applesId)
    {
    // code to do stuff here
    }
 
static StringId orangesId("Oranges");
if (myFruitTypeStringId==orangesId)
    {
    // code to do other stuff here
    }

The code is well-written and well-commented, and can be downloaded here. It is C++, and as usual it’s public domain – use it anyway you like :D

Leave a Reply

You must be logged in to post a comment.