Skip to content

Instantly share code, notes, and snippets.

@kulp
Created April 7, 2011 18:32
Show Gist options
  • Save kulp/1876ecae7fd8886840bc to your computer and use it in GitHub Desktop.
Save kulp/1876ecae7fd8886840bc to your computer and use it in GitHub Desktop.
provides macros for compactly representing tree-like structures at compile-time
/**
* @file
* Provides macros for compactly representing tree-like structures at compile-
* time.
*
* Must be compiled as C99 code to work correctly. With GCC, use -std=c99 or
* a superset thereof.
*
* Currently, traversal must be done manually. Soon, functions will exist to
* traverse the tree without understanding its internal structure.
*
* A tree node looks like this: @verbatim
struct _elt_SOME_USER_SPECIFIED_IDENTIFIER {
enum statictree_type {
STATICTREE_NULL,
STATICTREE_BRANCH,
STATICTREE_LEAF
} type;
struct {
struct {
int len;
struct _elt_SOME_USER_SPECIFIED_IDENTIFIER *elts;
} branch;
USER_SPECIFIED_TYPE leaf;
} val;
}
* @endverbatim
*
* Example usage: @verbatim
#define ST_CURR_ID some_opaque_identifier_linked_to_contained_type
ST_MAKE_TYPE(element, char*);
element forest[] = {
_LEAF("hi"),
_BRANCH(
_BRANCH(
_LEAF(","),
_LEAF("world"),
),
_LEAF("!"),
),
};
element tree = _BRANCH(
_LEAF("where"),
_LEAF("is"),
_LEAF("Waldo"),
_LEAF("?"),
);
element leaf = _LEAF("alone");
#undef ST_CURR_ID
#define ST_CURR_ID a_different_opaque_identifier
ST_MAKE_TYPE(my_type_name, struct pair { element a, b; });
my_type_name top = _BRANCH(
_LEAF({ leaf, tree }),
_LEAF({ tree, forest[1] }),
);
* @endverbatim
*/
#ifndef STATICTREE_H_
#define STATICTREE_H_
/// @todo differentiate internal nodes with and without values ?
enum statictree_type { STATICTREE_NULL, STATICTREE_BRANCH, STATICTREE_LEAF };
// define this to save space on root and internal nodes
/// @todo make appropriate changes to _BRANCH() to support initialization
#if ST_BRANCH_LACKS_VALUE
# define _ST_BRANCH_CONTAINER union
#else
# define _ST_BRANCH_CONTAINER struct
#endif
/**
* Some of the following macros are not really variadic, but uses their apparent
* variadicity to permit the use of arguments containing commas (for example,
* structures or struct initializers).
*/
//------------------------------------------------------------------------------
// Public API
//------------------------------------------------------------------------------
#define _LEAF(...) \
ST_LEAF(ST_CURR_ID, __VA_ARGS__)
#define _HERE(...) \
_LEAF(__VA_ARGS__)
#define _NOTHING \
{ .type = STATICTREE_NULL }
#define _BRANCH(...) \
ST_BRANCH(ST_CURR_ID, __VA_ARGS__)
#define _BRANCH_V(...) \
ST_BRANCH_V(ST_CURR_ID, __VA_ARGS__)
#define ST_MAKE_TYPE(N,...) \
typedef ST_TREE_TYPE(ST_CURR_ID, __VA_ARGS__) N
#ifndef countof
# define countof(X) (sizeof (X) / sizeof (X)[0])
#endif
//------------------------------------------------------------------------------
// Semi-public API
//------------------------------------------------------------------------------
#define ST_LEAF(ID, ...) \
{ .type = STATICTREE_LEAF, .val = { .leaf = __VA_ARGS__ } }
#define ST_BRANCH(ID, ...) \
{ .type = STATICTREE_BRANCH, \
.val = { .branch = { \
.len = countof(((struct _ST_ELT_NAME(ID)[]) { __VA_ARGS__ })), \
.elts = (struct _ST_ELT_NAME(ID)[]) { __VA_ARGS__ } } } }
#define ST_BRANCH_V(ID, ...) \
{ .type = STATICTREE_BRANCH, \
.val = { \
.leaf = ((struct _ST_ELT_NAME(ID)[]) { __VA_ARGS__ })[0].val.leaf, \
.branch = { \
.len = countof(((struct _ST_ELT_NAME(ID)[]) { __VA_ARGS__ })) - 1, \
.elts = &(struct _ST_ELT_NAME(ID)[]) { __VA_ARGS__ }[1] } } }
#define ST_TREE_TYPE_REF(ID) \
struct _elt_##ID
#define ST_TREE_TYPE(ID,...) \
ST_TREE_TYPE_REF(ID) { \
enum statictree_type type; \
_ST_BRANCH_CONTAINER { \
struct { \
int len; \
struct _ST_ELT_NAME(ID) *elts; \
/* int idx; */ \
} branch; \
__VA_ARGS__ leaf; \
} val; \
/* int visited; */ \
}
//------------------------------------------------------------------------------
// Private "API"
//------------------------------------------------------------------------------
#define _ST_ELT_NAME(id) \
_elt_##id
#endif /* STATICTREE_H_ */
/* vim:set et ts=4 sw=4 syntax=c.doxygen: */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment