Skip to content

Instantly share code, notes, and snippets.

Created December 18, 2012 08:57
Show Gist options
  • Select an option

  • Save anonymous/4326310 to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/4326310 to your computer and use it in GitHub Desktop.
A modification to http://christopherschwaab.wordpress.com/2012/09/01/generating-switch-statements-in-c/ Added the possibility to define a default option for the switch statement.
#include <stdio.h>
#include <switch.hpp>
// Default option shall be one higher than the last
enum { ADD = 0, SUB = 1, MUL = 2, DIV = 3, MOD = 4, DEFAULT = 5 };
template <int Operation>
struct interpreter {
static inline int run(const int x, const int y);
};
// Our default operation: XOR
template <>
struct interpreter<DEFAULT> {
static const char *name() { return "XOR"; }
static inline int run(const int x, const int y) {
return x^y;
}
};
template <> struct interpreter<ADD> {
static const char *name() { return "ADD"; }
static inline int run(const int x, const int y)
{ return x + y; }
};
template <> struct interpreter<SUB> {
static const char *name() { return "SUB"; }
static inline int run(const int x, const int y)
{ return x - y; }
};
template <> struct interpreter<MUL> {
static const char *name() { return "MUL"; }
static inline int run(const int x, const int y)
{ return x * y; }
};
template <> struct interpreter<DIV> {
static const char *name() { return "DIV"; }
static inline int run(const int x, const int y)
{ return x / y; }
};
template <> struct interpreter<MOD> {
static const char *name() { return "MOD"; }
static inline int run(const int x, const int y)
{ return x % y; }
};
template <int Operation>
struct operation_table {
static always_inline int value(const bool printResult,
const int x, const int y) {
const int r = interpreter<Operation>::run(x, y);
if (printResult) printf("operation_table<%s>::run(%i, %i) = %i\n",
interpreter<Operation>::name(), x, y, r);
return r;
}
};
int main() {
bool printResult = true;
int op,x,y;
printf("op,x,y: ");
scanf("%i,%i,%i", &op, &x, &y);
metalevel::switch_table<0,4, operation_table>::run<int>(op,printResult,x,y);
// no default:
metalevel::switch_table<0,4, operation_table, false>::run<int>(op,printResult,x,y);
return 0;
}
#ifndef metalevel_switch_hpp
#define metalevel_switch_hpp
#include <boost/mpl/at.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/size.hpp>
#include <boost/preprocessor/iterate.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#ifdef __GNUC__
# define always_inline __attribute__((always_inline))
#elif defined(_MSC_VER)
# define always_inline __forceinline
#else
# define always_inline inline
#endif
#ifndef METALEVEL_MAX_CHOICE_ARGS
# define METALEVEL_MAX_CHOICE_ARGS 20
#endif
#ifndef METALEVEL_MAX_SWITCH_SIZE
# define METALEVEL_MAX_SWITCH_SIZE 20
#endif
namespace metalevel {
namespace aux {
template <int NumberOfCases, typename Xs>
struct switch_impl;
# define BOOST_PP_ITERATION_LIMITS (0, METALEVEL_MAX_SWITCH_SIZE)
# define BOOST_PP_FILENAME_1 <switch_impl.hpp>
# include BOOST_PP_ITERATE()
template <int Counter, int N, template <int> class Table>
struct tabulate
: boost::mpl::push_front<
tabulate<Counter+1, N-1, Table>,
boost::mpl::pair<boost::mpl::int_<Counter>, Table<Counter> >
>::type {};
template <int Counter, template <int> class Table>
struct tabulate<Counter, 0, Table>
: boost::mpl::list<
boost::mpl::pair<boost::mpl::int_<Counter>, Table<Counter> >
> {};
} // namespace aux
template <typename Xs>
struct switch_
: aux::switch_impl<boost::mpl::size<Xs>::type::value-1, Xs> {};
template <int Counter, int N, template <int> class Table, bool addDefault = true>
struct switch_table
: switch_<aux::tabulate<Counter,N+addDefault,Table> > {};
} // namespace metalevel
#endif
#ifdef BOOST_PP_IS_ITERATING
#define NUMBER_OF_CASES BOOST_PP_FRAME_ITERATION(1)
template <typename Xs>
struct switch_impl<NUMBER_OF_CASES, Xs> {
# define TYPEDEF_X_SUB_I(_, i, __) \
typedef typename boost::mpl::at_c<Xs, i>::type x_##i;
BOOST_PP_REPEAT(NUMBER_OF_CASES, TYPEDEF_X_SUB_I, ~)
typedef typename boost::mpl::at_c<Xs, NUMBER_OF_CASES>::type x_default;
# define METALEVEL_CASE_TABLE_ENTRY(_, i, ts) \
case boost::mpl::first<x_##i>::type::value: \
return boost::mpl::second<x_##i>::type::value ts ;
# define METALEVEL_DEFAULT_TABLE_ENTRY(ts) \
default: \
return boost::mpl::second<x_default>::type::value ts ;
# define DEFINE_CHOICE_RUN(_, argc, __) \
template <typename R BOOST_PP_COMMA_IF(argc) \
BOOST_PP_ENUM_PARAMS(argc, typename T)> \
static always_inline R \
run(int n BOOST_PP_COMMA_IF(argc) \
BOOST_PP_ENUM_BINARY_PARAMS(argc, T, t)) { \
switch(n) { \
BOOST_PP_REPEAT(NUMBER_OF_CASES, \
METALEVEL_CASE_TABLE_ENTRY, \
(BOOST_PP_ENUM_PARAMS(argc, t))) \
METALEVEL_DEFAULT_TABLE_ENTRY((BOOST_PP_ENUM_PARAMS(argc, t))) \
} \
}
BOOST_PP_REPEAT(METALEVEL_MAX_CHOICE_ARGS,
DEFINE_CHOICE_RUN, ~)
# undef DEFINE_CHOICE_RUN
# undef METALEVEL_CASE_TABLE_ENTRY
# undef METALEVEL_TABLE_ENTRY
};
#undef NUMBER_OF_CASES
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment