Skip to content

Instantly share code, notes, and snippets.

@thecppzoo
Created October 29, 2021 18:45
Show Gist options
  • Save thecppzoo/840b32bfa85953ea393c5ee4563a1e4a to your computer and use it in GitHub Desktop.
Save thecppzoo/840b32bfa85953ea393c5ee4563a1e4a to your computer and use it in GitHub Desktop.
Data Orientation Macros
// This example requires the boost preprocessing library headers
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/seq/enum.hpp>
// Macro naming convention:
// The prefix ZOO_PP_ indicates the identifier is preprocessing
// The particle D_ indicates the macro is for Data Orientation techniques
// The particle SEQ_ indicates the macro is for boost preprocessing sequences
// The particle SEQI_ indicates the macro is used for BOOST_PP_SEQ_FOR_EACH_I
// The rest of the identifier indicates what it does
// handle, columnar state naming convention:
// The normal memory layout is declared as specified.
// The handle that corresponds to it uses the _handle suffix
// The columnar state global variable uses the prefix g_
// for example, for a type called Example, its handle would be Example_handle
// and its global variable to hold their states g_Example
// General utility to remove parenthesis ("untuple") or force expansion
#define ZOO_PP_QUOTE(...) __VA_ARGS__
// General utility to allow capturing lists of macro arguments as macros
#define ZOO_PP_INVOKE(macro, ...) macro(__VA_ARGS__)
// Specification format:
// Because C++ data types may have commas in them (templates with more than one
// argument, all specifications of types for macros have extra parenthesis for
// grouping into a single macro argument
// A data member is specified as a tuple of type and name, examples:
// ((int), anIntegerName)
// ((std::map<int, char>), aMapFromIntToChar)
// A function is specified as a tuple of return type, name, parameter list
// the parameter list is a boost sequence, that is, the sequence (a)(b)(c)
// has the three elements a, b and c
// A parameter has the same format as a data member.
// Examples:
// ((void), aFunctionThatReturnsVoidAndTakesTwoInts, (((int), firstArg))(((int), secondArg)))
// ( <- begins a tuple
// (void), <- the first tuple member is a type, parenthesis for grouping
// aFunctionThatReturnsVoidAndTakesTwoInts, <- second member, the name
// ( <- a sequence element
// ( <- a tuple
// (int)<- the type of the parameter, grouping with parenthesis
// , firstArg
// ) <- completes the tuple for the first function argument
// ) <- completes the first element in the sequence of f. args.
// (((int), secondArg)) <- second element in the sequence of f. args.
// ) <- end of the function specification
// ((void), modulus, ): will declare void modulus()
#define ZOO_PP_D_TYPE_FROM_MEMBER(type, name) type
#define ZOO_PP_D_NAME_FROM_MEMBER(type, name) name
// declares an identifier
// note the use of _QUOTE to remove parenthesis
#define ZOO_PP_D_DECLARE(type, name) ZOO_PP_QUOTE type name
#define ZOO_PP_D_DECLARE_MEMBER(type, name) ZOO_PP_D_DECLARE(type, name);
// Macros to declare a function
// Macro to pass to BOOST_SEQ_FOR_EACH_I with the sequence of arguments
#define ZOO_PP_D_SEQI_DECLARE_PARAMETER(R, _, ndx, argument) \
BOOST_PP_COMMA_IF(ndx) ZOO_PP_D_DECLARE argument
#define ZOO_PP_D_DECLARE_PLAIN_FUNCTION(returnType, name, arguments) \
ZOO_PP_QUOTE returnType \
name \
( \
BOOST_PP_SEQ_FOR_EACH_I( \
ZOO_PP_D_SEQI_DECLARE_PARAMETER, ~, arguments \
) \
);
// Macros to declare the normal memory layout type
#define ZOO_PP_D_SEQ_DECLARE_MEMBER(_, __, m) ZOO_PP_D_DECLARE_MEMBER m
#define ZOO_PP_D_SEQ_DECLARE_FUNCTION(_, __, f) \
ZOO_PP_D_DECLARE_PLAIN_FUNCTION f
#define ZOO_PP_D_DECLARE_AGGREGATE(name, members, functions) \
struct name { \
BOOST_PP_SEQ_FOR_EACH( \
ZOO_PP_D_SEQ_DECLARE_MEMBER, \
~, \
members \
) \
BOOST_PP_SEQ_FOR_EACH( \
ZOO_PP_D_SEQ_DECLARE_FUNCTION, \
~, \
functions \
) \
};
// Macros to declare the handle class
#define ZOO_PP_D_HANDLE_ACCESSOR(global, type, name) \
ZOO_PP_QUOTE type &name() { return global.name[this->index_]; }
#define ZOO_PP_D_SEQ_HANDLE_ACCESSOR(_, global, member) \
ZOO_PP_D_HANDLE_ACCESSOR( \
global, \
ZOO_PP_D_TYPE_FROM_MEMBER member, \
ZOO_PP_D_NAME_FROM_MEMBER member \
)
#define ZOO_PP_D_HANDLE(name, members, functions) \
struct BOOST_PP_CAT(name, _handle) { \
unsigned index_; \
BOOST_PP_SEQ_FOR_EACH( \
ZOO_PP_D_SEQ_HANDLE_ACCESSOR, \
BOOST_PP_CAT(g_, name), \
members \
) \
BOOST_PP_SEQ_FOR_EACH( \
ZOO_PP_D_SEQ_DECLARE_FUNCTION, \
~, \
functions \
) \
};
#define ZOO_PP_D_COLUMN_IMPL(functor, type, name) \
functor<ZOO_PP_QUOTE type> name;
#define ZOO_PP_D_SEQ_COLUMN(_, functor, member) \
ZOO_PP_D_COLUMN_IMPL( \
functor, \
ZOO_PP_D_TYPE_FROM_MEMBER member, \
ZOO_PP_D_NAME_FROM_MEMBER member \
)
#define ZOO_PP_D_COLUMNAR_STATE(storageTypeFunctor, name, members, functions) \
struct { \
BOOST_PP_SEQ_FOR_EACH(ZOO_PP_D_SEQ_COLUMN, storageTypeFunctor, members) \
} BOOST_PP_CAT(g_, name);
#ifndef SP
#include <map>
#include <vector>
#include <optional>
#endif
struct Position {};
struct Orientation {};
#define SPRITE_SPECIFICATION \
Sprite, \
(((Position), p))(((Orientation), o))(((void *), data)), \
(( \
(double), distance, (((Position), point)) \
)) \
(( \
(void), modulus, \
))
ZOO_PP_INVOKE(ZOO_PP_D_COLUMNAR_STATE, std::vector, SPRITE_SPECIFICATION)
ZOO_PP_INVOKE(ZOO_PP_D_DECLARE_AGGREGATE, SPRITE_SPECIFICATION)
ZOO_PP_INVOKE(ZOO_PP_D_HANDLE, SPRITE_SPECIFICATION)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment