Clean String Switches With constexpr

Recently I started data-driving my UI layouts via JSON, this required the overhead of parsing the file and then identifying what needed constructing and what properties to apply. An example file looks like this:

{
    "type":"CPlainWidget",
    "color": "ffffffff",

    "children":[{
        "type": "CPlainWidget",
        "name": "img_opponent",
        "color": "7e7e7eFF",
        "height": "90",
        "match":"x"
    }]
}

What I wanted to avoid whilst doing this was an incredible amount of string comparison to figure out the properties, it’s an awful waste. Something like the following:

if(!stricmp(pProperty, "name")) {}
else if(!stricmp(pProperty, "color")) {}
else if(!stricmp(pProperty, "height")) {}
else if...

So I decided to DJB2 hash (http://www.cse.yorku.ca/~oz/hash.html) the property names and then switch on them at runtime, but how can I properly maintain the code and make it readable (without littering switch cases with seemingly random numbers). Simple! constexpr to the rescue:

uint32_t constexpr DJBHash_constexpr(const char* pInput, unsigned int uPrev = 5381)
{
    return *pInput
    ? DJBHash_constexpr(pInput + 1, uPrev*33 + *pInput)
    : uPrev;
}

Now instead, I can write this:


void ParseProperty(unsigned int uProperty, const char* pValue)
{
    switch(uProperty)
    {
        case DJBHash_constexpr("name"):
        break;
        case DJBHash_constexpr("color"):
        break;
        case DJBHash_constexpr("height"):
        break;
    }
}

Which is not just cleaner and easier to read, it’s also more maintainable and has advantages at runtime. Cool! And for completeness, here is the equivalent of the hashing function:
inline unsigned int DJBHash(const char* pStr)
{
    unsigned int uHash = 5381;
    for(; *pStr; pStr++)
    {
        uHash = 33*uHash + (*pStr);
    }
    return uHash;
}

Clean String Switches With constexpr

2 thoughts on “Clean String Switches With constexpr

    1. Jerry Coffin says:

      If there’s a collision, that’ll create a duplicate case label, which will result in a compiler error message. If it compiles, you have no collisions.

      Like

Leave a comment