uthash is the greatest thing ever
I've been working on a reverse polish notation calculator off-and-on for a few months now. This isn't your run-of-the-mill reverse polish notation calculator, though: it supports, among other things, variables. Because most reverse polish notation calculators use stacks to do the actual math, I first implemented variables by making a variable stack.
This is not at all efficient, however. If you try to find a variable that happens to be at the end of the stack, you must step though every item in the stack. When I posted the code I had to 7chan's /pr/, someone immediately complained about my implementation of variables. I agreed that a hash table would be much better.
So, to learn a bit more about hash tables, I looked them up on Wikipedia, which had a link toward the bottom to a project called uthash. uthash lets you make any C structure hashable. Perhaps the best part is that it's small--just a 37.7 KiB C header file. What? Yes, because it is implemented entirely in C macros, there is no library to which to link; all you need to do is include the header.
I downloaded uthash and set out to rewrite the variables module. I had to change the structures and only one function declaration in the header. (The function to create a new variable to an argument to the next variable in the stack; obviously, this wouldn't be needed anymore!)
Using the very helpful documentation, I was able to rewrite the module to use a hash table in under an hour. Best of all--and to my absolute surprise--the first successful compilation worked!
Here's an example of using uthash. This function takes a pointer to a RPNVariables structure, which simply holds a pointer to the hash table in the table member. It then iterates through the hash table and prints the variable names and their values. (My program allows for the types of values to be either double or long double, so there are preprocessor conditions to allow this.)
void RPN_printVariables(RPNVariables *variables)
{
RPNVariable *var;
printf("[ ");
for(var = variables->table; var != NULL; var = var->hh.next)
{
#ifdef RPN_LONG_DOUBLE
printf("%s = %Lg, ", var->name, var->value);
#elif RPN_DOUBLE
printf("%s = %g, ", var->name, var->value);
#endif
}
printf("]\n");
}