123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #!/usr/bin/env python
- """
- Generates some handy macros for preprocessor metaprogramming.
- """
- from __future__ import print_function
- import sys
- import textwrap
- if sys.version_info >= (3, 0, 0):
- xrange = range
- def generate(limit):
- print('#pragma once')
- print(textwrap.dedent('''
- /// @file va_args.h
- ///
- /// Some handy macros for preprocessor metaprogramming.
- '''.rstrip()))
- print('')
- command = ' '.join(sys.argv)
- print('// NOTE: this file has been generated with "{}", do not edit -- use the generator instead'.format(command))
- print('')
- print('// DO_NOT_STYLE')
- print('')
- print('#include <util/system/defaults.h>')
- print('')
- pass_va_args()
- count(limit)
- get_elem(limit)
- map_args(limit)
- map_args_n(limit)
- map_args_with_last(limit)
- map_args_with_last_n(limit)
- all_but_last(limit)
- last(limit)
- impl_dispatcher()
- def pass_va_args():
- print(textwrap.dedent('''
- /**
- * Triggers another level of macro expansion, use whenever passing __VA_ARGS__ to another macro.
- *
- * Used merely for working around an MSVC++ bug.
- * See http://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
- */
- '''.rstrip()))
- print('#define Y_PASS_VA_ARGS(x) x')
- def count(limit):
- print(textwrap.dedent('''
- /**
- * Count number of arguments in `__VA_ARGS__`.
- * Doesn't work with empty arguments list.
- */
- '''.rstrip()))
- numbers = ', '.join(map(str, xrange(limit, -1, -1)))
- u_numbers = ', '.join(map('_{}'.format, xrange(limit, 0, -1)))
- print('#define Y_COUNT_ARGS(...) Y_PASS_VA_ARGS('
- '__Y_COUNT_ARGS(__VA_ARGS__, {}))'.format(numbers))
- print('#define __Y_COUNT_ARGS({}, N, ...) N'.format(u_numbers))
- def get_elem(limit):
- print(textwrap.dedent('''
- /**
- * Get the i-th element from `__VA_ARGS__`.
- */
- '''.rstrip()))
- print('#define Y_GET_ARG(N, ...) Y_PASS_VA_ARGS(Y_PASS_VA_ARGS(Y_CAT(__Y_GET_ARG_, '
- 'N))(__VA_ARGS__))')
- for i in xrange(0, limit + 1):
- args = ', '.join(map('_{}'.format, xrange(i + 1)))
- print('#define __Y_GET_ARG_{}({}, ...) _{}'.format(i, args, i))
- def map_args(limit):
- print(textwrap.dedent('''
- /**
- * Expands a macro for each of the variable arguments.
- * Doesn't work with empty arguments list.
- */
- '''.rstrip()))
- print('#define Y_MAP_ARGS(ACTION, ...) Y_PASS_VA_ARGS(Y_PASS_VA_ARGS(Y_CAT('
- '__Y_MAP_ARGS_, Y_COUNT_ARGS(__VA_ARGS__)))(ACTION, __VA_ARGS__))')
- print('#define __Y_MAP_ARGS_0(...)')
- print('#define __Y_MAP_ARGS_1(ACTION, x, ...) ACTION(x)')
- for i in xrange(2, limit + 1):
- print('#define __Y_MAP_ARGS_{}(ACTION, x, ...) ACTION(x) Y_PASS_VA_ARGS(__Y_MAP_ARGS_{}('
- 'ACTION, __VA_ARGS__))'.format(i, i - 1))
- def map_args_n(limit):
- print(textwrap.dedent('''
- /**
- * Expands a macro for each of the variable arguments with it's sequence number and value.
- * Corresponding sequence numbers will expand in descending order.
- * Doesn't work with empty arguments list.
- */
- '''.rstrip()))
- print('#define Y_MAP_ARGS_N(ACTION, ...) Y_PASS_VA_ARGS(Y_PASS_VA_ARGS(Y_CAT('
- '__Y_MAP_ARGS_N_, Y_COUNT_ARGS(__VA_ARGS__)))(ACTION, __VA_ARGS__))')
- print('#define __Y_MAP_ARGS_N_0(...)')
- print('#define __Y_MAP_ARGS_N_1(ACTION, x, ...) ACTION(1, x)')
- for i in xrange(2, limit + 1):
- print('#define __Y_MAP_ARGS_N_{}(ACTION, x, ...) ACTION({}, x) Y_PASS_VA_ARGS(__Y_MAP_ARGS_N_{}('
- 'ACTION, __VA_ARGS__))'.format(i, i, i - 1))
- def map_args_with_last(limit):
- print(textwrap.dedent('''
- /**
- * Expands a macro for each of the variable arguments.
- * Doesn't work with empty arguments list.
- */
- '''.rstrip()))
- print('#define Y_MAP_ARGS_WITH_LAST(ACTION, LAST_ACTION, ...) Y_PASS_VA_ARGS(Y_PASS_VA_ARGS('
- 'Y_CAT(__Y_MAP_ARGS_WITH_LAST_, Y_COUNT_ARGS(__VA_ARGS__)))(ACTION, LAST_ACTION, '
- '__VA_ARGS__))')
- print('#define __Y_MAP_ARGS_WITH_LAST_0(...)')
- print('#define __Y_MAP_ARGS_WITH_LAST_1(ACTION, LAST_ACTION, x, ...) LAST_ACTION(x)')
- for i in xrange(2, limit + 1):
- print('#define __Y_MAP_ARGS_WITH_LAST_{}(ACTION, LAST_ACTION, x, ...) ACTION(x) Y_PASS_VA_ARGS('
- '__Y_MAP_ARGS_WITH_LAST_{}(ACTION, LAST_ACTION, __VA_ARGS__))'.format(i, i - 1))
- def map_args_with_last_n(limit):
- print(textwrap.dedent('''
- /**
- * Expands a macro for each of the variable arguments with it's sequence number and value.
- * Corresponding sequence numbers will expand in descending order.
- * Doesn't work with empty arguments list.
- */
- '''.rstrip()))
- print('#define Y_MAP_ARGS_WITH_LAST_N(ACTION, LAST_ACTION, ...) Y_PASS_VA_ARGS(Y_PASS_VA_ARGS('
- 'Y_CAT(__Y_MAP_ARGS_WITH_LAST_N_, Y_COUNT_ARGS(__VA_ARGS__)))(ACTION, LAST_ACTION, '
- '__VA_ARGS__))')
- print('#define __Y_MAP_ARGS_WITH_LAST_N_0(...)')
- print('#define __Y_MAP_ARGS_WITH_LAST_N_1(ACTION, LAST_ACTION, x, ...) LAST_ACTION(1, x)')
- for i in xrange(2, limit + 1):
- print('#define __Y_MAP_ARGS_WITH_LAST_N_{}(ACTION, LAST_ACTION, x, ...) ACTION({}, x) Y_PASS_VA_ARGS('
- '__Y_MAP_ARGS_WITH_LAST_N_{}(ACTION, LAST_ACTION, __VA_ARGS__))'.format(i, i, i - 1))
- def all_but_last(limit):
- print(textwrap.dedent('''
- /**
- * Get all elements but the last one from `__VA_ARGS__`.
- * Doesn't work with empty arguments list.
- */
- '''.rstrip()))
- print('#define Y_ALL_BUT_LAST(...) Y_PASS_VA_ARGS(Y_PASS_VA_ARGS(Y_CAT(__Y_ALL_BUT_LAST_, '
- 'Y_COUNT_ARGS(__VA_ARGS__)))(__VA_ARGS__))')
- print('#define __Y_ALL_BUT_LAST_0(...)')
- print('#define __Y_ALL_BUT_LAST_1(...)')
- for i in xrange(2, limit + 1):
- args = ', '.join(map('_{}'.format, xrange(i - 1)))
- print('#define __Y_ALL_BUT_LAST_{}({}, ...) {}'.format(i, args, args))
- def last(limit):
- print(textwrap.dedent('''
- /**
- * Get the last element from `__VA_ARGS__`.
- * Doesn't work with empty arguments list.
- */
- '''.rstrip()))
- print('#define Y_LAST(...) Y_PASS_VA_ARGS('
- 'Y_GET_ARG(Y_COUNT_ARGS(__VA_ARGS__), , __VA_ARGS__, {}))'.format(',' * limit))
- def impl_dispatcher():
- print(textwrap.dedent('''
- /**
- * Macros for implementing overload by number of arguments.
- *
- * Example usage:
- *
- * @code{cpp}
- * #define I1(arg1) Cout << Y_STRINGIZE(arg1) << Endl;
- * #define I2(arg1, arg2) Cout << Y_STRINGIZE(arg1) << ';' << Y_STRINGIZE(arg2) << Endl;
- *
- * #define Y_PRINT(...) Y_PASS_VA_ARGS(Y_MACRO_IMPL_DISPATCHER_2(__VA_ARGS__, I2, I1)(__VA_ARGS__))
- * @endcode
- */
- '''.rstrip()))
- print('/// @{')
- for i in xrange(2, 11):
- args = ', '.join(map('_{}'.format, xrange(i)))
- print('#define Y_MACRO_IMPL_DISPATCHER_{}({}, IMPL, ...) IMPL'.format(i, args))
- print('/// }@')
- def main():
- if len(sys.argv) > 2:
- sys.stderr.write('Usage: {} [limit=50]\n'.format(sys.argv[0]))
- sys.exit(1)
- limit = 50
- if len(sys.argv) == 2:
- limit = int(sys.argv[1])
- generate(limit)
- if __name__ == '__main__':
- main()
|