Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make_macros for python3 #117

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions script/make_macros_py3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#! /usr/bin/env python

# This file is based on script/make_macros.py and updated for Python3.

# 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.

# You only need this script if you are developing enum.h, or run into a limit.
#
# This script generates the macros BETTER_ENUMS_PP_MAP and BETTER_ENUMS_ITERATE,
# used internally by enum.h. These are already inlined into enum.h.
#
# BETTER_ENUMS_PP_MAP has a limit, which determines the maximum number of
# constants an enum can have. By default, this limit is 64 constants.
#
# BETTER_ENUMS_ITERATE also has a limit. This one determines the maximum length
# of the name of a constant that is followed by an initializer (" = 2") when
# compiling an enum with constexpr _to_string function (i.e. usually, this limit
# does not apply). By default, the limit is 23 characters (24 with the
# obligatory null terminator).
#
# 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 make_macros.py 512 128 > MACRO_FILE
# 2. Build your code with an additional compiler flag:
# - for gcc and clang, -DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
# - for VC++, /DBETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
# or use any other method of getting these macros defined.
# 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._columns_left - 1) + '\\', file=self._stream)
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 fprint(stream, *args):
fline = " ".join(map(str, args))
stream.write(fline + "\n")

def generate(stream, constants, length, script):
fprint(stream, '// This file was automatically generated by ' + script)

fprint(stream, '')
fprint(stream, '#pragma once')
fprint(stream, '')
fprint(stream, '#ifndef BETTER_ENUMS_MACRO_FILE_H')
fprint(stream, '#define BETTER_ENUMS_MACRO_FILE_H')

fprint(stream, '')
fprint(stream, '#define BETTER_ENUMS_PP_MAP(macro, data, ...) \\')
fprint(stream, ' BETTER_ENUMS_ID( \\')
fprint(stream, ' BETTER_ENUMS_APPLY( \\')
fprint(stream, ' BETTER_ENUMS_PP_MAP_VAR_COUNT, \\')
fprint(stream, ' BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \\')
fprint(stream, ' (macro, data, __VA_ARGS__))')

fprint(stream, '')
fprint(stream, '#define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) ' + \
'BETTER_ENUMS_M ## count')

fprint(stream, '')
fprint(stream, '#define BETTER_ENUMS_APPLY(macro, ...) ' + \
'BETTER_ENUMS_ID(macro(__VA_ARGS__))')

fprint(stream, '')
fprint(stream, '#define BETTER_ENUMS_ID(x) x')

fprint(stream, '')
fprint(stream, '#define BETTER_ENUMS_M1(m, d, x) m(d,0,x)')
for index in range(2, constants + 1):
fprint(stream, '#define BETTER_ENUMS_M' + str(index) + \
'(m,d,x,...) m(d,' + str(index - 1) + ',x) \\')
fprint(stream, ' BETTER_ENUMS_ID(BETTER_ENUMS_M' + \
str(index - 1) + '(m,d,__VA_ARGS__))')

fprint(stream, '')
pp_count_impl_prefix = '#define BETTER_ENUMS_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)
fprint(stream, '')

fprint(stream, '')
fprint(stream, '#define BETTER_ENUMS_PP_COUNT(...) \\')
pp_count_prefix = \
' BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__,'
stream.write(pp_count_prefix)
pp_count = MultiLine(stream = stream, indent = 8,
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)
fprint(stream, '')

fprint(stream, '')
iterate_prefix = '#define BETTER_ENUMS_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)
fprint(stream, '')

fprint(stream, '')
fprint(stream, '#endif // #ifndef BETTER_ENUMS_MACRO_FILE_H')

def print_err(*args):
err_msg= " ".join(str(arg) for arg in args)
sys.stderr.write(err_msg + "\n")

if __name__ == '__main__':
if len(sys.argv) != 3:
print_err('Usage: ' + sys.argv[0] + ' CONSTANTS LENGTH > FILE')
print_err("")
print_err("Prints map macro definition to FILE.")
print_err("CONSTANTS is the number of constants to support.")
print_err("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)