Initial version.

This commit is contained in:
Anton Bachin 2015-04-22 20:21:07 -04:00
parent f54960590a
commit d0be0beff1
3 changed files with 1451 additions and 0 deletions

99
Enum.h Normal file
View File

@ -0,0 +1,99 @@
/// @file Enum.h
/// Enum type generator.
///
/// @todo Provide type name as a string.
#pragma once
#include <util/EnumInternal.h>
// TODO (DOC) Link to the main enum documentation from the macro documentation,
// or paste it here?
// TODO (DOC) Improve the readability and formatting of enum documentation.
// TODO (DOC) Refer to detailed documentation of internals in EnumInternal.h.
// TODO Document why it's okay to convert the value span to an unsigned integer.
// TODO `size()` is only for compatibility with `BETTER_ENUM`.
// TODO toUnderlying can probably be constexpr.
// TODO If type name is added to the class, it would be useful in pyatl.
#define ENUM(EnumType, UnderlyingType, ...) \
_ENUM_ARRAYS(EnumType, UnderlyingType, __VA_ARGS__); \
\
class EnumType : public _enum::_Internal<EnumType> { \
protected: \
using _Super = _enum::_Internal<EnumType>; \
\
public: \
using Enum = _Value; \
\
static constexpr _Value bad = (_Value)_values[_badIndex]; \
static constexpr _Value def = (_Value)_values[_defIndex]; \
static constexpr _Value min = (_Value)_values[_minIndex]; \
static constexpr _Value max = (_Value)_values[_maxIndex]; \
\
static constexpr size_t span = max - min + 1; \
\
static constexpr size_t size() { return _size; } \
\
static constexpr _Value MaxValid = max; \
static constexpr _Value MinValid = min; \
\
static ValueIterable values() { return _Super::values(); } \
static ValueIterable allValues() { return _Super::allValues(); } \
static NameIterable names() { return _Super::names(); } \
static NameIterable allNames() { return _Super::allNames(); } \
\
const char* desc() const { return desc(*this); } \
const char* descE() const { return descE(*this); } \
\
static const char* desc(EnumType value) { return _Super::desc(value); }\
static const char* descE(EnumType value) \
{ return _Super::descE(value); } \
\
static EnumType find(const char *name) { return _Super::find(name); } \
static EnumType findE(const char *name) { return _Super::findE(name); }\
\
static EnumType caseFind(const char *name) \
{ return _Super::caseFind(name); } \
static EnumType caseFindE(const char *name) \
{ return _Super::caseFindE(name); } \
\
bool valid() const { return valid(this->toUnderlying()); }; \
\
template <typename IntegralType> \
static bool valid(IntegralType value) { return _Super::valid(value); } \
static bool valid(const char *name) { return _Super::valid(name); } \
static bool caseValid(const char *name) \
{ return _Super::caseValid(name); } \
\
EnumType() : _value(def) { } \
EnumType(_Value value) : _value(value) { } \
template <typename IntegralType> \
explicit EnumType(IntegralType value, \
typename enable_if<is_integral<IntegralType>::value> \
::type *dummy = nullptr) : _value(value) { } \
\
template <typename IntegralType> \
EnumType& operator =(IntegralType value) \
{ *this = EnumType(value); return *this; } \
\
operator _Value () const { return (_Value)_value; } \
Underlying toUnderlying() const { return (Underlying)_value; } \
\
protected: \
Underlying _value; \
\
friend _Super; \
friend ValueIterable; \
}; \
\
static_assert(sizeof(EnumType) == sizeof(UnderlyingType), \
"internal error: enum type does not have same size as its " \
"underlying type"); \
static_assert(alignof(EnumType) == alignof(UnderlyingType), \
"internal error: enum type does not have same alignment " \
"requirement as its underlying type");

1255
EnumInternal.h Normal file

File diff suppressed because it is too large Load Diff

97
pp_map_gen.py Executable file
View File

@ -0,0 +1,97 @@
#! /usr/bin/env python
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, filename, count, script):
print >> stream, '/// @file ' + filename
print >> stream, '/// @brief Preprocessor higher-order map macro.'
print >> stream, '///'
print >> stream, '/// This file was automatically generated by ' + script
print >> stream, ''
print >> stream, '#pragma once'
print >> stream, ''
print >> stream, '#define _ENUM_PP_MAP(macro, data, ...) \\'
print >> stream, ' _ENUM_PP_APPLY(_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_PP_MAP_ ## count'
print >> stream, ''
print >> stream, '#define _ENUM_PP_APPLY(macro, ...) macro(__VA_ARGS__)'
print >> stream, ''
print >> stream, '#define _ENUM_PP_MAP_1(macro, data, x) ' + \
'_ENUM_PP_APPLY(macro, data, x)'
for index in range(2, count + 1):
print >> stream, '#define _ENUM_PP_MAP_' + str(index) + \
'(macro, data, x, ...) ' + \
'_ENUM_PP_APPLY(macro, data, x), \\'
print >> stream, ' ' + \
'_ENUM_PP_MAP_' + str(index - 1) + \
'(macro, data, __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, count + 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, count - 1):
pp_count.write(' ' + str(count - index) + ',')
pp_count.write(' 1)', last = True)
print >> stream, ''
if __name__ == '__main__':
if len(sys.argv) != 3:
print >> sys.stderr, 'Usage: ' + sys.argv[0] + ' FILE COUNT'
print >> sys.stderr, ''
print >> sys.stderr, 'Prints macro header file to standard output.'
print >> sys.stderr, 'The FILE parameter is used in the comment.'
sys.exit(2)
generate(sys.stdout, sys.argv[1], int(sys.argv[2]),
os.path.basename(sys.argv[0]))
sys.exit(0)