mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
A Better Enum is normally implicitly convertible to its internal enum type,
which makes it then implicitly convertible to an integer as well. The former
conversion is necessary for Better Enums to be usable in switch statements.
This change makes it possible to define BETTER_ENUMS_SAFER_SWITCH, which makes
Better Enums convert to an enum class, preventing the implicit conversion to
integers. The drawback is that switch cases have to be written as
case Enum::_Case::A:
instead of
case Enum::A:
141 lines
5.6 KiB
Python
Executable File
141 lines
5.6 KiB
Python
Executable File
#! /usr/bin/env python
|
|
|
|
# This file is part of Better Enums, released under the BSD 2-clause license.
|
|
# See LICENSE for details, or visit http://github.com/aantron/better-enums.
|
|
|
|
# This script generates the macros _ENUM_PP_MAP and _ENUM_ITERATE, used
|
|
# internally by enum.h. These are already inlined into enum.h. You only need
|
|
# this script if you are developing enum.h, or run into a limit.
|
|
#
|
|
# _ENUM_PP_MAP has a limit, which determines the maximum number of constants an
|
|
# enum can have. By default, this limit is 256 constants.
|
|
#
|
|
# _ENUM_ITERATE also has a limit. This one determines the maximum length of the
|
|
# name of a constant that is followed by an explicit setting (" = 2"). By
|
|
# default, this is 23 (24 with the obligatory null terminator). Constants
|
|
# without explicit setting can have any length.
|
|
#
|
|
# If either of these limits is inadequate, you can still compile your code
|
|
# without changing enum.h. You need to generate an external macro file with
|
|
# definitions of these macros with relaxed limits, and tell enum.h to use the
|
|
# external macro file. Here is how this is done, supposing you want support for
|
|
# 512 constants of length up to 127 (128 with null terminator):
|
|
#
|
|
# 0. MACRO_FILE is the name of the external macro file. Make sure you put it
|
|
# somewhere in your include path.
|
|
# 1. Run python pp_map_gen.py 512 128 > MACRO_FILE
|
|
# 2. Build your code with an additional compiler flag:
|
|
# - for gcc and clang, -BETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
|
|
# - for VC++, /BETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
|
|
# or use any other method of getting these macros declared.
|
|
# 3. Compile your code. Your macro file should be included, and enum.h should
|
|
# happily work with whatever limits you chose.
|
|
|
|
import os
|
|
import sys
|
|
|
|
class MultiLine(object):
|
|
def __init__(self, stream, indent = 4, columns = 80, initial_column = 0):
|
|
self._columns_left = columns - initial_column
|
|
self._indent = indent
|
|
self._columns = columns
|
|
self._stream = stream
|
|
|
|
def write(self, token, last = False):
|
|
break_line = False
|
|
if last:
|
|
if len(token) > self._columns_left:
|
|
break_line = True
|
|
else:
|
|
if len(token) > self._columns_left - 1:
|
|
break_line = True
|
|
|
|
if break_line:
|
|
print >> self._stream, ' ' * (self._columns_left - 1) + '\\'
|
|
self._stream.write(' ' * self._indent)
|
|
self._columns_left = self._columns - self._indent
|
|
token = token.lstrip()
|
|
|
|
self._stream.write(token)
|
|
self._columns_left -= len(token)
|
|
|
|
def generate(stream, constants, length, script):
|
|
print >> stream, '// This file was automatically generated by ' + script
|
|
|
|
print >> stream, ''
|
|
print >> stream, '#pragma once'
|
|
print >> stream, ''
|
|
print >> stream, '#ifndef _BETTER_ENUM_ENUM_PREPROCESSOR_MAP_H_'
|
|
print >> stream, '#define _BETTER_ENUM_ENUM_PREPROCESSOR_MAP_H_'
|
|
|
|
print >> stream, ''
|
|
print >> stream, '#define _ENUM_PP_MAP(macro, data, ...) \\'
|
|
print >> stream, ' _ENUM_A(_ENUM_PP_MAP_VAR_COUNT, ' + \
|
|
'_ENUM_PP_COUNT(__VA_ARGS__)) \\'
|
|
print >> stream, ' (macro, data, __VA_ARGS__)'
|
|
|
|
print >> stream, ''
|
|
print >> stream, '#define _ENUM_PP_MAP_VAR_COUNT(count) ' + \
|
|
'_ENUM_M ## count'
|
|
|
|
print >> stream, ''
|
|
print >> stream, '#define _ENUM_A(macro, ...) macro(__VA_ARGS__)'
|
|
|
|
print >> stream, ''
|
|
print >> stream, '#define _ENUM_M1(m, d, x) _ENUM_A(m, d, 0, x)'
|
|
for index in range(2, constants + 1):
|
|
print >> stream, '#define _ENUM_M' + str(index) + \
|
|
'(m,d,x,...) _ENUM_A(m,d,' + str(index - 1) + \
|
|
',x) _ENUM_M' + str(index - 1) + \
|
|
'(m,d,__VA_ARGS__)'
|
|
|
|
print >> stream, ''
|
|
pp_count_impl_prefix = '#define _ENUM_PP_COUNT_IMPL(_1,'
|
|
stream.write(pp_count_impl_prefix)
|
|
pp_count_impl = MultiLine(stream = stream, indent = 4,
|
|
initial_column = len(pp_count_impl_prefix))
|
|
for index in range(2, constants + 1):
|
|
pp_count_impl.write(' _' + str(index) + ',')
|
|
pp_count_impl.write(' count,')
|
|
pp_count_impl.write(' ...)')
|
|
pp_count_impl.write(' count', last = True)
|
|
print >> stream, ''
|
|
|
|
print >> stream, ''
|
|
pp_count_prefix = \
|
|
'#define _ENUM_PP_COUNT(...) _ENUM_PP_COUNT_IMPL(__VA_ARGS__,'
|
|
stream.write(pp_count_prefix)
|
|
pp_count = MultiLine(stream = stream, indent = 4,
|
|
initial_column = len(pp_count_prefix))
|
|
for index in range(0, constants - 1):
|
|
pp_count.write(' ' + str(constants - index) + ',')
|
|
pp_count.write(' 1)', last = True)
|
|
print >> stream, ''
|
|
|
|
print >> stream, ''
|
|
iterate_prefix = '#define _ENUM_ITERATE(X, f, l)'
|
|
stream.write(iterate_prefix)
|
|
iterate = MultiLine(stream = stream, indent = 4,
|
|
initial_column = len(iterate_prefix))
|
|
for index in range(0, length):
|
|
iterate.write(' X(f, l, %i)' % index)
|
|
print >> stream, ''
|
|
|
|
print >> stream, ''
|
|
print >> stream, '#endif // #ifndef _BETTER_ENUM_ENUM_PREPROCESSOR_MAP_H_'
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) != 3:
|
|
print >> sys.stderr, \
|
|
'Usage: ' + sys.argv[0] + ' CONSTANTS LENGTH > FILE'
|
|
print >> sys.stderr, ''
|
|
print >> sys.stderr, 'Prints map macro definition to FILE.'
|
|
print >> sys.stderr, 'CONSTANTS is the number of constants to support.'
|
|
print >> sys.stderr, 'LENGTH is the maximum length of a constant name.'
|
|
sys.exit(1)
|
|
|
|
generate(sys.stdout, int(sys.argv[1]), int(sys.argv[2]),
|
|
os.path.basename(sys.argv[0]))
|
|
|
|
sys.exit(0)
|