Skip to content

wendyn-projects/tagged_union.h

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tagged_union.h

A single header C library for safe construction and use of tagged-unions.

Tagged-Union Type Declaration

To define a tagged-union just #define a macro that takes 2 arguments: 2ndnd arg. can be ignored, but the 1st one is used to define members:

#define Shape(entry, ...) \
    entry(LINE, Line) \
    entry(SQUARE, struct Square) \
    entry(NUMBER, float) \
    entry(TRIANGLE, struct { float mA, mB, mC; })

Note that the arguments can have any name.

Then you just pass it to tagged_union macro:

tagged_union(Shape)

which will create all the necessary type declarations.

Tagged-Union Initialization

For type-safe tagged-union initialization the header provides tu_new macro. To create an array it can be used like this:

Shape lShapes[] = {
    tu_new(LINE,      { 1, 2 }    ),
    tu_new(TRIANGLE,  { 3, 5, 6 } ),
    tu_new(NUMBER,      7         ),
    tu_new(SQUARE,    { 8 }       )
};

First we need to specify the tagged-union type, then the tag enum label will tell the both set the right tag and make sure the correct union member is used, lastly we initialize the member.

Working with an Instances of a Tagged-Union

Header provides tu_resolve macro which helps to process individual cases.

for (i = 0; i < sizeof(lShapes) / sizeof(*lShapes); i++)
{
    tu_resolve (Shape, lShapes + i)
        tu_matches (LINE, line)
            line->mDirection = 0;
            printf("len: %f dir: %f\n", line->mLength, line->mDirection);
        tu_matches (TRIANGLE, triangle)
            printf("sides: %f %f %f\n", triangle->mA, triangle->mB, triangle->mC);
        tu_matches (NUMBER, num)
            printf("%f\n", *num);
    tu_resolved
}

This macro is a wrapper around switch statement and stores a pointer to the tagged-union for later use (compiler should be able to optimize this out), that is why the macro requires the type of the tagged-union and a pointer to it. Each tu_matches handles the specific union member, for that you need to specify tag enum label (from which the right member and its type is derrived), name of a variable to which a pointer to the member will be stored from previously stored tagged-union (compiler should be able to optimize this out) and what should be done with the variable holding the correctly cast union member (this code will have its own { /*scope*/ break; }, so there is no "fallthrough" for individual "cases").

Then the whole thing needs to be closed with tagged_end macro.

Example File

You can check the example.c, to see what is going on try following command:

gcc -D_STDIO_H -D_STDDEF_H example.c -E | cat -s | sed '/^#/d' > example.i

This will do just the preprocessing step of gcc and also remove all the extra junk.


Note: This library is just a fun experiment and exists only to share knowledge about fun features of C.

About

Single header C library for type safe tagged unions

Topics

Resources

License

Stars

Watchers

Forks

Languages