mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
The interface is now uniformly constexpr, including to_string and the _names iterable. Without the weak symbol, the remaining code is also entirely standard C++. The compile-time string trimming code in this commit has a negative impact on performance. The performance test is now twice as slow as including <iostream>, whereas before it was faster. That test declares an excessive number of enums, though, so perhaps in typical usage, and with some future optimizations, the impact will not be so significant. There may be other ways to solve this, such as providing a version of the macro that does not trim strings at compile time, but only checks if they need trimming. If some string does need trimming, that macro would fail a static_assert and ask the user to use the slow macro.
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, -DBETTER_ENUM_PP_MAP_FILE='<MACRO_FILE>'
|
|
# - for VC++, /DBETTER_ENUM_PP_MAP_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)
|