mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-07 17:26:45 +08:00
Initial version.
This commit is contained in:
parent
f54960590a
commit
d0be0beff1
99
Enum.h
Normal file
99
Enum.h
Normal 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
1255
EnumInternal.h
Normal file
File diff suppressed because it is too large
Load Diff
97
pp_map_gen.py
Executable file
97
pp_map_gen.py
Executable 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)
|
||||
Loading…
x
Reference in New Issue
Block a user